rep+: Ein AI-gestützter Repeater direkt in den Chrome DevTools
Motivation rep+ ist eine leichte Chrome-DevTools-Erweiterung, inspiriert von Burp Suite Repeater. Ziel: Requests schnell untersuchen, ohne die komplette Burp-Pipeline hochzufahren. Mit integrierter LLM-Unterstützung (lokal oder API) werden Header/Bodies generiert, transformiert oder erklärt – direkt neben dem Network-Panel.
Kernfunktionen
- DevTools-Panel “rep+” mit tabs für einzelne Requests
- Import aus Network-Panel (inkl. Methode, URL, Header, Body)
- Wiederholung von Requests mit editierbaren Headern/Body
- Mehrere Umgebungen (Base URL, Default-Header, Variablen)
- AI-Aktionen: Body/Headers vorschlagen, transformieren, Templates erzeugen, Unterschiede erklären
- Diff-Ansicht für Response-Körper und -Header (inline und side-by-side)
- Status/Timing/Size-Metriken, automatische Wiederholungen
- cURL/HAR Import/Export, JSON-Sessionsharing
- Tastatursteuerung für schnelles Iterieren
Architekturüberblick
- MV3 Service Worker: führt Requests aus (fetch), verwaltet Sessions und Settings, ruft optional LLMs
- DevTools Panel (UI): Editor, Diff, AI-Controls, Session-Verwaltung
- Messaging: chrome.runtime/message passing zwischen Panel und Worker
- Persistenz: chrome.storage.local (Sessions, Environments, Provider-Konfiguration)
- Optional: Offlinemodus für AI (lokale Modelle)
DevTools-Integration
- Panel-Erstellung via chrome.devtools.panels.create(“rep+”, …).
- Import aus Network-Panel über chrome.devtools.network.onRequestFinished:
- Extrahiert: URL, Methode, Header (request/response), Body (request), Timing, Status, Cookies (soweit zugänglich).
- Speichert als RequestSpec in rep+.
Request-Replay-Engine
- Ausführung: fetch im Service Worker mit RequestInit (method, headers, body, redirect, credentials)
- Wiederholungen: konfigurierbarer Retry mit Backoff
- Protokolle: HTTP/1.1/2 abhängig vom Browser; kein Low-Level-TLS-Fingerprint-Tuning
- Zeitlimits: globales Timeout pro Request; Abbruch via AbortController
- Response-Erfassung: Status, Header, Body (Text/Binär als Base64), Größe, Dauer, Redirect-Kette
Header/Body-Grenzen und CORS
- Nicht setzbare Header (Browser-forbidden): Host, Content-Length, Connection, Transfer-Encoding, Origin (teilweise), Referer (restriktiv), Sec-*
- Content-Length wird automatisch gesetzt
- Cookies: mit credentials: “include” werden Domain-Cookies gesendet, wenn host_permissions passen
- CORS: Extension-Kontext unterliegt nicht der Page-CORS-Policy, aber Cross-Origin-Fetch benötigt host_permissions
- TLS/ALPN/Fingerprint weicht von nativen Clients oder Burp ab; Serververhalten kann minimal variieren
AI-Assistenz
- Provider:
- Lokal: Ollama (HTTP API), LM Studio, OpenAI-compatible Gateway
- Remote: OpenAI, Anthropic, Azure OpenAI, Together, Mistral (API-Keys)
- Funktionen:
- Prompt-gestützte Transformationen (z. B. “mach daraus valid JSON”, “erzeuge multipart/form-data mit Datei-Platzhalter”)
- Header/Body-Vervollständigungen, Param-Exploration, Payload-Mutationen (fuzz-lite)
- Response-Erklärung, Regexp-Extraktion, Schema-Hypothesen
- Token-/Kostenkontrolle:
- Max tokens pro Anfrage, Rate Limit, Stop-Sequenzen
- Kontext-Zuschnitt: nur relevante Teile (Methode, URL, selektive Header, Body-Ausschnitt)
- Privacy:
- Redaktionsregeln: Secrets (Cookies, Tokens) standardmäßig maskieren, manuell freigeben
- Offlinemodus: Nur lokaler LLM, kein externer API-Call
- Streaming:
- Optionales Token-Streaming ins UI für schnelle Iteration
Installation (aus Source)
- Voraussetzungen: Node.js 18+, pnpm oder npm
- Schritte:
git clone https://github.com/your-org/rep-plus.git
cd rep-plus
pnpm install
pnpm build- In Chrome:
- chrome://extensions
- Entwicklermodus aktivieren
- Entpackte Erweiterung laden → dist/ auswählen
- DevTools öffnen → Tab “rep+”
Minimaler MV3-Manifestauszug
{
"name": "rep+",
"description": "Lightweight DevTools Repeater with AI",
"version": "0.1.0",
"manifest_version": 3,
"devtools_page": "devtools.html",
"background": { "service_worker": "worker.js", "type": "module" },
"permissions": ["storage"],
"host_permissions": ["https://*/", "http://*/"],
"action": { "default_title": "rep+" },
"icons": { "16": "icon16.png", "48": "icon48.png", "128": "icon128.png" }
}
DevTools-Panel Bootstrap
- devtools.html bindet devtools.js, das das Panel erzeugt
chrome.devtools.panels.create(
"rep+",
"icon16.png",
"panel.html",
function(panel) {
// optional: panel.onShown.addListener(...)
}
);
Service-Worker Skizze (Request-Ausführung)
chrome.runtime.onMessage.addListener(async (msg, sender, sendResponse) => {
if (msg.type === "REPLAY") {
try {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), msg.timeoutMs ?? 30000);
const res = await fetch(msg.url, {
method: msg.method,
headers: msg.headers,
body: msg.body,
redirect: msg.redirect ?? "follow",
credentials: msg.credentials ?? "include",
signal: ctrl.signal
});
clearTimeout(t);
const buf = await res.arrayBuffer();
sendResponse({
ok: res.ok,
status: res.status,
statusText: res.statusText,
headers: [...res.headers.entries()],
bodyB64: btoa(String.fromCharCode(...new Uint8Array(buf))),
url: res.url
});
} catch (e) {
sendResponse({ error: String(e) });
}
return true; // async
}
});
Import aus Network Panel
- Listener in devtools.js:
chrome.devtools.network.onRequestFinished.addListener(async (req) => {
const requestBody = await new Promise((resolve) =>
req.getContent((content, encoding) => resolve({ content, encoding }))
);
const entry = {
url: req.request.url,
method: req.request.method,
headers: req.request.headers,
postData: requestBody,
status: req.response.status,
responseHeaders: req.response.headers,
timings: req.time,
};
chrome.runtime.sendMessage({ type: "IMPORT", entry });
});
Datenmodell (vereinfacht)
type RequestSpec = {
id: string
name?: string
url: string
method: string
headers: { name: string, value: string }[]
body?: string | { type: "base64", data: string }
environmentId?: string
};
type ResponseRecord = {
status: number
statusText: string
headers: { name: string, value: string }[]
bodyB64?: string
durationMs: number
sizeBytes: number
url: string
};
type Tab = { request: RequestSpec, history: ResponseRecord[] };
type Session = { tabs: Tab[], environments: Environment[], createdAt: number };
Umgebungen und Variablen
- Environments definieren:
- baseUrl, defaultHeaders, variables (Key/Value, z. B. token, userId)
- Variablenersetzung im Request:
- {{varName}} in URL, Headern, Body
- Mehrere Environments pro Session; schnelle Umschaltung
AI-Provider-Konfiguration
- Felder:
- provider: “ollama” | “openai” | “anthropic” | “openai-compatible”
- endpoint: z. B. http://localhost:11434
- model: z. B. llama3.1:8b, gpt-4o-mini, claude-3.5-sonnet
- apiKey: nur wenn erforderlich
- maxTokens, temperature, rateLimitRps
- redactSecrets: true/false
- Beispiel (Ollama):
{
"provider": "ollama",
"endpoint": "http://localhost:11434",
"model": "llama3.1:8b",
"redactSecrets": true
}
Typische Workflows
- Aus dem Network-Panel übernehmen:
- Request im Network-Panel wählen → Button “Import to rep+”
- In rep+ Header/Body anpassen
- Mit Cmd/Ctrl+Enter ausführen, Responses vergleichen
- cURL importieren:
- cURL in Zwischenablage → Import → cURL einfügen
- Automatisches Mapping auf Methode, URL, Header, Body
- Schnell-Diff:
- Tab duplizieren, nur ein Feld ändern
- Responses side-by-side vergleichen
- AI-gestützte Mutation:
- Prompt: “Füge XSS-ähnliche Payload in alle text/html Felder ein”
- Vorschau prüfen, ausführen, Resultate sichten
Tastenkürzel
- Cmd/Ctrl+Enter: Ausführen
- Cmd/Ctrl+D: Tab duplizieren
- Cmd/Ctrl+/: AI-Prompt öffnen
- Alt+←/→: Zwischen Tabs wechseln
- Esc: Laufende AI-Ausgabe/Streaming abbrechen
Import/Export
- HAR: Auswahl an Requests als HAR exportieren, HAR-Import erzeugt Tabs
- cURL: Rundtripfähig (Import/Export)
- Session: JSON mit Tabs/Environments; geeignet zum Teilen/Versionieren
Berechtigungen und Sicherheit
- host_permissions: Ziel-Domains für Cross-Origin-Fetch
- storage: Persistenz der Sessions/Settings
- Optional cookies: Nur wenn programmatic Zugriff auf Cookies benötigt wird
- Geheimnisse:
- Redaction by default (Cookies, Authorization) für AI-Prompts
- Explizites Opt-in zum unmaskierten Senden
- Keine Inhalte werden ohne Nutzeraktion an externe LLMs gesendet
- Offlinemodus erzwingt lokale LLMs
Grenzfälle und Tipps
- Auth-Header: Authorization: Bearer … wird gesendet; aber achte auf Redaction-Regeln beim AI-Context
- Set-Cookie in Responses: wird erfasst, aber nicht automatisch persistiert; Cookies verwaltet der Browser
- Multipart: Boundary wird automatisch generiert, wenn Body per FormData gesendet wird; bei Raw multipart muss Boundary konsistent gesetzt werden
- Redirects: redirect: “follow” / “manual” steuerbar; bei “manual” Location-Header selbst auswerten
- Binärpayloads: In UI base64 anzeigen; Download-Button für Payload-Export
- Nicht setzbare Header (Host, Content-Length): vom Browser bestimmt; bei Host-Header-Hardchecks ggf. via Reverse-Proxy testen
Fehlersuche
- 403/401 trotz gültiger Cookies: Prüfe credentials: “include” und host_permissions
- CORS-Fehler: In Extensions eher host_permissions-Thema; Manifest prüfen
- TLS/JA3-Mismatch: Browser-Stack ist nicht anpassbar; vergleiche mit echten Clients nur bedingt
- AI blockiert: Rate Limit oder Token-Limit erhöhen; Streaming deaktivieren, wenn Prompts groß sind
Tags #chrome-extensiondevtoolsrepeaterburphttpaillmmv3securityprivacycurlharwebdebuggingproductivity