@sksoftofficial/ocduet 0.2.2 → 0.2.3
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/package.json +1 -1
- package/src/commands/relay.js +3 -1
- package/src/relay-client.js +3 -1
- package/src/relayer.js +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sksoftofficial/ocduet",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Duet for opencode: pair your phone with a local opencode TUI. Type on mobile, see it live on both screens. LAN-first, QR pairing, zero config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/relay.js
CHANGED
|
@@ -40,7 +40,9 @@ function registerOnce(url, desktopId, pubB64, sign, secret, certPem) {
|
|
|
40
40
|
return new Promise((resolve, reject) => {
|
|
41
41
|
const wsUrl = new URL("/desktop", url);
|
|
42
42
|
wsUrl.protocol = wsUrl.protocol === "http:" ? "ws:" : "wss:";
|
|
43
|
-
|
|
43
|
+
// pinned cert = the identity itself; hostname/SAN matching would always
|
|
44
|
+
// fail for a bare-IP relayer with a self-signed cert
|
|
45
|
+
const tlsOpts = certPem ? { ca: certPem, checkServerIdentity: () => undefined } : { rejectUnauthorized: false };
|
|
44
46
|
const ws = new WebSocket(wsUrl, { ...tlsOpts, handshakeTimeout: 10_000 });
|
|
45
47
|
const fail = (why) => { try { ws.close(); } catch {} reject(new Error(why)); };
|
|
46
48
|
const timer = setTimeout(() => fail("register timeout"), 12_000);
|
package/src/relay-client.js
CHANGED
|
@@ -33,7 +33,9 @@ export function readRelayConfig() {
|
|
|
33
33
|
// auth still comes from the ed25519 register signature — the pin kills
|
|
34
34
|
// silent MITM even without a domain.
|
|
35
35
|
export function relayTlsOpts(cfg) {
|
|
36
|
-
|
|
36
|
+
// when pinned, the exact cert IS the identity — skip hostname/SAN matching,
|
|
37
|
+
// which can never pass for a bare-IP host anyway
|
|
38
|
+
return cfg?.certPem ? { ca: cfg.certPem, checkServerIdentity: () => undefined } : { rejectUnauthorized: false };
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
const state = { linked: false, connected: false, url: null, desktopId: null, since: null, lastError: null, reconnects: 0 };
|
package/src/relayer.js
CHANGED
|
@@ -75,11 +75,17 @@ function ensureCert() {
|
|
|
75
75
|
return { cert: fs.readFileSync(certP), key: fs.readFileSync(keyP) };
|
|
76
76
|
}
|
|
77
77
|
fs.mkdirSync(relayerDir(), { recursive: true });
|
|
78
|
+
// cover every address the box might be reached on — desktops link by bare IP
|
|
79
|
+
const ips = [];
|
|
80
|
+
for (const addrs of Object.values(os.networkInterfaces())) {
|
|
81
|
+
for (const a of addrs || []) if (a.family === "IPv4" && !a.internal) ips.push(a.address);
|
|
82
|
+
}
|
|
83
|
+
const san = ["DNS:localhost", "IP:127.0.0.1", ...ips.map((ip) => `IP:${ip}`)];
|
|
78
84
|
const out = spawnSync("openssl", [
|
|
79
85
|
"req", "-x509", "-newkey", "ec", "-pkeyopt", "ec_paramgen_curve:prime256v1",
|
|
80
86
|
"-keyout", keyP, "-out", certP, "-days", "3650", "-nodes",
|
|
81
87
|
"-subj", "/CN=ocduet-relayer",
|
|
82
|
-
"-addext",
|
|
88
|
+
"-addext", `subjectAltName=${san.join(",")}`,
|
|
83
89
|
], { stdio: "ignore" });
|
|
84
90
|
if (out.status !== 0) throw new Error("openssl cert generation failed — is openssl installed?");
|
|
85
91
|
try { fs.chmodSync(keyP, 0o600); } catch {}
|