@tonyruan/dsh-bridge-host 0.1.1-beta.4 → 0.1.1-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/agent.mjs +12 -6
- package/lib/child.mjs +38 -38
- package/lib/client.js +428 -427
- package/lib/controller.mjs +154 -26
- package/lib/index.mjs +1705 -1424
- package/lib/local-management.mjs +303 -47
- package/lib/management.mjs +177 -49
- package/lib/multi-client-profile.mjs +2 -2
- package/lib/multi-client-session.mjs +54 -42
- package/lib/profile-store.mjs +2 -2
- package/lib/session.mjs +57 -45
- package/package.json +3 -3
- package/scripts/prepublish-check.mjs +1 -1
package/README.md
CHANGED
|
@@ -7,3 +7,6 @@ Package: @tonyruan/dsh-bridge-host. Use the official DSH plugin manager for inst
|
|
|
7
7
|
This generic build contains no personal relay preset or update root/feed. Import the original trusted deployment configuration or use the private migration bridge locally before replacing an old configured build. Existing paired profiles without deployment configuration fail recoverably and retain identity, pairing and login data. Strict LAN-only use does not enable update or diagnostic networking.
|
|
8
8
|
|
|
9
9
|
Own project code is licensed under the standard PolyForm Noncommercial License1.0.0 in LICENSE. This is not OSI open-source; permitted purposes and exceptions are governed by that exact text, not a blanket promise about every business/payment scenario. Third-party components retain their own permission, copyright and NOTICE terms in THIRD-PARTY-NOTICES.txt and oss-licenses/. These own-code terms do not restrict upstream rights. The complete own development project/Git repository is not included; npm runtime JavaScript is publicly readable. Native platform download assets are not included in this npm release.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Beta6/build26 retains the original validated persisted connection realm across upgrades and LAN-only restarts, including previously paired WSS realms without an unused relay leaf. Existing trusted deployment is reused without import or rewrite. AUTO still requires trusted TLS material. Legacy private code-only presets require the separately delivered Linux pre-upgrade migration helper before replacement; it statically validates the original local package and pin, never executes old code or fetches a new network leaf. No identity/pairing/schema reinitialization or client update-source JSON is required. Physical LAN management and the original phone-connection product label/icon remain as in the tested beta5.
|
package/lib/agent.mjs
CHANGED
|
@@ -332,7 +332,13 @@ var require_is_electron = __commonJS({
|
|
|
332
332
|
}
|
|
333
333
|
});
|
|
334
334
|
|
|
335
|
-
//
|
|
335
|
+
// host-config-migration-r1/host/phone-access-plugin/src/lan-provenance.mjs
|
|
336
|
+
var accepted = /* @__PURE__ */ new WeakMap();
|
|
337
|
+
function acceptedLanEndpoint(socket) {
|
|
338
|
+
return socket.destroyed ? null : accepted.get(socket) ?? null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// host-config-migration-r1/host/phone-access-plugin/src/agent.mjs
|
|
336
342
|
import net from "node:net";
|
|
337
343
|
import { once } from "node:events";
|
|
338
344
|
|
|
@@ -15327,7 +15333,7 @@ function noise(init = {}) {
|
|
|
15327
15333
|
return (components) => new Noise(components, init);
|
|
15328
15334
|
}
|
|
15329
15335
|
|
|
15330
|
-
//
|
|
15336
|
+
// host-config-migration-r1/host/phone-access-plugin/src/lan-trace.mjs
|
|
15331
15337
|
var LAN_DETAIL_CODES = Object.freeze(["LAN_TCP_ACCEPTED", "LAN_TCP_CLOSED_REJECTED", "LAN_TCP_DISABLED_REJECTED", "LAN_TCP_POLICY_REJECTED", "LAN_TCP_SUBNET_REJECTED", "LAN_TCP_LIMIT_REJECTED", "LAN_TCP_GLOBAL_RATE_REJECTED", "LAN_TCP_SOURCE_RATE_REJECTED", "LAN_TCP_RATE_KEYS_REJECTED", "LAN_AGENT_CLOSED_REJECTED", "LAN_AGENT_LIMIT_REJECTED", "LAN_AGENT_HANDSHAKE_LIMIT_REJECTED", "LAN_AGENT_PEER_LIMIT_REJECTED", "LAN_AGENT_ADMISSION_REJECTED", "LAN_AGENT_READMISSION_REJECTED", "LAN_AGENT_FIRST_FRAME_EOF", "LAN_AGENT_NOISE_FAILED", "LAN_AGENT_FIRST_FRAME_TIMEOUT", "LAN_AGENT_FIRST_FRAME_FAILED", "LAN_AGENT_BACKEND_CONNECT_FAILED", "LAN_AGENT_REGISTER_FAILED", "LAN_AGENT_FORWARD_FAILED", "LAN_AGENT_CHANNEL_READY", "LAN_AGENT_CHANNEL_CLOSED"]);
|
|
15332
15338
|
var codes = new Set(LAN_DETAIL_CODES);
|
|
15333
15339
|
var bounded = (v, max) => Number.isSafeInteger(v) && v >= 0 ? Math.min(max, v) : 0;
|
|
@@ -15395,7 +15401,7 @@ function createLanTrace(diagnostic = () => {
|
|
|
15395
15401
|
return { sample, lifetime, now };
|
|
15396
15402
|
}
|
|
15397
15403
|
|
|
15398
|
-
//
|
|
15404
|
+
// host-config-migration-r1/host/noise-lab/core.mjs
|
|
15399
15405
|
var silent = Object.assign(() => {
|
|
15400
15406
|
}, { enabled: false, error: () => {
|
|
15401
15407
|
}, trace: () => {
|
|
@@ -15435,7 +15441,7 @@ async function temporaryIdentity() {
|
|
|
15435
15441
|
return { privateKey, peerId: peerIdFromPrivateKey(privateKey) };
|
|
15436
15442
|
}
|
|
15437
15443
|
|
|
15438
|
-
//
|
|
15444
|
+
// host-config-migration-r1/host/phone-access-plugin/src/agent.mjs
|
|
15439
15445
|
async function createPcAgent({ backendPort, listenPort = 0, listen = true, identity: providedIdentity, pairing = () => ({ confirmed: false, pin: null }), acquireLease, registerBackend, diagnostic = () => {
|
|
15440
15446
|
}, factories = {} }) {
|
|
15441
15447
|
if (!Number.isInteger(backendPort) || backendPort < 1 || backendPort > 65535) throw Error("INVALID_FIXED_BACKEND");
|
|
@@ -15452,7 +15458,7 @@ async function createPcAgent({ backendPort, listenPort = 0, listen = true, ident
|
|
|
15452
15458
|
let handshaking = 0, closed = false, attempts = 0;
|
|
15453
15459
|
const stats = { handshakes: 0, rejected: 0, handshakeFailed: 0, dshConnections: 0, upBytes: 0, downBytes: 0 };
|
|
15454
15460
|
const acceptWire = (wire, { route = "RELAY", pairId } = {}) => {
|
|
15455
|
-
const attempt = ++attempts, began = trace.now();
|
|
15461
|
+
const attempt = ++attempts, began = trace.now(), lanEndpoint = route === "LAN" ? acceptedLanEndpoint(wire) : null;
|
|
15456
15462
|
const event = (code3) => {
|
|
15457
15463
|
try {
|
|
15458
15464
|
diagnostic({ stage: route === "LAN" ? "LAN" : "AUTH", code: code3, attempt });
|
|
@@ -15629,7 +15635,7 @@ async function createPcAgent({ backendPort, listenPort = 0, listen = true, ident
|
|
|
15629
15635
|
check();
|
|
15630
15636
|
if (registerBackend) {
|
|
15631
15637
|
phase = "REGISTER";
|
|
15632
|
-
const registration = Promise.resolve(registerBackend({ localAddress: backend.localAddress, localPort: backend.localPort, remoteAddress: backend.remoteAddress, remotePort: backend.remotePort })).then((fn) => {
|
|
15638
|
+
const registration = Promise.resolve(registerBackend({ localAddress: backend.localAddress, localPort: backend.localPort, remoteAddress: backend.remoteAddress, remotePort: backend.remotePort }, lease && lease.valid() ? { schema: 1, route: route === "LAN" && lanEndpoint ? "LAN" : route === "RELAY" ? "RELAY" : "UNKNOWN", peerId: lease.peerId, pairId: lease.pairId, generation: lease.generation, lanEndpoint: route === "LAN" ? lanEndpoint : null } : null)).then((fn) => {
|
|
15633
15639
|
let released = false;
|
|
15634
15640
|
const once2 = () => {
|
|
15635
15641
|
if (released) return;
|
package/lib/child.mjs
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import {createPcAgent} from './agent.mjs';
|
|
2
|
-
import {createPhoneSession} from './session.mjs';
|
|
3
|
-
import {randomUUID} from 'node:crypto';
|
|
4
|
-
let agent,closing=false,heartbeat;
|
|
5
|
-
const registrations=new Map();
|
|
6
|
-
function registerBackend(tuple){return new Promise((resolve,reject)=>{
|
|
7
|
-
const registrationId=randomUUID(),timer=setTimeout(()=>{registrations.delete(registrationId);process.send?.({op:'backend.close',registrationId},()=>{});reject(Error('BACKEND_REGISTRATION_TIMEOUT'));},3000);
|
|
8
|
-
registrations.set(registrationId,{resolve,reject,timer});
|
|
9
|
-
process.send?.({op:'backend.open',registrationId,tuple},error=>{if(error){clearTimeout(timer);registrations.delete(registrationId);reject(Error('BACKEND_REGISTRATION_FAILED'));}});
|
|
10
|
-
});}
|
|
11
|
-
const finish=async()=>{if(closing)return;closing=true;clearInterval(heartbeat);await agent?.close();process.exit(0);};
|
|
12
|
-
process.on('disconnect',finish);process.on('SIGTERM',finish);process.on('SIGINT',finish);
|
|
13
|
-
// Parent IPC is the only controller. No unauthenticated control HTTP listener exists.
|
|
14
|
-
process.on('message',async message=>{
|
|
15
|
-
if(closing)return;
|
|
16
|
-
try{
|
|
17
|
-
if(message?.op==='backend.ack'){
|
|
18
|
-
const r=registrations.get(message.registrationId);if(!r)return;registrations.delete(message.registrationId);clearTimeout(r.timer);
|
|
19
|
-
if(!message.ok)r.reject(Error('BACKEND_REGISTRATION_REJECTED'));else {let released=false;r.resolve(()=>{if(released)return;released=true;process.send?.({op:'backend.close',registrationId:message.registrationId},()=>{});});}return;
|
|
20
|
-
}
|
|
21
|
-
if(message?.op==='init'){
|
|
22
|
-
if(agent)throw Error('ALREADY_INITIALIZED');
|
|
23
|
-
if(message.profileDirectory&&!message.relay)throw Error('PERSISTENT_PROFILE_REQUIRES_FIXED_RELAY');
|
|
24
|
-
agent=message.relay?await createPhoneSession({backendPort:message.backendPort,connectionMode:message.connectionMode??'auto',lanAddress:message.lanAddress,relay:message.relay,relayCa:message.relayCa,relayLeaf:message.relayLeaf,profileDirectory:message.profileDirectory,lanEnabled:message.lanEnabled===true,registerBackend,diagnostics:{record:event=>{if(process.connected)process.send?.({op:'diagnostic',event:{...event,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});}}}):await createPcAgent({backendPort:message.backendPort,registerBackend});
|
|
25
|
-
heartbeat=setInterval(()=>{if(process.connected)process.send?.({op:'diagnostic',event:{stage:'LOCAL',code:'COMPANION_HEARTBEAT',count:1,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});},30000);heartbeat.unref?.();
|
|
26
|
-
process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
|
|
27
|
-
}else if(message?.op==='status'&&agent)process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
|
|
28
|
-
else if(message?.op==='confirmReverseScan'&&agent?.confirmReverseScan){await agent.confirmReverseScan(message.qr);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
29
|
-
else if(message?.op==='pair/start'&&agent?.beginPairing){await agent.beginPairing();process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
30
|
-
else if(message?.op==='pair/cancel'&&agent?.cancelPairing){await agent.cancelPairing(message.sessionId);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
31
|
-
else if(message?.op==='revoke'&&agent?.revoke){await agent.revoke(message.target);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
32
|
-
else if(message?.op==='lan/settings'&&agent?.setLanEnabled){await agent.setLanEnabled(message.enabled);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
33
|
-
else if(message?.op==='reconnect'&&agent?.reconnect){await agent.reconnect();process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
34
|
-
else if(message?.op==='stop')await finish();
|
|
35
|
-
}catch(error){const code=error?.code??error?.message;process.send?.({id:message?.id,ok:false,error:/^[A-Z_]{3,70}$/.test(code??'')?code:'AGENT_OPERATION_FAILED'});if(!agent)await finish();}
|
|
36
|
-
});
|
|
37
|
-
// Failed owners must not leave a child waiting forever before init.
|
|
38
|
-
setTimeout(()=>{if(!agent)finish();},10000).unref();
|
|
1
|
+
import {createPcAgent} from './agent.mjs';
|
|
2
|
+
import {createPhoneSession} from './session.mjs';
|
|
3
|
+
import {randomUUID} from 'node:crypto';
|
|
4
|
+
let agent,closing=false,heartbeat;
|
|
5
|
+
const registrations=new Map();
|
|
6
|
+
function registerBackend(tuple,provenance){return new Promise((resolve,reject)=>{
|
|
7
|
+
const registrationId=randomUUID(),timer=setTimeout(()=>{registrations.delete(registrationId);process.send?.({op:'backend.close',registrationId},()=>{});reject(Error('BACKEND_REGISTRATION_TIMEOUT'));},3000);
|
|
8
|
+
registrations.set(registrationId,{resolve,reject,timer});
|
|
9
|
+
process.send?.({op:'backend.open',registrationId,tuple,provenance},error=>{if(error){clearTimeout(timer);registrations.delete(registrationId);reject(Error('BACKEND_REGISTRATION_FAILED'));}});
|
|
10
|
+
});}
|
|
11
|
+
const finish=async()=>{if(closing)return;closing=true;clearInterval(heartbeat);await agent?.close();process.exit(0);};
|
|
12
|
+
process.on('disconnect',finish);process.on('SIGTERM',finish);process.on('SIGINT',finish);
|
|
13
|
+
// Parent IPC is the only controller. No unauthenticated control HTTP listener exists.
|
|
14
|
+
process.on('message',async message=>{
|
|
15
|
+
if(closing)return;
|
|
16
|
+
try{
|
|
17
|
+
if(message?.op==='backend.ack'){
|
|
18
|
+
const r=registrations.get(message.registrationId);if(!r)return;registrations.delete(message.registrationId);clearTimeout(r.timer);
|
|
19
|
+
if(!message.ok)r.reject(Error('BACKEND_REGISTRATION_REJECTED'));else {let released=false;r.resolve(()=>{if(released)return;released=true;process.send?.({op:'backend.close',registrationId:message.registrationId},()=>{});});}return;
|
|
20
|
+
}
|
|
21
|
+
if(message?.op==='init'){
|
|
22
|
+
if(agent)throw Error('ALREADY_INITIALIZED');
|
|
23
|
+
if(message.profileDirectory&&!message.relay)throw Error('PERSISTENT_PROFILE_REQUIRES_FIXED_RELAY');
|
|
24
|
+
agent=message.relay?await createPhoneSession({backendPort:message.backendPort,connectionMode:message.connectionMode??'auto',lanAddress:message.lanAddress,relay:message.relay,relayCa:message.relayCa,relayLeaf:message.relayLeaf,profileDirectory:message.profileDirectory,lanEnabled:message.lanEnabled===true,registerBackend,diagnostics:{record:event=>{if(process.connected)process.send?.({op:'diagnostic',event:{...event,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});}}}):await createPcAgent({backendPort:message.backendPort,registerBackend});
|
|
25
|
+
heartbeat=setInterval(()=>{if(process.connected)process.send?.({op:'diagnostic',event:{stage:'LOCAL',code:'COMPANION_HEARTBEAT',count:1,generation:Number.isInteger(message.diagnosticGeneration)?message.diagnosticGeneration:0}},()=>{});},30000);heartbeat.unref?.();
|
|
26
|
+
process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
|
|
27
|
+
}else if(message?.op==='status'&&agent)process.send?.({id:message.id,ok:true,status:{pid:process.pid,...agent.status()}});
|
|
28
|
+
else if(message?.op==='confirmReverseScan'&&agent?.confirmReverseScan){await agent.confirmReverseScan(message.qr);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
29
|
+
else if(message?.op==='pair/start'&&agent?.beginPairing){await agent.beginPairing();process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
30
|
+
else if(message?.op==='pair/cancel'&&agent?.cancelPairing){await agent.cancelPairing(message.sessionId);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
31
|
+
else if(message?.op==='revoke'&&agent?.revoke){await agent.revoke(message.target);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
32
|
+
else if(message?.op==='lan/settings'&&agent?.setLanEnabled){await agent.setLanEnabled(message.enabled);process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
33
|
+
else if(message?.op==='reconnect'&&agent?.reconnect){await agent.reconnect();process.send?.({id:message.id,ok:true,status:agent.status()});}
|
|
34
|
+
else if(message?.op==='stop')await finish();
|
|
35
|
+
}catch(error){const code=error?.code??error?.message;process.send?.({id:message?.id,ok:false,error:/^[A-Z_]{3,70}$/.test(code??'')?code:'AGENT_OPERATION_FAILED'});if(!agent)await finish();}
|
|
36
|
+
});
|
|
37
|
+
// Failed owners must not leave a child waiting forever before init.
|
|
38
|
+
setTimeout(()=>{if(!agent)finish();},10000).unref();
|