UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

76 lines (75 loc) • 3.33 kB
/** Reuse the CLI login through a live, run-scoped proof from One. */ import { randomUUID } from 'node:crypto'; import { z } from 'zod'; import { getOptionalOneAccessToken } from '../../auth/store.js'; import { VigilbaseApiError } from '../../lib/client.js'; import { VigilbaseOneClient } from '../../lib/one-client.js'; import { LocalCheckupError } from './errors.js'; import { displayRequester } from './submit-client.js'; const IdentityProofSchema = z.object({ success: z.literal(true), identity: z.object({ runId: z.uuid(), email: z.email().max(254), proof: z.string().min(1).max(2048), }) }); /** A signed-in requester. Its exchange always starts a new checkup, and vigilbase.com refuses one not awaiting an upload. */ export class IdentityRequester { #session; #renewed = false; #exchange; constructor(session, exchange) { this.#session = session; this.#exchange = exchange; } get requester() { return displayRequester(this.#session.requester); } get sessionCode() { return this.#session.code; } get expiresAt() { return this.#session.expiresAt; } get renewable() { return !this.#renewed; } async renew() { if (this.#renewed) throw new LocalCheckupError('SESSION_EXPIRED', 'The checkup session expired again after it was renewed.'); this.#renewed = true; this.#session = await this.#exchange(); } toJSON() { return { requester: this.requester }; } } /** * Ask One for a run-scoped proof of the saved login. It costs no email and * starts no checkup, so it runs alongside the availability check. Null when * there is no usable login, One rejects it, or `--email` names another address. */ export async function startSignedInIdentity(options) { const saved = await getOptionalOneAccessToken(options.config); if (saved.problem) options.warn(saved.problem); if (!saved.accessToken) return null; const one = new VigilbaseOneClient(options.config, saved.accessToken, true); const runId = randomUUID(); const proof = async () => { const response = await one.requestJson('/api/tools/cloudflare-checkup/local-identity', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ runId }), }); const parsed = IdentityProofSchema.safeParse(response); if (!parsed.success || parsed.data.identity.runId !== runId) { throw new LocalCheckupError('VERIFICATION_INVALID', 'One returned an invalid checkup identity proof.'); } return parsed.data.identity; }; let identity; try { identity = await proof(); } catch (error) { // A revoked or unverified login can still run the public email flow. if (error instanceof VigilbaseApiError && [401, 403].includes(error.status)) return null; throw error; } if (options.email && options.email.toLowerCase() !== identity.email.toLowerCase()) return null; return { async exchange(client, locale) { const renew = async () => client.exchangeIdentity({ ...await proof(), locale }); const session = await client.exchangeIdentity({ ...identity, locale }); return new IdentityRequester(session, renew); }, }; }