import type { TrustedNetwork, PairedDevice, IncomingPairingRequest } from '../shared/sync-types'; const TRUSTED_NETWORKS_KEY = 'peach_trusted_networks'; const PAIRED_DEVICES_KEY = 'peach_paired_devices'; const INCOMING_PAIR_KEY = 'peach_incoming_pair'; const PEACH_HAS_PAIRED_KEY = 'peach_has_paired'; // --------------------------------------------------------------------------- // Has-paired flag // // Set once on first successful pairing. Never cleared — controls whether the // sync info sheet is shown. // --------------------------------------------------------------------------- export async function getHasPaired(): Promise { try { const result = await chrome.storage.local.get(PEACH_HAS_PAIRED_KEY); return (result as Record)[PEACH_HAS_PAIRED_KEY] === true; } catch { return false; } } export async function setHasPaired(): Promise { await chrome.storage.local.set({ [PEACH_HAS_PAIRED_KEY]: true }); } // --------------------------------------------------------------------------- // Trusted Networks // --------------------------------------------------------------------------- export async function getTrustedNetworks(): Promise { try { const result = await chrome.storage.local.get(TRUSTED_NETWORKS_KEY); return (result as { peach_trusted_networks?: TrustedNetwork[] })[TRUSTED_NETWORKS_KEY] ?? []; } catch { return []; } } export async function addTrustedNetwork(network: TrustedNetwork): Promise { try { const networks = await getTrustedNetworks(); networks.push(network); await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: networks }); } catch (err) { throw new Error(`Failed to add trusted network: ${err}`); } } export async function removeTrustedNetwork(addedAt: number): Promise { try { const networks = await getTrustedNetworks(); const filtered = networks.filter((n) => n.addedAt !== addedAt); await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: filtered }); } catch (err) { throw new Error(`Failed to remove trusted network: ${err}`); } } // --------------------------------------------------------------------------- // Paired Devices // --------------------------------------------------------------------------- export async function getPairedDevices(): Promise { try { const result = await chrome.storage.local.get(PAIRED_DEVICES_KEY); return (result as { peach_paired_devices?: PairedDevice[] })[PAIRED_DEVICES_KEY] ?? []; } catch { return []; } } export async function addPairedDevice(device: PairedDevice): Promise { try { const devices = await getPairedDevices(); const exists = devices.some((d) => d.deviceId === device.deviceId); if (exists) throw new Error(`Device ${device.deviceId} is already paired`); devices.push(device); await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: devices }); } catch (err) { throw new Error(`Failed to add paired device: ${err}`); } } export async function removePairedDevice(deviceId: string): Promise { try { const devices = await getPairedDevices(); const filtered = devices.filter((d) => d.deviceId !== deviceId); await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: filtered }); } catch (err) { throw new Error(`Failed to remove paired device: ${err}`); } } export async function updatePairedDevice( x25519PublicKey: string, patch: Partial>, ): Promise { try { const devices = await getPairedDevices(); const updated = devices.map((d) => d.x25519PublicKey === x25519PublicKey ? { ...d, ...patch } : d, ); await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: updated }); } catch (err) { throw new Error(`Failed to update paired device: ${err}`); } } // --------------------------------------------------------------------------- // Incoming Pairing Request // // Stored in session storage so the request disappears when the browser closes // and never lands on disk. The 60-second expiry is enforced by the consumer // (`getIncomingPairingRequest` returns null past expiry and clears storage). // --------------------------------------------------------------------------- export async function setIncomingPairingRequest( request: IncomingPairingRequest ): Promise { await chrome.storage.session.set({ [INCOMING_PAIR_KEY]: request }); } export async function getIncomingPairingRequest(): Promise { try { const result = await chrome.storage.session.get(INCOMING_PAIR_KEY); const request = (result as { peach_incoming_pair?: IncomingPairingRequest })[INCOMING_PAIR_KEY]; if (!request) return null; if (Date.now() >= request.expiresAt) { await clearIncomingPairingRequest(); return null; } return request; } catch { return null; } } export async function clearIncomingPairingRequest(): Promise { try { await chrome.storage.session.remove(INCOMING_PAIR_KEY); } catch { // session storage may be unavailable in some contexts; safe to ignore. } }