1import type { TrustedNetwork, PairedDevice, IncomingPairingRequest } from '../shared/sync-types';23const TRUSTED_NETWORKS_KEY = 'peach_trusted_networks';4const PAIRED_DEVICES_KEY = 'peach_paired_devices';5const INCOMING_PAIR_KEY = 'peach_incoming_pair';67891011export async function getTrustedNetworks(): Promise<TrustedNetwork[]> {12 try {13 const result = await chrome.storage.local.get(TRUSTED_NETWORKS_KEY);14 return (result as { peach_trusted_networks?: TrustedNetwork[] })[TRUSTED_NETWORKS_KEY] ?? [];15 } catch {16 return [];17 }18}1920export async function addTrustedNetwork(network: TrustedNetwork): Promise<void> {21 try {22 const networks = await getTrustedNetworks();23 networks.push(network);24 await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: networks });25 } catch (err) {26 throw new Error(`Failed to add trusted network: ${err}`);27 }28}2930export async function removeTrustedNetwork(addedAt: number): Promise<void> {31 try {32 const networks = await getTrustedNetworks();33 const filtered = networks.filter((n) => n.addedAt !== addedAt);34 await chrome.storage.local.set({ [TRUSTED_NETWORKS_KEY]: filtered });35 } catch (err) {36 throw new Error(`Failed to remove trusted network: ${err}`);37 }38}3940export async function isCurrentNetworkTrusted(): Promise<boolean> {41 try {42 const networks = await getTrustedNetworks();43 if (networks.length === 0) return false;4445 46 const systemNetwork = (chrome as any).system?.network;47 const interfaces: Array<{ name: string; address: string; prefixLength?: number }> =48 systemNetwork ? await systemNetwork.getNetworkInterfaces() : [];4950 const hasTailscaleIp = interfaces.some((iface) => isTailscaleAddress(iface.address));5152 for (const network of networks) {53 if (network.isTailscale && hasTailscaleIp) return true;54 }5556 return false;57 } catch {58 return false;59 }60}6162function isTailscaleAddress(address: string): boolean {63 const parts = address.split('.').map(Number);64 if (parts.length !== 4 || parts.some(isNaN)) return false;65 const [a, b] = parts;66 return a === 100 && b >= 64 && b <= 127;67}686970717273export async function getPairedDevices(): Promise<PairedDevice[]> {74 try {75 const result = await chrome.storage.local.get(PAIRED_DEVICES_KEY);76 return (result as { peach_paired_devices?: PairedDevice[] })[PAIRED_DEVICES_KEY] ?? [];77 } catch {78 return [];79 }80}8182export async function addPairedDevice(device: PairedDevice): Promise<void> {83 try {84 const devices = await getPairedDevices();85 const exists = devices.some((d) => d.deviceId === device.deviceId);86 if (exists) throw new Error(`Device ${device.deviceId} is already paired`);87 devices.push(device);88 await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: devices });89 } catch (err) {90 throw new Error(`Failed to add paired device: ${err}`);91 }92}9394export async function removePairedDevice(deviceId: string): Promise<void> {95 try {96 const devices = await getPairedDevices();97 const filtered = devices.filter((d) => d.deviceId !== deviceId);98 await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: filtered });99 } catch (err) {100 throw new Error(`Failed to remove paired device: ${err}`);101 }102}103104export async function updatePairedDevice(deviceId: string, updates: Partial<PairedDevice>): Promise<void> {105 try {106 const devices = await getPairedDevices();107 const index = devices.findIndex((d) => d.deviceId === deviceId);108 if (index === -1) throw new Error(`Device ${deviceId} not found`);109 devices[index] = { ...devices[index], ...updates, deviceId };110 await chrome.storage.local.set({ [PAIRED_DEVICES_KEY]: devices });111 } catch (err) {112 throw new Error(`Failed to update paired device: ${err}`);113 }114}115116export async function getPairedDevice(deviceId: string): Promise<PairedDevice | undefined> {117 try {118 const devices = await getPairedDevices();119 return devices.find((d) => d.deviceId === deviceId);120 } catch {121 return undefined;122 }123}124125126127128129130131132133export async function setIncomingPairingRequest(134 request: IncomingPairingRequest135): Promise<void> {136 await chrome.storage.session.set({ [INCOMING_PAIR_KEY]: request });137}138139export async function getIncomingPairingRequest(): Promise<IncomingPairingRequest | null> {140 try {141 const result = await chrome.storage.session.get(INCOMING_PAIR_KEY);142 const request = (result as { peach_incoming_pair?: IncomingPairingRequest })[INCOMING_PAIR_KEY];143 if (!request) return null;144 if (Date.now() >= request.expiresAt) {145 await clearIncomingPairingRequest();146 return null;147 }148 return request;149 } catch {150 return null;151 }152}153154export async function clearIncomingPairingRequest(): Promise<void> {155 try {156 await chrome.storage.session.remove(INCOMING_PAIR_KEY);157 } catch {158 159 }160}