70 lines
2.3 KiB
Go
70 lines
2.3 KiB
Go
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
|
|
}
|