ClientAPIKeyMiddleware validates client API keys and extracts instance information
(store *models.ClientAPIKeyStore)
| 101 | |
| 102 | // ClientAPIKeyMiddleware validates client API keys and extracts instance information |
| 103 | func ClientAPIKeyMiddleware(store *models.ClientAPIKeyStore) func(http.Handler) http.Handler { |
| 104 | return func(next http.Handler) http.Handler { |
| 105 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 106 | log.Debug(). |
| 107 | Str("method", r.Method). |
| 108 | Msg("ClientAPIKeyMiddleware called") |
| 109 | |
| 110 | // Extract API key from URL path parameter |
| 111 | apiKey := chi.URLParam(r, "api-key") |
| 112 | log.Debug(). |
| 113 | Bool("hasKey", apiKey != ""). |
| 114 | Msg("Checking API key from URL parameter") |
| 115 | |
| 116 | if apiKey == "" { |
| 117 | log.Warn(). |
| 118 | Str("user_agent", userAgentOrUnknown(r)). |
| 119 | Msg("Missing API key in proxy request") |
| 120 | http.Error(w, "Missing API key", http.StatusUnauthorized) |
| 121 | return |
| 122 | } |
| 123 | |
| 124 | // Validate the API key |
| 125 | ctx := r.Context() |
| 126 | clientAPIKey, err := store.ValidateKey(ctx, apiKey) |
| 127 | if err != nil { |
| 128 | if err == models.ErrClientAPIKeyNotFound { |
| 129 | log.Warn(). |
| 130 | Str("user_agent", userAgentOrUnknown(r)). |
| 131 | Msg("Invalid client API key") |
| 132 | http.Error(w, "Invalid API key", http.StatusUnauthorized) |
| 133 | return |
| 134 | } |
| 135 | log.Error().Err(err).Msg("Failed to validate client API key") |
| 136 | http.Error(w, "Internal server error", http.StatusInternalServerError) |
| 137 | return |
| 138 | } |
| 139 | |
| 140 | // Update last used timestamp with debouncing per API key |
| 141 | debouncer := getOrCreateDebouncer(clientAPIKey.KeyHash) |
| 142 | |
| 143 | if !debouncer.Queued() { |
| 144 | debouncer.Do(func() { |
| 145 | if err := store.UpdateLastUsed(context.Background(), clientAPIKey.KeyHash); err != nil { |
| 146 | log.Error().Err(err).Int("keyId", clientAPIKey.ID).Msg("Failed to update API key last used timestamp") |
| 147 | } |
| 148 | }) |
| 149 | } |
| 150 | |
| 151 | log.Debug(). |
| 152 | Str("client", clientAPIKey.ClientName). |
| 153 | Int("instanceId", clientAPIKey.InstanceID). |
| 154 | Str("method", r.Method). |
| 155 | Msg("Client API key validated successfully") |
| 156 | |
| 157 | // Add client API key and instance ID to request context |
| 158 | ctx = context.WithValue(ctx, ClientAPIKeyContextKey, clientAPIKey) |
| 159 | ctx = context.WithValue(ctx, InstanceIDContextKey, clientAPIKey.InstanceID) |
| 160 |
no test coverage detected