1import type { TrustedNetwork } from '../shared/sync-types';2import { getTrustedNetworks, addTrustedNetwork as storageAddTrustedNetwork } from './sync-storage';34export interface NetworkInfo {5 ssid?: string;6 bssid?: string;7 isTailscale: boolean;8 ipAddress?: string;9}1011export function isTailscaleIP(ip: string): boolean {12 const parts = ip.split('.').map(Number);13 if (parts.length !== 4 || parts.some(isNaN)) return false;14 const [a, b] = parts;15 return a === 100 && b >= 64 && b <= 127;16}1718export async function isOnTailscale(): Promise<boolean> {19 try {20 if (typeof chrome === 'undefined' || !(chrome as unknown as { system?: { network?: { getNetworkInterfaces: () => Promise<Array<{ address: string }>> } } }).system?.network) return false;21 const networkApi = (chrome as unknown as { system: { network: { getNetworkInterfaces: () => Promise<Array<{ address: string }>> } } }).system.network;22 const interfaces = await networkApi.getNetworkInterfaces();23 return interfaces.some((iface) => isTailscaleIP(iface.address));24 } catch {25 return false;26 }27}2829export async function getCurrentNetwork(): Promise<NetworkInfo> {30 const info: NetworkInfo = { isTailscale: false };3132 try {33 const chromeTyped = chrome as unknown as { system?: { network?: { getNetworkInterfaces: () => Promise<Array<{ address: string; name?: string }>> } } };34 if (chromeTyped.system?.network) {35 const networkApi = chromeTyped.system.network;36 const interfaces = await networkApi.getNetworkInterfaces();37 const tailscaleIface = interfaces.find((iface) => isTailscaleIP(iface.address));38 if (tailscaleIface) {39 info.isTailscale = true;40 info.ipAddress = tailscaleIface.address;41 } else if (interfaces.length > 0) {42 info.ipAddress = interfaces[0].address;43 }44 }45 } catch {46 47 }4849 return info;50}5152export async function isCurrentNetworkTrusted(): Promise<boolean> {53 try {54 const networks = await getTrustedNetworks();55 if (networks.length === 0) return false;5657 if (typeof chrome !== 'undefined') {58 const chromeTyped = chrome as unknown as { system?: { network?: { getNetworkInterfaces: () => Promise<Array<{ address: string }>> } } };59 if (chromeTyped.system?.network) {60 const interfaces = await chromeTyped.system.network.getNetworkInterfaces();61 const hasTailscaleIp = interfaces.some((iface) => isTailscaleIP(iface.address));6263 for (const network of networks) {64 if (network.isTailscale && hasTailscaleIp) return true;65 }66 }67 }6869 return false;70 } catch {71 return false;72 }73}7475export async function trustCurrentNetwork(): Promise<void> {76 const network = await getCurrentNetwork();77 const trusted: TrustedNetwork = {78 isTailscale: network.isTailscale,79 addedAt: Date.now(),80 };8182 if (network.ssid) trusted.ssid = network.ssid;83 if (network.bssid) trusted.bssid = network.bssid;84 if (network.ipAddress) {85 trusted.isTailscale = isTailscaleIP(network.ipAddress) || network.isTailscale;86 }8788 await storageAddTrustedNetwork(trusted);89}