807418099580

TEST_WS_LOCAL + TEST_SUBNET_DETECT handlers in messages.ts for service-worker connectivity probe (v2.38.13)

time
2026-05-12 15:11 UTC · 5 months ago
machine
koh2
parent
717b4cb8afca
5 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.ts+92 −0src/shared/types.ts+2 −0
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.38.12",4+  "version": "2.38.13",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.38.12",4+  "version": "2.38.13",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "2.38.12",3+  "version": "2.38.13",44   "description": "Zero-knowledge password manager",55   "type": "module",66   "scripts": {

view file

src/background/messages.ts+92 −0
@@ -1246,6 +1246,98 @@12461246         const result = await discoverDevice(subnet, "000000000000000000000000000000000000000000000000000000000000000000");12471247         return { ok: true, data: { elapsed: Date.now() - start, found: !!result } };12481248       }1249+      case 'TEST_WS_LOCAL': {1250+        const { ip } = msg.payload as { ip: string };1251+1252+        return new Promise((resolve) => {1253+          const log: string[] = [];1254+          log.push(`Attempting ws://${ip}:44100 from service worker...`);1255+1256+          let ws: WebSocket;1257+          let settled = false;1258+          const settle = (result: MessageResponse) => {1259+            if (!settled) { settled = true; resolve(result); }1260+          };1261+1262+          try {1263+            ws = new WebSocket(`ws://${ip}:44100`);1264+1265+            ws.onopen = () => {1266+              log.push('SUCCESS: WebSocket connected');1267+              ws.close();1268+              settle({ ok: true, data: { log } });1269+            };1270+1271+            ws.onerror = (e) => {1272+              log.push(`FAILED: onerror fired — ${String(e)}`);1273+              settle({ ok: false, error: 'ws_error', data: { log } });1274+            };1275+1276+            ws.onclose = (e) => {1277+              if (e.code !== 1000) {1278+                log.push(`CLOSED unexpectedly: code=${e.code} reason=${e.reason}`);1279+                settle({ ok: false, error: 'ws_closed', data: { code: e.code, log } });1280+              }1281+            };1282+1283+            setTimeout(() => {1284+              try { ws.close(); } catch {}1285+              log.push('FAILED: 5 second timeout — connection never opened');1286+              settle({ ok: false, error: 'timeout', data: { log } });1287+            }, 5000);1288+1289+          } catch (err) {1290+            log.push(`FAILED: WebSocket constructor threw — ${String(err)}`);1291+            settle({ ok: false, error: 'constructor_threw', data: { log } });1292+          }1293+        });1294+      }1295+1296+      case 'TEST_SUBNET_DETECT': {1297+        return new Promise((resolve) => {1298+          try {1299+            // RTCPeerConnection availability varies by context — this is what we're testing1300+            // eslint-disable-next-line @typescript-eslint/no-explicit-any1301+            const RTC = (globalThis as any).RTCPeerConnection as (new (cfg: object) => RTCPeerConnection) | undefined;1302+            if (!RTC) {1303+              resolve({ ok: false, error: 'RTCPeerConnection is not defined' });1304+              return;1305+            }1306+            const pc = new RTC({ iceServers: [] });1307+            pc.createDataChannel('');1308+            pc.createOffer().then((o) => pc.setLocalDescription(o));1309+1310+            const candidates: string[] = [];1311+            const timer = setTimeout(() => {1312+              pc.close();1313+              if (candidates.length === 0) {1314+                resolve({ ok: false, error: 'no_candidates', data: { candidates } });1315+              } else {1316+                const subnet = candidates[0].match(/(\d+\.\d+\.\d+)\.\d+/)?.[1];1317+                resolve({ ok: true, data: { subnet, candidates } });1318+              }1319+            }, 2000);1320+1321+            pc.onicecandidate = (e) => {1322+              if (!e.candidate) return;1323+              const m = e.candidate.candidate.match(/(\d+\.\d+\.\d+\.\d+)/);1324+              if (m && !m[1].startsWith('127')) candidates.push(m[1]);1325+            };1326+1327+            pc.onicegatheringstatechange = () => {1328+              if (pc.iceGatheringState === 'complete') {1329+                clearTimeout(timer);1330+                pc.close();1331+                const subnet = candidates[0]?.match(/(\d+\.\d+\.\d+)\.\d+/)?.[1];1332+                resolve({ ok: candidates.length > 0, data: { subnet, candidates } });1333+              }1334+            };1335+          } catch (err) {1336+            resolve({ ok: false, error: String(err) });1337+          }1338+        });1339+      }1340+12491341       // --- end test handlers ---12501342       default:12511343         return { ok: false, error: "unknown message type" };

view file

src/shared/types.ts+2 −0
@@ -309,6 +309,8 @@309309   | "TEST_LOCAL_WEBSOCKET"310310   | "TEST_SUBNET_DETECTION"311311   | "TEST_SUBNET_SCAN"312+  | "TEST_WS_LOCAL"313+  | "TEST_SUBNET_DETECT"312314   // Content-script-bound message types — sent BY the background TO content313315   // scripts. They never reach messages.ts's switch. Kept in this union so314316   // existing call sites type-check; do not add cases for them in the

view file