sweetspot-remote-agent 1.8.6 → 1.8.7

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/mcp-server.js +34 -12
  2. package/package.json +1 -1
package/mcp-server.js CHANGED
@@ -273,20 +273,34 @@ if (!isStdio && !noRegister && !regName) {
273
273
  process.exit(1);
274
274
  }
275
275
 
276
- // ── 토큰 자동 생성/저장 ──
276
+ // ── RSA 키페어 자동 생성/저장 ──
277
277
  import fs from "fs";
278
278
 
279
- const tokenFile = `${os.homedir()}/.sweetspot-token`;
279
+ const keypairFile = `${os.homedir()}/.sweetspot-keypair.json`;
280
280
 
281
- function loadOrCreateToken() {
282
- if (fs.existsSync(tokenFile)) return fs.readFileSync(tokenFile, "utf-8").trim();
283
- const token = crypto.randomUUID();
284
- fs.writeFileSync(tokenFile, token, "utf-8");
285
- return token;
281
+ function loadOrCreateKeypair() {
282
+ if (fs.existsSync(keypairFile)) {
283
+ const { privateKey, publicKey } = JSON.parse(fs.readFileSync(keypairFile, "utf-8"));
284
+ return { privateKey, publicKey };
285
+ }
286
+ const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
287
+ modulusLength: 2048,
288
+ publicKeyEncoding: { type: "spki", format: "pem" },
289
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
290
+ });
291
+ fs.writeFileSync(keypairFile, JSON.stringify({ privateKey, publicKey }), { mode: 0o600 });
292
+ console.error(`[remote-agent] RSA 키페어 생성 완료: ${keypairFile}`);
293
+ return { privateKey, publicKey };
294
+ }
295
+
296
+ function signChallenge(privateKey, name, timestamp) {
297
+ const payload = `${name}:${timestamp}`;
298
+ return crypto.sign("sha256", Buffer.from(payload), { key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING })
299
+ .toString("base64");
286
300
  }
287
301
 
288
302
  // ── WebSocket 클라이언트 (GCP 역방향 연결) ──
289
- async function connectWs(name, token) {
303
+ async function connectWs(name, keypair) {
290
304
  const { default: WebSocket } = await import("ws");
291
305
  const wsUrl = BOT_SERVER.replace(/^http/, "ws") + "/agent";
292
306
  let alive = true;
@@ -296,7 +310,15 @@ async function connectWs(name, token) {
296
310
  const ws = new WebSocket(wsUrl);
297
311
 
298
312
  ws.on("open", () => {
299
- ws.send(JSON.stringify({ type: "register", name, token }));
313
+ const timestamp = Date.now();
314
+ const signature = signChallenge(keypair.privateKey, name, timestamp);
315
+ ws.send(JSON.stringify({
316
+ type: "register",
317
+ name,
318
+ publicKey: keypair.publicKey,
319
+ timestamp,
320
+ signature,
321
+ }));
300
322
  console.error(`[remote-agent] GCP 서버에 연결 중... (${name})`);
301
323
  });
302
324
 
@@ -432,9 +454,9 @@ async function main() {
432
454
  console.error("[remote-agent] MCP 서버 시작 (stdio)");
433
455
  } else {
434
456
  // WebSocket 모드: GCP 역방향 연결 (ngrok 불필요)
435
- const token = loadOrCreateToken();
436
- console.error(`[remote-agent] 토큰 파일: ${tokenFile}`);
437
- await connectWs(regName, token);
457
+ const keypair = loadOrCreateKeypair();
458
+ console.error(`[remote-agent] RSA 키페어 파일: ${keypairFile}`);
459
+ await connectWs(regName, keypair);
438
460
  }
439
461
  }
440
462
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sweetspot-remote-agent",
3
- "version": "1.8.6",
3
+ "version": "1.8.7",
4
4
  "description": "Sweetspot 원격 제어 MCP 서버 — 스크린샷, 마우스/키보드, 앱 제어, 파일 탐색, 셸 실행",
5
5
  "type": "module",
6
6
  "main": "mcp-server.js",