package main import ( "encoding/json" "net/http" "strings" "sync" "time" ) type keyCache struct { mu sync.RWMutex keys map[string]bool expires time.Time } var apiKeyCache = &keyCache{ keys: make(map[string]bool), } type APIKey struct { ID string `json:"id,omitempty"` Key string `json:"key"` Name string `json:"name"` Active bool `json:"active"` CreatedAt string `json:"created_at,omitempty"` } func isValidAPIKey(key string) bool { apiKeyCache.mu.RLock() if time.Now().Before(apiKeyCache.expires) { valid := apiKeyCache.keys[key] apiKeyCache.mu.RUnlock() return valid } apiKeyCache.mu.RUnlock() return checkKeyInSupabase(key) } func checkKeyInSupabase(key string) bool { data, status, err := supabaseServiceRequest("GET", "api_keys", "key=eq."+key+"&active=eq.true&select=key", nil) if err != nil || status != 200 { return false } var results []map[string]interface{} if err := json.Unmarshal(data, &results); err != nil { return false } found := len(results) > 0 if found { apiKeyCache.mu.Lock() apiKeyCache.keys[key] = true if apiKeyCache.expires.IsZero() { apiKeyCache.expires = time.Now().Add(60 * time.Second) } apiKeyCache.mu.Unlock() } return found } func refreshKeyCache() { data, status, err := supabaseServiceRequest("GET", "api_keys", "active=eq.true&select=key", nil) if err != nil || status != 200 { return } var results []map[string]string if err := json.Unmarshal(data, &results); err != nil { return } apiKeyCache.mu.Lock() apiKeyCache.keys = make(map[string]bool) for _, r := range results { apiKeyCache.keys[r["key"]] = true } apiKeyCache.expires = time.Now().Add(60 * time.Second) apiKeyCache.mu.Unlock() } func authHeader(r *http.Request) string { auth := r.Header.Get("Authorization") if strings.HasPrefix(auth, "Bearer ") { return strings.TrimPrefix(auth, "Bearer ") } return r.Header.Get("x-api-key") }