@kontextmind/kxm
Version:
KXM local-first multi-agent orchestration and operator dashboard
76 lines (69 loc) • 3.04 kB
text/typescript
// @ts-nocheck — vendored snapshot; host tsconfig is stricter than upstream.
import { antigravityEnv } from "./util.ts";
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "::1", "localhost"]);
const ALLOWED_API_HOST_SUFFIXES = [".googleapis.com", ".sandbox.googleapis.com"];
/** Only loopback binds are allowed so OAuth codes cannot be stolen off-machine. */
export function resolveCallbackHost(raw = antigravityEnv("CALLBACK_HOST")): string {
const host = (raw || "127.0.0.1").trim().toLowerCase();
if (!LOOPBACK_HOSTS.has(host)) {
throw new Error(
`Unsafe ANTIGRAVITY_CALLBACK_HOST="${host}". Only loopback hosts are allowed: 127.0.0.1, ::1, localhost.`,
);
}
return host === "localhost" ? "127.0.0.1" : host;
}
/** Prevent token exfiltration via poisoned BASE_URL (SSRF / credential leak). */
export function assertSafeApiBaseUrl(raw: string): string {
let url: URL;
try {
url = new URL(raw);
} catch {
throw new Error(`Invalid ANTIGRAVITY_BASE_URL: ${raw}`);
}
if (url.protocol !== "https:") {
throw new Error(`ANTIGRAVITY_BASE_URL must use https (got ${url.protocol})`);
}
if (url.username || url.password) {
throw new Error("ANTIGRAVITY_BASE_URL must not include credentials");
}
const host = url.hostname.toLowerCase();
const allowed =
host === "googleapis.com" || ALLOWED_API_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix));
if (!allowed) {
throw new Error(
`ANTIGRAVITY_BASE_URL host "${host}" is not allowed. Use a *.googleapis.com endpoint.`,
);
}
const path = url.pathname.replace(/\/+$/, "");
return `${url.origin}${path === "/" ? "" : path}`;
}
/** Redact bearer tokens, refresh tokens, and similar secrets from diagnostics/errors. */
export function redactSecrets(text: string): string {
return text
.replace(/\bya29\.[A-Za-z0-9._~+/-]+=*/g, "[redacted-access-token]")
.replace(/\b1\/\/[A-Za-z0-9_-]+/g, "[redacted-refresh-token]")
.replace(/\b1\/[A-Za-z0-9_-]{20,}/g, "[redacted-refresh-token]")
.replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [redacted]")
.replace(
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*")[^"]*(")/gi,
"$1[redacted]$2",
)
.replace(
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*)[^\s&,}]+/gi,
"$1[redacted]",
);
}
export function maskEmail(email: string | undefined): string | undefined {
if (!email || typeof email !== "string") return undefined;
const parts = email.split("@");
if (parts.length !== 2 || !parts[0] || !parts[1]) return "[redacted-email]";
const name = parts[0];
const domain = parts[1];
const lastChar = name.at(-1) || "";
const maskedName = name.length > 2 ? `${name[0]}***${lastChar}` : `${name[0]}***`;
return `${maskedName}@${domain}`;
}
export function safeError(error: unknown): string {
const raw = error instanceof Error ? error.message : String(error);
return redactSecrets(raw);
}