package db import "database/sql" import "time" import "codit/internal/models" import "codit/internal/util" func (s *Store) CreatePrincipalAPIKey(principalID string, name string, tokenHash string, prefix string, expiresAt int64) (models.PrincipalAPIKey, error) { var key models.PrincipalAPIKey var err error var now time.Time var nowUnix int64 var id string id, err = util.NewID() if err != nil { return key, err } now = time.Now().UTC() nowUnix = now.Unix() key = models.PrincipalAPIKey{ ID: id, PrincipalID: principalID, Name: name, Prefix: prefix, CreatedAt: nowUnix, LastUsedAt: 0, ExpiresAt: expiresAt, Disabled: false, } _, err = s.Exec(`INSERT INTO principal_api_keys (public_id, principal_id, name, token_hash, token_prefix, created_at, last_used_at, expires_at, disabled) VALUES (?, (SELECT id FROM service_principals WHERE public_id = ?), ?, ?, ?, ?, ?, ?, ?)`, key.ID, key.PrincipalID, key.Name, tokenHash, key.Prefix, key.CreatedAt, key.LastUsedAt, key.ExpiresAt, key.Disabled) return key, err } func (s *Store) ListPrincipalAPIKeys(principalID string) ([]models.PrincipalAPIKey, error) { var rows *sql.Rows var err error var keys []models.PrincipalAPIKey var key models.PrincipalAPIKey rows, err = s.Query(`SELECT k.public_id, p.public_id, k.name, k.token_prefix, k.created_at, k.last_used_at, k.expires_at, k.disabled FROM principal_api_keys k JOIN service_principals p ON p.id = k.principal_id WHERE p.public_id = ? ORDER BY k.created_at DESC`, principalID) if err != nil { return nil, err } defer rows.Close() for rows.Next() { err = rows.Scan(&key.ID, &key.PrincipalID, &key.Name, &key.Prefix, &key.CreatedAt, &key.LastUsedAt, &key.ExpiresAt, &key.Disabled) if err != nil { return nil, err } keys = append(keys, key) } return keys, rows.Err() } func (s *Store) DeletePrincipalAPIKey(principalID string, id string) error { var err error _, err = s.Exec(`DELETE FROM principal_api_keys WHERE public_id = ? AND principal_id = (SELECT id FROM service_principals WHERE public_id = ?)`, id, principalID) return err } func (s *Store) SetPrincipalAPIKeyDisabled(principalID string, id string, disabled bool) error { var err error _, err = s.Exec(`UPDATE principal_api_keys SET disabled = ? WHERE public_id = ? AND principal_id = (SELECT id FROM service_principals WHERE public_id = ?)`, disabled, id, principalID) return err } func (s *Store) GetPrincipalByAPIKeyHash(tokenHash string) (models.ServicePrincipal, error) { var principal models.ServicePrincipal var tx *sql.Tx var owned bool var row *sql.Row var keyID int64 var now time.Time var nowUnix int64 var currentUnix int64 var err error tx, owned, err = s.begin() if err != nil { return principal, err } now = time.Now().UTC() currentUnix = now.Unix() row = tx.QueryRow(` SELECT p.public_id, p.name, p.description, p.is_admin, p.disabled, p.created_at, p.updated_at, k.id FROM principal_api_keys k JOIN service_principals p ON p.id = k.principal_id WHERE k.token_hash = ? AND p.disabled = 0 AND k.disabled = 0 AND (k.expires_at = 0 OR k.expires_at > ?) LIMIT 1 `, tokenHash, currentUnix) err = row.Scan(&principal.ID, &principal.Name, &principal.Description, &principal.IsAdmin, &principal.Disabled, &principal.CreatedAt, &principal.UpdatedAt, &keyID) if err != nil { rollbackIfOwned(tx, owned) return principal, err } now = time.Now().UTC() nowUnix = now.Unix() _, err = tx.Exec(`UPDATE principal_api_keys SET last_used_at = ? WHERE id = ?`, nowUnix, keyID) if err != nil { rollbackIfOwned(tx, owned) return principal, err } err = commitIfOwned(tx, owned) if err != nil { return principal, err } return principal, nil }