Spaces:
Runtime error
Runtime error
| /** | |
| * Paste-safe credential blob codec for the remote OAuth login helper. | |
| * | |
| * Why this exists: Google's `firstparty/nativeapp` consent for embedded desktop | |
| * clients (Antigravity, gemini-cli) only releases the authorization code when the | |
| * loopback redirect (127.0.0.1:<port>) is reachable. On a remote VPS install the | |
| * loopback is unreachable, so the consent hangs and never emits a code β there is | |
| * nothing for the user to paste back. (The same flow works locally and over an SSH | |
| * tunnel because then the loopback IS reachable.) | |
| * | |
| * The workaround: a local helper (`omniroute login antigravity`) runs the OAuth on | |
| * the user's own machine (loopback reachable β consent completes β tokens), then | |
| * encodes the raw token response into a single-line blob with this codec. The user | |
| * pastes the blob into the remote dashboard, which decodes it and persists the | |
| * connection (running the provider's post-exchange/onboarding from the server, | |
| * which CAN reach Google's Cloud Code APIs). | |
| * | |
| * Format: `<prefix><base64url(JSON)>` β a recognizable prefix so humans and the | |
| * decoder can identify it, followed by a URL/shell-safe base64url payload (no | |
| * `+`, `/`, `=`, or whitespace) so it survives copy-paste through terminals. | |
| */ | |
| /** Human-recognizable, copy-paste-safe prefix. The decoder requires it. */ | |
| export const CREDENTIAL_BLOB_PREFIX = "omniroute-cred-v1."; | |
| /** Current blob schema version (embedded in the payload as `v`). */ | |
| const CREDENTIAL_BLOB_VERSION = 1; | |
| export interface CredentialBlobTokens { | |
| access_token?: string; | |
| refresh_token?: string; | |
| id_token?: string; | |
| expires_in?: number; | |
| scope?: string; | |
| [key: string]: unknown; | |
| } | |
| export interface CredentialBlob { | |
| provider: string; | |
| tokens: CredentialBlobTokens; | |
| } | |
| /** | |
| * Encode a provider + raw OAuth token response into a single-line blob. | |
| * Throws if `provider` is missing β a blob with no provider cannot be routed. | |
| */ | |
| export function encodeCredentialBlob(input: CredentialBlob): string { | |
| if (!input || typeof input.provider !== "string" || !input.provider.trim()) { | |
| throw new Error("encodeCredentialBlob: a non-empty provider is required"); | |
| } | |
| if (!input.tokens || typeof input.tokens !== "object") { | |
| throw new Error("encodeCredentialBlob: tokens object is required"); | |
| } | |
| const payload = { | |
| v: CREDENTIAL_BLOB_VERSION, | |
| provider: input.provider.trim(), | |
| tokens: input.tokens, | |
| }; | |
| const json = JSON.stringify(payload); | |
| const b64 = Buffer.from(json, "utf8").toString("base64url"); | |
| return `${CREDENTIAL_BLOB_PREFIX}${b64}`; | |
| } | |
| /** | |
| * Decode a credential blob produced by {@link encodeCredentialBlob}. | |
| * Validates the prefix, version, JSON shape, and the presence of an access_token. | |
| * Throws a descriptive error on any malformed/tampered/unsupported input. | |
| */ | |
| export function decodeCredentialBlob(blob: string): CredentialBlob { | |
| if (typeof blob !== "string" || !blob.startsWith(CREDENTIAL_BLOB_PREFIX)) { | |
| throw new Error( | |
| `decodeCredentialBlob: invalid format β must start with "${CREDENTIAL_BLOB_PREFIX}"` | |
| ); | |
| } | |
| const b64 = blob.slice(CREDENTIAL_BLOB_PREFIX.length).trim(); | |
| if (!/^[A-Za-z0-9_-]+$/.test(b64)) { | |
| throw new Error("decodeCredentialBlob: invalid payload β not base64url"); | |
| } | |
| let parsed: { v?: unknown; provider?: unknown; tokens?: unknown }; | |
| try { | |
| const json = Buffer.from(b64, "base64url").toString("utf8"); | |
| parsed = JSON.parse(json); | |
| } catch { | |
| throw new Error("decodeCredentialBlob: invalid payload β could not parse JSON"); | |
| } | |
| if (parsed.v !== CREDENTIAL_BLOB_VERSION) { | |
| throw new Error( | |
| `decodeCredentialBlob: unsupported blob version ${String(parsed.v)} (expected ${CREDENTIAL_BLOB_VERSION})` | |
| ); | |
| } | |
| if (typeof parsed.provider !== "string" || !parsed.provider.trim()) { | |
| throw new Error("decodeCredentialBlob: invalid payload β missing provider"); | |
| } | |
| const tokens = parsed.tokens as CredentialBlobTokens | undefined; | |
| if (!tokens || typeof tokens !== "object") { | |
| throw new Error("decodeCredentialBlob: invalid payload β missing tokens"); | |
| } | |
| if (typeof tokens.access_token !== "string" || !tokens.access_token) { | |
| throw new Error("decodeCredentialBlob: invalid payload β missing access_token"); | |
| } | |
| return { provider: parsed.provider.trim(), tokens }; | |
| } | |