MCPcopy
hub / github.com/autobrr/qui / ClientAPIKeyMiddleware

Function ClientAPIKeyMiddleware

internal/proxy/middleware.go:103–165  ·  view source on GitHub ↗

ClientAPIKeyMiddleware validates client API keys and extracts instance information

(store *models.ClientAPIKeyStore)

Source from the content-addressed store, hash-verified

101
102// ClientAPIKeyMiddleware validates client API keys and extracts instance information
103func 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

Callers 1

RoutesMethod · 0.85

Calls 8

userAgentOrUnknownFunction · 0.85
getOrCreateDebouncerFunction · 0.85
ValidateKeyMethod · 0.80
QueuedMethod · 0.80
DoMethod · 0.80
ServeHTTPMethod · 0.80
ErrorMethod · 0.45
UpdateLastUsedMethod · 0.45

Tested by

no test coverage detected