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.
Files changed (2) hide show
  1. package/dist/index.js +61 -1
  2. 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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squad-openclaw",
3
- "version": "2026.2.192",
3
+ "version": "2026.2.193",
4
4
  "description": "Entity registry, filesystem tools, and version management plugin for OpenClaw gateway",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",