package store import ( "context" "database/sql" "errors" "fmt" "time" ) // CredentialKind identifies the role of a host_credentials row. type CredentialKind string const ( // CredKindRepo is the append-only credential used for every backup. CredKindRepo CredentialKind = "repo" // CredKindAdmin is the delete-capable credential used for prune. CredKindAdmin CredentialKind = "admin" ) // GetHostCredentials returns the AEAD-encrypted repo creds blob for // the host + kind, or ("", ErrNotFound) if no matching row exists. // The caller decrypts using host_id as AEAD additional data. func (s *Store) GetHostCredentials(ctx context.Context, hostID string, kind CredentialKind) (string, error) { row := s.db.QueryRowContext(ctx, `SELECT enc_repo_creds FROM host_credentials WHERE host_id = ? AND kind = ?`, hostID, string(kind)) var enc string if err := row.Scan(&enc); err != nil { if errors.Is(err, sql.ErrNoRows) { return "", ErrNotFound } return "", fmt.Errorf("store: get host credentials: %w", err) } return enc, nil } // SetHostCredentials replaces the host's encrypted repo creds blob for // the given kind. The caller has already encrypted using host_id as // additional data. func (s *Store) SetHostCredentials(ctx context.Context, hostID string, kind CredentialKind, encRepoCreds string) error { if encRepoCreds == "" { return fmt.Errorf("store: empty enc_repo_creds") } now := time.Now().UTC().Format(time.RFC3339Nano) _, err := s.db.ExecContext(ctx, `INSERT INTO host_credentials (host_id, kind, enc_repo_creds, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT(host_id, kind) DO UPDATE SET enc_repo_creds = excluded.enc_repo_creds, updated_at = excluded.updated_at`, hostID, string(kind), encRepoCreds, now) if err != nil { return fmt.Errorf("store: set host credentials: %w", err) } return nil } // DeleteHostCredentials removes the credential row for the given host // and kind. A no-op if the row does not exist. func (s *Store) DeleteHostCredentials(ctx context.Context, hostID string, kind CredentialKind) error { _, err := s.db.ExecContext(ctx, `DELETE FROM host_credentials WHERE host_id = ? AND kind = ?`, hostID, string(kind)) if err != nil { return fmt.Errorf("store: delete host credentials: %w", err) } return nil }