12345678910111213import {14 pairWithCode,15 type CodePairingDeps,16 type CodePairingCallbacks,17} from "./code-pairing";18import { openPairingSocket } from "../shared/pairing-dial";19import { upsertPairedDevice, setLastKnownIp } from "./paired-devices";20import { buildLocalIdentity } from "./device-identity";21import { computeVaultId } from "../shared/sync-identity";22import { isUnlocked, getRootKeyHex } from "./vault";23import type { LocalIdentity } from "../shared/pairing-handshake";2425function hexToBytesLocal(hex: string): Uint8Array {26 const out = new Uint8Array(hex.length / 2);27 for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);28 return out;29}303132function push(type: string, payload: unknown): void {33 try {34 const maybe = chrome.runtime.sendMessage({ type, payload }) as unknown;35 if (maybe && typeof (maybe as Promise<unknown>).catch === "function") {36 (maybe as Promise<unknown>).catch(() => undefined);37 }38 } catch {39 40 }41}424344export function productionCodePairingDeps(): CodePairingDeps {45 return {46 openSocket: (ip, port) => openPairingSocket(ip, port),47 async getLocalIdentity(): Promise<LocalIdentity> {48 if (!isUnlocked()) throw new Error("vault_locked");49 const masterKeyHex = getRootKeyHex();50 if (!masterKeyHex) throw new Error("vault_locked");51 52 53 const masterKey = hexToBytesLocal(masterKeyHex);54 try {55 const base = await buildLocalIdentity(masterKey);56 const vaultId = await computeVaultId(masterKey);57 return { ...base, vaultId };58 } finally {59 masterKey.fill(0);60 }61 },62 persistDevice: (d) => upsertPairedDevice(d),63 cacheLastKnownIp: (pubkeyHex, ip) => setLastKnownIp(pubkeyHex, ip),64 };65}6667686970let pendingConfirm: ((confirmed: boolean) => void) | null = null;71let inFlight = false;7273function clearPairingState(): void {74 pendingConfirm = null;75 inFlight = false;76}7778export function isCodePairingInFlight(): boolean {79 return inFlight;80}81828384858687export function startCodePairing(88 code: string,89 deps: CodePairingDeps = productionCodePairingDeps(),90): void {91 inFlight = true;92 const cb: CodePairingCallbacks = {93 onSasReady: (sas) => push("CODE_PAIR_SAS", { sas }),94 onComplete: (device) => {95 push("CODE_PAIR_RESULT", { status: "complete", device });96 clearPairingState();97 },98 onError: (error) => {99 push("CODE_PAIR_RESULT", { status: "error", error });100 clearPairingState();101 },102 };103 104 const confirm = (_sas: string): Promise<boolean> =>105 new Promise<boolean>((resolve) => { pendingConfirm = resolve; });106107 void pairWithCode(code, cb, deps, confirm).finally(() => {108 109 110 if (inFlight) clearPairingState();111 });112}113114115export function resolveCodePairingConfirm(confirmed: boolean): void {116 const resolve = pendingConfirm;117 pendingConfirm = null;118 if (resolve) resolve(confirmed);119}