squad-openclaw 2026.2.192 → 2026.2.193
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/dist/index.js +61 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -879,6 +879,7 @@ function registerVersionMethods(api) {
|
|
|
879
879
|
|
|
880
880
|
// src/relay-client.ts
|
|
881
881
|
import { WebSocket as NodeWebSocket } from "ws";
|
|
882
|
+
import crypto2 from "crypto";
|
|
882
883
|
import fs5 from "fs";
|
|
883
884
|
import path5 from "path";
|
|
884
885
|
import os from "os";
|
|
@@ -997,6 +998,51 @@ function deleteClaimToken() {
|
|
|
997
998
|
} catch {
|
|
998
999
|
}
|
|
999
1000
|
}
|
|
1001
|
+
function toBase64Url(buf) {
|
|
1002
|
+
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1003
|
+
}
|
|
1004
|
+
function loadOrCreateDeviceKeys() {
|
|
1005
|
+
const keysPath = path5.join(os.homedir(), ".squad", "relay-device-keys.json");
|
|
1006
|
+
try {
|
|
1007
|
+
const raw = fs5.readFileSync(keysPath, "utf-8");
|
|
1008
|
+
const keys2 = JSON.parse(raw);
|
|
1009
|
+
if (keys2.deviceId && keys2.publicKey && keys2.privateKey) {
|
|
1010
|
+
return keys2;
|
|
1011
|
+
}
|
|
1012
|
+
} catch {
|
|
1013
|
+
}
|
|
1014
|
+
const { publicKey, privateKey } = crypto2.generateKeyPairSync("ed25519");
|
|
1015
|
+
const pubDer = publicKey.export({ type: "spki", format: "der" });
|
|
1016
|
+
const privDer = privateKey.export({ type: "pkcs8", format: "der" });
|
|
1017
|
+
const rawPub = pubDer.subarray(pubDer.length - 32);
|
|
1018
|
+
const deviceId = crypto2.createHash("sha256").update(rawPub).digest("hex");
|
|
1019
|
+
const pubB64 = toBase64Url(rawPub);
|
|
1020
|
+
const privB64 = toBase64Url(privDer);
|
|
1021
|
+
const keys = { deviceId, publicKey: pubB64, privateKey: privB64 };
|
|
1022
|
+
const dir = path5.dirname(keysPath);
|
|
1023
|
+
if (!fs5.existsSync(dir)) {
|
|
1024
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
1025
|
+
}
|
|
1026
|
+
fs5.writeFileSync(keysPath, JSON.stringify(keys, null, 2), { mode: 384 });
|
|
1027
|
+
console.log(`[relay-client] Generated new device keys: ${deviceId.substring(0, 12)}...`);
|
|
1028
|
+
return keys;
|
|
1029
|
+
}
|
|
1030
|
+
function signDeviceIdentity(keys, clientId, clientMode, role, scopes, token) {
|
|
1031
|
+
const signedAtMs = Date.now();
|
|
1032
|
+
const nonce = crypto2.randomBytes(16).toString("hex");
|
|
1033
|
+
const scopeStr = scopes.join(",");
|
|
1034
|
+
const payload = `v2|${keys.deviceId}|${clientId}|${clientMode}|${role}|${scopeStr}|${signedAtMs}|${token ?? ""}|${nonce}`;
|
|
1035
|
+
const privDer = Buffer.from(keys.privateKey.replace(/-/g, "+").replace(/_/g, "/") + "==", "base64");
|
|
1036
|
+
const privateKey = crypto2.createPrivateKey({ key: privDer, format: "der", type: "pkcs8" });
|
|
1037
|
+
const signature = crypto2.sign(null, Buffer.from(payload), privateKey);
|
|
1038
|
+
return {
|
|
1039
|
+
id: keys.deviceId,
|
|
1040
|
+
publicKey: keys.publicKey,
|
|
1041
|
+
signature: toBase64Url(signature),
|
|
1042
|
+
signedAt: signedAtMs,
|
|
1043
|
+
nonce
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1000
1046
|
var RelayClient = class {
|
|
1001
1047
|
config;
|
|
1002
1048
|
relayWs = null;
|
|
@@ -1008,6 +1054,8 @@ var RelayClient = class {
|
|
|
1008
1054
|
destroyed = false;
|
|
1009
1055
|
/** Pending claim token — sent on first successful connect, then cleared */
|
|
1010
1056
|
pendingClaimToken = null;
|
|
1057
|
+
/** Device keys for authenticating local WS connections to the gateway */
|
|
1058
|
+
deviceKeys;
|
|
1011
1059
|
constructor(config) {
|
|
1012
1060
|
this.config = {
|
|
1013
1061
|
relayUrl: config.relayUrl,
|
|
@@ -1017,6 +1065,7 @@ var RelayClient = class {
|
|
|
1017
1065
|
claimToken: config.claimToken ?? null
|
|
1018
1066
|
};
|
|
1019
1067
|
this.pendingClaimToken = this.config.claimToken ?? readClaimToken();
|
|
1068
|
+
this.deviceKeys = loadOrCreateDeviceKeys();
|
|
1020
1069
|
}
|
|
1021
1070
|
/** Start connecting to the relay */
|
|
1022
1071
|
start() {
|
|
@@ -1155,8 +1204,19 @@ var RelayClient = class {
|
|
|
1155
1204
|
const params = msg.params ?? {};
|
|
1156
1205
|
if (this.config.operatorToken) {
|
|
1157
1206
|
params.auth = { token: this.config.operatorToken };
|
|
1158
|
-
msg.params = params;
|
|
1159
1207
|
}
|
|
1208
|
+
const client = params.client ?? {};
|
|
1209
|
+
const role = params.role ?? "operator";
|
|
1210
|
+
const scopes = params.scopes ?? [];
|
|
1211
|
+
params.device = signDeviceIdentity(
|
|
1212
|
+
this.deviceKeys,
|
|
1213
|
+
client.id ?? "cli",
|
|
1214
|
+
client.mode ?? "ui",
|
|
1215
|
+
role,
|
|
1216
|
+
scopes,
|
|
1217
|
+
this.config.operatorToken
|
|
1218
|
+
);
|
|
1219
|
+
msg.params = params;
|
|
1160
1220
|
conn.connectHandshakeComplete = false;
|
|
1161
1221
|
}
|
|
1162
1222
|
conn.localWs.send(JSON.stringify(msg));
|