67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
package repo
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"github.com/dbiz/cdp/ingestion/ingest/internal/apperr"
|
|
"github.com/dbiz/cdp/ingestion/ingest/internal/model"
|
|
)
|
|
|
|
// WriteKeyRepo loads WriteKey records by their plaintext value.
|
|
// The plaintext is hashed before the lookup; the DB only stores hashes.
|
|
type WriteKeyRepo interface {
|
|
FindByPlaintext(ctx context.Context, plaintext string) (*model.WriteKey, error)
|
|
MarkUsed(ctx context.Context, id string) error
|
|
}
|
|
|
|
type writeKeyRepo struct {
|
|
db *pgxpool.Pool
|
|
}
|
|
|
|
func NewWriteKeyRepo(db *pgxpool.Pool) WriteKeyRepo {
|
|
return &writeKeyRepo{db: db}
|
|
}
|
|
|
|
func hashKey(plaintext string) string {
|
|
sum := sha256.Sum256([]byte(plaintext))
|
|
return hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func (r *writeKeyRepo) FindByPlaintext(ctx context.Context, plaintext string) (*model.WriteKey, error) {
|
|
const q = `
|
|
SELECT id::text, workspace_id::text, source_id::text,
|
|
key_prefix, COALESCE(label, ''),
|
|
revoked_at, last_used_at, created_at
|
|
FROM write_keys
|
|
WHERE key_hash = $1`
|
|
row := r.db.QueryRow(ctx, q, hashKey(plaintext))
|
|
|
|
var k model.WriteKey
|
|
err := row.Scan(&k.ID, &k.WorkspaceID, &k.SourceID,
|
|
&k.KeyPrefix, &k.Label,
|
|
&k.RevokedAt, &k.LastUsedAt, &k.CreatedAt)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, apperr.Unauthorized("invalid write key")
|
|
}
|
|
if err != nil {
|
|
return nil, apperr.Internal(fmt.Errorf("writekey lookup: %w", err))
|
|
}
|
|
return &k, nil
|
|
}
|
|
|
|
func (r *writeKeyRepo) MarkUsed(ctx context.Context, id string) error {
|
|
const q = `UPDATE write_keys SET last_used_at = now() WHERE id = $1`
|
|
_, err := r.db.Exec(ctx, q, id)
|
|
if err != nil {
|
|
return apperr.Internal(fmt.Errorf("writekey mark used: %w", err))
|
|
}
|
|
return nil
|
|
}
|