Files
gott/Services/StripeKeyChecker.cs
T
Meleki 3cd35ebbfa feat: Stripe-Key-Checker, Krea AI Pattern, Scan-Progress-Tracking
- StripeKeyChecker: 2-Schritt-Check (/v1/balance + /v1/account), Live/Test-Erkennung, Balance, Account-Details
- KeyPatterns: Stripe-Patterns einkommentiert (sk_live_, sk_test_), Krea AI Pattern (UUID:Token), Mindest-Suchlänge 4
- KeyScannerService: Stripe-Check integriert, Auto-Check nach Scan entfernt (manuell separat), Progress-Tracking (Phase, Detail, Current/Total, KeysFound)
- ApiKeysEndpoint: Stripe in HandleCheck/HandleCheckAll/HandleAdopt, Progress im Status-Endpoint
- Frontend: Live-Fortschrittsanzeige mit Spinner, Phase, Query, Counter, Polling 1.5s, Krea AI in typeNames/typeIcons
2026-03-14 14:34:02 +01:00

202 lines
8.2 KiB
C#

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
namespace Gott.Services
{
public class StripeCheckResult
{
public string Status { get; set; } // "ok", "invalid", "error"
public string Message { get; set; }
public bool IsLiveKey { get; set; }
public string Currency { get; set; }
public long? BalanceAvailable { get; set; }
public long? BalancePending { get; set; }
public string AccountId { get; set; }
public string AccountName { get; set; }
public string AccountEmail { get; set; }
public string AccountCountry { get; set; }
public bool? PayoutsEnabled { get; set; }
public bool? ChargesEnabled { get; set; }
}
public static class StripeKeyChecker
{
public static async Task<StripeCheckResult> CheckKeyAsync(IHttpClientFactory httpFactory, string apiKey)
{
try
{
var client = httpFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var isLive = apiKey.StartsWith("sk_live_", StringComparison.Ordinal);
// Step 1: Check /v1/balance (read-only, no cost)
var balanceRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.stripe.com/v1/balance");
balanceRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
var balanceResp = await client.SendAsync(balanceRequest);
var balanceBody = await balanceResp.Content.ReadAsStringAsync();
var balanceCode = (int)balanceResp.StatusCode;
if (balanceCode == 401)
{
return new StripeCheckResult
{
Status = "invalid",
Message = "Ungültig oder revoked (401)",
IsLiveKey = isLive
};
}
if (balanceCode >= 400)
{
// Parse error
var errorMsg = "Unbekannter Fehler";
try
{
using var errDoc = JsonDocument.Parse(balanceBody);
if (errDoc.RootElement.TryGetProperty("error", out var errObj) &&
errObj.TryGetProperty("message", out var msg))
errorMsg = msg.GetString();
}
catch { }
return new StripeCheckResult
{
Status = "error",
Message = $"API-Fehler ({balanceCode}): {errorMsg}",
IsLiveKey = isLive
};
}
// Parse balance
string currency = null;
long balanceAvailable = 0;
long balancePending = 0;
try
{
using var balDoc = JsonDocument.Parse(balanceBody);
var root = balDoc.RootElement;
if (root.TryGetProperty("available", out var available) && available.GetArrayLength() > 0)
{
var first = available[0];
if (first.TryGetProperty("currency", out var cur))
currency = cur.GetString()?.ToUpperInvariant();
if (first.TryGetProperty("amount", out var amt))
balanceAvailable = amt.GetInt64();
}
if (root.TryGetProperty("pending", out var pending) && pending.GetArrayLength() > 0)
{
var first = pending[0];
if (first.TryGetProperty("amount", out var amt))
balancePending = amt.GetInt64();
}
}
catch { }
// Step 2: Get account info via /v1/account
string accountId = null;
string accountName = null;
string accountEmail = null;
string accountCountry = null;
bool? payoutsEnabled = null;
bool? chargesEnabled = null;
try
{
var accountRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.stripe.com/v1/account");
accountRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
var accountResp = await client.SendAsync(accountRequest);
if ((int)accountResp.StatusCode == 200)
{
var accountBody = await accountResp.Content.ReadAsStringAsync();
using var accDoc = JsonDocument.Parse(accountBody);
var acc = accDoc.RootElement;
if (acc.TryGetProperty("id", out var id))
accountId = id.GetString();
if (acc.TryGetProperty("business_profile", out var bp) && bp.TryGetProperty("name", out var name))
accountName = name.GetString();
if (acc.TryGetProperty("email", out var email))
accountEmail = email.GetString();
if (acc.TryGetProperty("country", out var country))
accountCountry = country.GetString();
if (acc.TryGetProperty("payouts_enabled", out var pe))
payoutsEnabled = pe.GetBoolean();
if (acc.TryGetProperty("charges_enabled", out var ce))
chargesEnabled = ce.GetBoolean();
}
}
catch { }
// Build message
var parts = new System.Collections.Generic.List<string>();
parts.Add(isLive ? "🔴 LIVE Key" : "🟡 Test Key");
if (accountName != null)
parts.Add($"Account: {accountName}");
else if (accountId != null)
parts.Add($"Account: {accountId}");
if (accountEmail != null)
parts.Add($"Email: {accountEmail}");
if (accountCountry != null)
parts.Add($"Land: {accountCountry}");
if (currency != null)
{
var availFormatted = FormatAmount(balanceAvailable, currency);
var pendingFormatted = FormatAmount(balancePending, currency);
parts.Add($"Balance: {availFormatted} verfügbar, {pendingFormatted} ausstehend");
}
if (chargesEnabled.HasValue)
parts.Add(chargesEnabled.Value ? "✅ Charges aktiv" : "❌ Charges deaktiviert");
if (payoutsEnabled.HasValue)
parts.Add(payoutsEnabled.Value ? "✅ Payouts aktiv" : "❌ Payouts deaktiviert");
return new StripeCheckResult
{
Status = "ok",
Message = string.Join(" · ", parts),
IsLiveKey = isLive,
Currency = currency,
BalanceAvailable = balanceAvailable,
BalancePending = balancePending,
AccountId = accountId,
AccountName = accountName,
AccountEmail = accountEmail,
AccountCountry = accountCountry,
PayoutsEnabled = payoutsEnabled,
ChargesEnabled = chargesEnabled
};
}
catch (Exception ex)
{
return new StripeCheckResult
{
Status = "error",
Message = ex.Message,
IsLiveKey = apiKey.StartsWith("sk_live_", StringComparison.Ordinal)
};
}
}
private static string FormatAmount(long amountInCents, string currency)
{
var amount = amountInCents / 100.0;
return $"{amount:N2} {currency}";
}
}
}