Key-Scanner: Auth-Header fix, 401-mit-Usage-Handling, breitere Suche, Live-Refresh

- AnthropicKeyChecker: Bearer-Auth + CLI-Header statt x-api-key (identisch mit AnthropicService)
- 401 mit Usage-Headern → 'usage_limited' statt 'invalid' (Key gültig, Limit erreicht)
- Haiku-Phase entfernt, Streaming-Logik entfernt → ein einfacher Request reicht
- KeyScannerService: SearchLanguages 1→13, PathExtensions 24 neue Pfad-Filter
- ApiKeysEndpoint: usage_limited als 'ok' ans Frontend
- Frontend: Adopt-Button auch bei quota_exceeded, Live-Refresh alle 3s während Scan
- CSS: Overflow-Ellipsis für lange URLs in Admin-Listen
This commit is contained in:
Meleki committed 2026-03-12 17:11:06 +01:00
1 parent 006ef223bf
commit 608118a823
5 files changed
+55 -15

No files matched your search

+27 -9
View File
@@ -25,6 +25,8 @@ namespace Gott.Services
public static class AnthropicKeyChecker
{
private const string CheckModel = "claude-sonnet-4-20250514";
public static async Task<KeyCheckResult> CheckKeyAsync(IHttpClientFactory httpFactory, string apiKey)
{
try
@@ -34,30 +36,45 @@ namespace Gott.Services
var payload = JsonSerializer.Serialize(new
{
model = "claude-sonnet-4-20250514",
model = CheckModel,
max_tokens = 1,
messages = new[] { new { role = "user", content = "hi" } }
});
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.anthropic.com/v1/messages");
request.Headers.Add("x-api-key", apiKey);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
request.Headers.Add("anthropic-version", "2023-06-01");
request.Headers.Add("anthropic-beta", "claude-code-20250219,oauth-2025-04-20");
request.Headers.Add("User-Agent", "claude-cli/2.1.2 (external, cli)");
request.Headers.Add("x-app", "cli");
request.Headers.Add("anthropic-dangerous-direct-browser-access", "true");
request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
var resp = await client.SendAsync(request);
var statusCode = (int)resp.StatusCode;
var headers = resp.Headers;
if (statusCode == 401)
return new KeyCheckResult { Status = "invalid", Message = "Ungültig oder abgelaufen (401)", Plan = "Unknown" };
if (statusCode == 429)
{
var has7d = GetHeader(headers, "anthropic-ratelimit-unified-7d-utilization", "unified-7d-utilization");
var has5h = GetHeader(headers, "anthropic-ratelimit-unified-5h-utilization", "unified-5h-utilization");
if (has7d == null && has5h == null)
return new KeyCheckResult { Status = "invalid", Message = "Ungültig oder abgelaufen (401)", Plan = "Unknown" };
}
else if (statusCode == 429)
{
return new KeyCheckResult { Status = "rate_limited", Message = "Rate Limited (429)", Plan = "Unknown" };
if (statusCode == 403)
}
else if (statusCode == 403)
{
return new KeyCheckResult { Status = "quota_exceeded", Message = "Insufficient Quota (403)", Plan = "Unknown" };
if (statusCode >= 400)
}
else if (statusCode >= 400)
{
return new KeyCheckResult { Status = "error", Message = $"API-Fehler ({statusCode})", Plan = "Unknown" };
}
// Key gültig – Header auslesen
var headers = resp.Headers;
// Header auslesen
var d7Util = GetHeader(headers, "anthropic-ratelimit-unified-7d-utilization", "unified-7d-utilization");
var d5hUtil = GetHeader(headers, "anthropic-ratelimit-unified-5h-utilization", "unified-5h-utilization");
var overageUtil = GetHeader(headers, "anthropic-ratelimit-unified-overage-utilization", "unified-overage-utilization");
@@ -81,7 +98,8 @@ namespace Gott.Services
var result = new KeyCheckResult
{
Status = "ok",
Status = statusCode == 401 ? "usage_limited" : "ok",
Message = statusCode == 401 ? "Gültig, aber Usage-Limit erreicht (401)" : null,
Plan = plan,
IsSubscription = isSubscription,
Status7d = d7Status,