Files
MindSift/internal/storage/apikeys.go
T
sandrodachandClaude Opus 5.5 74c394efaa
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m31s
refactor: split sqlite.go and server.go by domain (FLAW-20)
Pure moves, no behaviour change: the storage layer now has users,
apikeys, thoughts, tasklists, documents, folders, tags, lists, teams and
system files next to sqlite.go (store, schema, migrations); the API has
handlers_*.go per area plus realtime.go and alarms.go next to server.go
(server, router, middleware). Declarations were moved verbatim with an
AST-based tool; imports pruned with goimports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 08:14:33 +01:00

76 lines
2.0 KiB
Go

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)
}