package storage import ( "errors" "strings" "github.com/sandrodach/mindsift/internal/auth" "github.com/sandrodach/mindsift/internal/domain" ) // --- API KEYS & WEBHOOKS --- func (s *Store) CreateAPIKey(userID, name string) (*domain.APIKey, error) { if strings.TrimSpace(name) == "" { name = "Smarthome / Webhook Key" } rawKey, prefix, hash := auth.GenerateAPIKey() k := &domain.APIKey{ ID: domain.NewID("key"), UserID: userID, Name: strings.TrimSpace(name), KeyPrefix: prefix, KeyHash: hash, RawKey: rawKey, Scopes: "ingest,read", CreatedAt: domain.NowISO(), } _, err := s.db.Exec( `INSERT INTO api_keys (id, user_id, name, key_prefix, key_hash, scopes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`, k.ID, k.UserID, k.Name, k.KeyPrefix, k.KeyHash, k.Scopes, k.CreatedAt, ) if err != nil { return nil, err } return k, nil } func (s *Store) GetAPIKeys(userID string) ([]domain.APIKey, error) { rows, err := s.db.Query( `SELECT id, user_id, name, key_prefix, scopes, last_used_at, created_at FROM api_keys WHERE user_id = ? ORDER BY created_at DESC`, userID, ) if err != nil { return nil, err } defer rows.Close() keys := make([]domain.APIKey, 0) for rows.Next() { var k domain.APIKey if err := rows.Scan(&k.ID, &k.UserID, &k.Name, &k.KeyPrefix, &k.Scopes, &k.LastUsedAt, &k.CreatedAt); err == nil { keys = append(keys, k) } } return keys, nil } func (s *Store) DeleteAPIKey(userID, keyID string) error { _, err := s.db.Exec(`DELETE FROM api_keys WHERE id = ? AND user_id = ?`, keyID, userID) return err } func (s *Store) ValidateAPIKeyAndGetUser(rawKey string) (*domain.User, error) { hash := auth.HashAPIKey(strings.TrimSpace(rawKey)) var keyID, userID string err := s.db.QueryRow(`SELECT id, user_id FROM api_keys WHERE key_hash = ?`, hash).Scan(&keyID, &userID) if err != nil { return nil, errors.New("invalid API key") } _, _ = s.db.Exec(`UPDATE api_keys SET last_used_at = ? WHERE id = ?`, domain.NowISO(), keyID) return s.GetUserByID(userID) }