mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Closes #33. The MITM proxy only sees the agent's own actions, so anything behind a human gate (signup captcha, email OTP, 2FA, SSO) left the authenticated surface dark. The operator's browser becomes a capture source instead: - traffic: exported RecordExternal storing an externally captured exchange through the same spill/blob/FTS path as proxy traffic (insert logic shared with record()); rejects unparsable URLs and empty methods - server: POST /api/traffic/ingest inside the authenticated API group, batch capped at 50 entries, bodies truncated at 256 KiB, per-entry ingested/failed counts - extension/: Manifest V3 Chrome/Edge extension driving the chrome.debugger Network domain on the chosen tab, batching text exchanges to the ingest endpoint with the operator's URL + JWT in chrome.storage.local; binary bodies skipped; flush on batch/stop - tests for both layers, README section
47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
const $ = (id) => document.getElementById(id);
|
|
|
|
async function refreshState() {
|
|
const st = await chrome.runtime.sendMessage({ type: "getState" });
|
|
const lines = [];
|
|
lines.push(st.capturing
|
|
? `● Recording tab ${st.tabId}`
|
|
: "○ Not recording");
|
|
lines.push(`ingested: ${st.ingested} · queued: ${st.queued} · failed: ${st.failed}`);
|
|
if (st.lastError) lines.push(st.lastError);
|
|
$("status").textContent = lines.join("\n");
|
|
$("error").textContent = st.capturing ? "" : (st.lastError || "");
|
|
}
|
|
|
|
$("save").addEventListener("click", async () => {
|
|
await chrome.storage.local.set({
|
|
serverUrl: $("serverUrl").value.trim(),
|
|
token: $("token").value.trim(),
|
|
});
|
|
$("save").textContent = "Saved ✓";
|
|
setTimeout(() => ($("save").textContent = "Save settings"), 1200);
|
|
});
|
|
|
|
$("start").addEventListener("click", async () => {
|
|
const out = await chrome.runtime.sendMessage({ type: "start" });
|
|
if (out && out.ok === false) $("error").textContent = out.error || "failed to start";
|
|
refreshState();
|
|
});
|
|
|
|
$("stop").addEventListener("click", async () => {
|
|
await chrome.runtime.sendMessage({ type: "stop" });
|
|
refreshState();
|
|
});
|
|
|
|
$("flush").addEventListener("click", async () => {
|
|
await chrome.runtime.sendMessage({ type: "flushNow" });
|
|
refreshState();
|
|
});
|
|
|
|
(async () => {
|
|
const { serverUrl = "", token = "" } = await chrome.storage.local.get(["serverUrl", "token"]);
|
|
$("serverUrl").value = serverUrl;
|
|
$("token").value = token;
|
|
refreshState();
|
|
setInterval(refreshState, 1500);
|
|
})();
|