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.
- package/mcp-server.js +34 -12
- 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
|
|
279
|
+
const keypairFile = `${os.homedir()}/.sweetspot-keypair.json`;
|
|
280
280
|
|
|
281
|
-
function
|
|
282
|
-
if (fs.existsSync(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
436
|
-
console.error(`[remote-agent]
|
|
437
|
-
await connectWs(regName,
|
|
457
|
+
const keypair = loadOrCreateKeypair();
|
|
458
|
+
console.error(`[remote-agent] RSA 키페어 파일: ${keypairFile}`);
|
|
459
|
+
await connectWs(regName, keypair);
|
|
438
460
|
}
|
|
439
461
|
}
|
|
440
462
|
|