Spaces:
Runtime error
Runtime error
File size: 2,333 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /**
* Client-side fetch helpers for the TPROXY decrypt capture mode (Epic A, 4c/N).
*
* Drive the local-only route /api/tools/agent-bridge/tproxy (#4211):
* - GET → status (running / available / interceptCount / onPort)
* - POST → start (apply TPROXY rules + open transparent listener + install CA)
* - DELETE → stop (close listener + uninstall CA + revert rules)
*
* Kept DOM-free so request/response/error handling is unit-testable by stubbing
* global.fetch. The status type is imported type-only so this client bundle never
* pulls the manager's native-addon / server dependencies.
*/
import type { CaptureManagerStatus } from "@/mitm/tproxy/captureManager";
const ROUTE = "/api/tools/agent-bridge/tproxy";
/** Extract the sanitized server error message, falling back to the status. */
async function errorMessage(res: Response): Promise<string> {
const body = (await res.json().catch(() => null)) as { error?: { message?: string } } | null;
return body?.error?.message ?? `HTTP ${res.status}`;
}
async function requestJson<T>(url: string, init?: RequestInit): Promise<T> {
const res = await fetch(url, init);
if (!res.ok) throw new Error(await errorMessage(res));
return (await res.json()) as T;
}
/** Optional TPROXY config overrides + the sudo password (desktop, non-root only). */
export interface StartTproxyOptions {
sudoPassword?: string;
dport?: number;
onPort?: number;
mark?: number;
routeTable?: number;
bypassMark?: number;
}
/** Current decrypt-capture status (safe to poll). */
export function fetchTproxyStatus(): Promise<CaptureManagerStatus> {
return requestJson<CaptureManagerStatus>(ROUTE);
}
/** Start decrypt capture; resolves with the resulting status. */
export function startTproxyCaptureMode(
options: StartTproxyOptions = {}
): Promise<CaptureManagerStatus> {
return requestJson<{ ok: boolean; status: CaptureManagerStatus }>(ROUTE, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(options),
}).then((r) => r.status);
}
/** Stop decrypt capture; resolves with the resulting status. */
export function stopTproxyCaptureMode(): Promise<CaptureManagerStatus> {
return requestJson<{ ok: boolean; status: CaptureManagerStatus }>(ROUTE, {
method: "DELETE",
}).then((r) => r.status);
}
|