feat: 3 Scan-Modi (Quick/Web/Full) für Key Scanner
- Quick-Scan: nur GitHub mit Dotenv, Text, Markdown + .env - Web-Scan: nur Serper.dev (Google Dorks) - Full-Scan: GitHub + Serper komplett (wie bisher) - Backend: TriggerScan(mode), ScanGitHubQuick(), mode-basierte Quellsteuerung - Endpoint: ?mode=quick|web|full Query-Parameter - Frontend: 3 Buttons (⚡ Quick, 🌐 Web, 🔍 Full) mit gemeinsamer Scan-Logik - Status-Anzeige zeigt Scan-Modus im Ergebnis
This commit is contained in:
1 parent
ed8e5af428
commit
558ded1ed5
5 files changed
+117
-25
No files matched your search
@@ -30,6 +30,7 @@ public class KeyScannerService : BackgroundService
|
||||
private string _lastRun;
|
||||
private string _lastResult;
|
||||
private readonly ManualResetEventSlim _triggerNow = new(false);
|
||||
private string _scanMode = "full"; // full, quick, web
|
||||
|
||||
public bool IsRunning { get { lock (_lock) return _isRunning; } }
|
||||
public string LastRun { get { lock (_lock) return _lastRun; } }
|
||||
@@ -131,37 +132,46 @@ public class KeyScannerService : BackgroundService
|
||||
}
|
||||
|
||||
/// <summary>Wird vom Endpoint aufgerufen um einen sofortigen Scan auszulösen.</summary>
|
||||
public void TriggerScan()
|
||||
public void TriggerScan(string mode = "full")
|
||||
{
|
||||
lock (_lock) _scanMode = mode;
|
||||
_triggerNow.Set();
|
||||
}
|
||||
|
||||
private async Task RunScan(CancellationToken ct)
|
||||
{
|
||||
string mode;
|
||||
lock (_lock)
|
||||
{
|
||||
if (_isRunning) return;
|
||||
_isRunning = true;
|
||||
mode = _scanMode;
|
||||
_scanMode = "full"; // Reset für nächsten Lauf
|
||||
}
|
||||
|
||||
_logger.LogInformation("KeyScannerService: Scan gestartet");
|
||||
var modeLabels = new Dictionary<string, string> { ["quick"] = "Quick", ["web"] = "Web", ["full"] = "Full" };
|
||||
var modeLabel = modeLabels.ContainsKey(mode) ? modeLabels[mode] : "Full";
|
||||
_logger.LogInformation("KeyScannerService: {Mode}-Scan gestartet", modeLabel);
|
||||
var newKeysFound = 0;
|
||||
var checkedCount = 0;
|
||||
var totalFound = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Phase 1: Alle konfigurierten Quellen scannen
|
||||
// Phase 1: Quellen je nach Scan-Modus scannen
|
||||
var allFoundKeys = new List<(string Key, string Url, string Source)>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_githubToken))
|
||||
// Quick: nur GitHub mit reduzierten Sprachen/Pfaden
|
||||
// Full: GitHub + Serper
|
||||
// Web: nur Serper
|
||||
if (mode != "web" && !string.IsNullOrWhiteSpace(_githubToken))
|
||||
{
|
||||
var ghKeys = await ScanGitHub(ct);
|
||||
var ghKeys = mode == "quick" ? await ScanGitHubQuick(ct) : await ScanGitHub(ct);
|
||||
allFoundKeys.AddRange(ghKeys.Select(k => (k.Key, k.Url, "github")));
|
||||
_logger.LogInformation("GitHub-Scan: {Count} Key(s) gefunden", ghKeys.Count);
|
||||
_logger.LogInformation("GitHub-Scan ({Mode}): {Count} Key(s) gefunden", modeLabel, ghKeys.Count);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_serperApiKey))
|
||||
if (mode != "quick" && !string.IsNullOrWhiteSpace(_serperApiKey))
|
||||
{
|
||||
var spKeys = await ScanSerper(ct);
|
||||
allFoundKeys.AddRange(spKeys.Select(k => (k.Key, k.Url, "serper")));
|
||||
@@ -207,7 +217,7 @@ public class KeyScannerService : BackgroundService
|
||||
lock (_lock)
|
||||
{
|
||||
_lastRun = DateTime.UtcNow.ToString("o");
|
||||
_lastResult = $"{totalFound} gefunden, {newKeysFound} neu, {checkedCount} geprüft";
|
||||
_lastResult = $"{modeLabel}: {totalFound} gefunden, {newKeysFound} neu, {checkedCount} geprüft";
|
||||
}
|
||||
|
||||
_logger.LogInformation("KeyScannerService: Scan abgeschlossen – {Result}", _lastResult);
|
||||
@@ -228,7 +238,60 @@ public class KeyScannerService : BackgroundService
|
||||
}
|
||||
}
|
||||
|
||||
// ── GitHub Code Search (portiert aus ExampleScannerProject) ──
|
||||
// ── GitHub Code Search ──
|
||||
|
||||
private static readonly string[] QuickLanguages = { "Dotenv", "Text", "Markdown" };
|
||||
private static readonly string[] QuickPathExtensions = { ".env" };
|
||||
|
||||
/// <summary>Quick-Scan: nur die wichtigsten Sprachen/Pfade durchsuchen.</summary>
|
||||
private async Task<List<(string Key, string Url)>> ScanGitHubQuick(CancellationToken ct)
|
||||
{
|
||||
var allKeys = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
var queries = new List<(string Query, Regex Regex)>();
|
||||
|
||||
foreach (var (pattern, searchTerm) in KeyPatterns)
|
||||
{
|
||||
var regex = new Regex(pattern, RegexOptions.Compiled);
|
||||
foreach (var lang in QuickLanguages)
|
||||
{
|
||||
var langFilter = lang.Contains(' ') ? $"language:\"{lang}\"" : $"language:{lang}";
|
||||
queries.Add(($"{searchTerm} {langFilter}", regex));
|
||||
}
|
||||
foreach (var pathExt in QuickPathExtensions)
|
||||
queries.Add(($"{searchTerm} path:{pathExt}", regex));
|
||||
}
|
||||
|
||||
var client = _httpFactory.CreateClient();
|
||||
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("GottKeyScanner", "1.0"));
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github+json"));
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _githubToken);
|
||||
client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28");
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github.text-match+json"));
|
||||
|
||||
for (int i = 0; i < queries.Count; i++)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
var (query, regex) = queries[i];
|
||||
|
||||
try
|
||||
{
|
||||
var results = await SearchCodeAsync(client, query, regex, ct);
|
||||
foreach (var (key, url) in results)
|
||||
if (!allKeys.ContainsKey(key)) allKeys[key] = url;
|
||||
}
|
||||
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
|
||||
{
|
||||
_logger.LogWarning("GitHub Rate-Limit (Quick), warte 60s ...");
|
||||
await Task.Delay(60_000, ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("GitHub-Suche fehlgeschlagen (Quick): {Msg}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return allKeys.Select(kv => (kv.Key, kv.Value)).ToList();
|
||||
}
|
||||
|
||||
private async Task<List<(string Key, string Url)>> ScanGitHub(CancellationToken ct)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user