@sstar/embedlink_agent 0.1.0 → 0.2.0
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/server/grpc.js +14 -0
- package/dist/server/web.js +41 -19
- package/dist/ui/assets/index-BWR08YtC.js +375 -0
- package/dist/ui/assets/index-CCZ6chFx.css +32 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -7
- package/dist/ui/assets/index-BlnLVmbt.js +0 -374
- package/dist/ui/assets/index-xMbarYXA.css +0 -32
package/dist/server/grpc.js
CHANGED
|
@@ -1065,5 +1065,19 @@ export async function startGrpcServer(cfg, identity) {
|
|
|
1065
1065
|
};
|
|
1066
1066
|
tryBindPort(cfg.grpc.port);
|
|
1067
1067
|
});
|
|
1068
|
+
// @grpc/grpc-js 内部会为底层 Http2Server 注册多个 close 监听器(按服务/生命周期),
|
|
1069
|
+
// 在 Node 默认 maxListeners=10 时可能触发 MaxListenersExceededWarning。
|
|
1070
|
+
// 这里针对内部 Http2Server 提升阈值,避免误报“内存泄漏”告警。
|
|
1071
|
+
try {
|
|
1072
|
+
const http2Servers = server.http2Servers;
|
|
1073
|
+
if (http2Servers && typeof http2Servers.values === 'function') {
|
|
1074
|
+
for (const s of http2Servers.values()) {
|
|
1075
|
+
if (s && typeof s.setMaxListeners === 'function') {
|
|
1076
|
+
s.setMaxListeners(64);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
catch { }
|
|
1068
1082
|
return server;
|
|
1069
1083
|
}
|
package/dist/server/web.js
CHANGED
|
@@ -499,13 +499,41 @@ export async function startWebServer(cfg) {
|
|
|
499
499
|
reused: true,
|
|
500
500
|
});
|
|
501
501
|
}
|
|
502
|
+
// 先准备 SSH 鉴权材料(避免 probe 阶段因未加载私钥而误报认证失败)
|
|
503
|
+
const c = await ensureConfigLoaded();
|
|
504
|
+
const requestedPassword = typeof password === 'string' && password.trim() ? String(password) : undefined;
|
|
505
|
+
const enablePasswordFallback = c.ssh?.enablePasswordFallback !== false;
|
|
506
|
+
const effectivePassword = requestedPassword || (enablePasswordFallback ? sshPasswordSecret.value : undefined);
|
|
507
|
+
let privateKey = uploadedKeyMem;
|
|
508
|
+
if (keySource === 'default' && !privateKey) {
|
|
509
|
+
try {
|
|
510
|
+
if (c.ssh?.defaultKeyPath) {
|
|
511
|
+
privateKey = await fs.readFile(c.ssh.defaultKeyPath);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
catch (e) {
|
|
515
|
+
console.debug('Failed to read default SSH key:', e?.message || String(e));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// 无鉴权材料时直接报错,避免 ssh2 报 “All configured authentication methods failed”
|
|
519
|
+
if (!privateKey && !effectivePassword) {
|
|
520
|
+
return res.status(400).json({
|
|
521
|
+
error: 'missing ssh authentication (password/privateKey)',
|
|
522
|
+
code: 'EL_SSH_AUTH_MISSING',
|
|
523
|
+
suggestions: [
|
|
524
|
+
'请上传私钥或在配置中设置 ssh.defaultKeyPath',
|
|
525
|
+
'或在界面填写 password / 设置环境变量 SSH_PASSWORD',
|
|
526
|
+
],
|
|
527
|
+
});
|
|
528
|
+
}
|
|
502
529
|
// Probe existing mapping for this user+agent on remote; if active, refuse
|
|
503
530
|
const agentId = cfg.agentId || 'agent';
|
|
504
531
|
const probe = await probeRemoteExistingTunnel({
|
|
505
532
|
host,
|
|
506
533
|
sshPort: Number(port),
|
|
507
534
|
user,
|
|
508
|
-
password,
|
|
535
|
+
password: effectivePassword,
|
|
536
|
+
privateKey,
|
|
509
537
|
agentId,
|
|
510
538
|
});
|
|
511
539
|
if (probe.active && probe.port) {
|
|
@@ -522,19 +550,6 @@ export async function startWebServer(cfg) {
|
|
|
522
550
|
});
|
|
523
551
|
}
|
|
524
552
|
await cleanupTunnel('probe_existing_tunnel');
|
|
525
|
-
// 确保私钥已正确加载
|
|
526
|
-
let privateKey = uploadedKeyMem;
|
|
527
|
-
if (keySource === 'default' && !privateKey) {
|
|
528
|
-
try {
|
|
529
|
-
const c = await loadConfig();
|
|
530
|
-
if (c.ssh?.defaultKeyPath) {
|
|
531
|
-
privateKey = await fs.readFile(c.ssh.defaultKeyPath);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
catch (e) {
|
|
535
|
-
console.debug('Failed to read default SSH key:', e?.message || String(e));
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
553
|
// First try requested port, else fallback to username-hash mapping
|
|
539
554
|
const userName = os.userInfo().username || 'user';
|
|
540
555
|
const basePort = remotePort ? Number(remotePort) : hashPort(user);
|
|
@@ -554,7 +569,7 @@ export async function startWebServer(cfg) {
|
|
|
554
569
|
host,
|
|
555
570
|
port: Number(port),
|
|
556
571
|
user,
|
|
557
|
-
password:
|
|
572
|
+
password: effectivePassword,
|
|
558
573
|
privateKey,
|
|
559
574
|
bindAddr,
|
|
560
575
|
bindPort: Number(p),
|
|
@@ -575,7 +590,14 @@ export async function startWebServer(cfg) {
|
|
|
575
590
|
if (!bound)
|
|
576
591
|
throw new Error(portBindingError || 'bind failed');
|
|
577
592
|
lastRemotePort = bound;
|
|
578
|
-
lastParams = {
|
|
593
|
+
lastParams = {
|
|
594
|
+
host,
|
|
595
|
+
port: Number(port),
|
|
596
|
+
user,
|
|
597
|
+
password: effectivePassword,
|
|
598
|
+
bindAddr,
|
|
599
|
+
keySource,
|
|
600
|
+
};
|
|
579
601
|
// 添加清理监听器:在Server关闭时自动清理隧道
|
|
580
602
|
addTunnelCleanupListener(async () => {
|
|
581
603
|
await cleanupTunnel('server_shutdown');
|
|
@@ -2235,7 +2257,7 @@ async function writeRemoteAgentJson(tunnel, info) {
|
|
|
2235
2257
|
}
|
|
2236
2258
|
}
|
|
2237
2259
|
async function probeRemoteExistingTunnel(params) {
|
|
2238
|
-
const { host, sshPort, user, password } = params;
|
|
2260
|
+
const { host, sshPort, user, password, privateKey } = params;
|
|
2239
2261
|
const ssh2 = await import('ssh2');
|
|
2240
2262
|
const client = new ssh2.Client();
|
|
2241
2263
|
return await new Promise(async (resolve) => {
|
|
@@ -2271,7 +2293,7 @@ async function probeRemoteExistingTunnel(params) {
|
|
|
2271
2293
|
return finish({ active: false });
|
|
2272
2294
|
}
|
|
2273
2295
|
catch (e) {
|
|
2274
|
-
console.warn('Failed to probe remote agent.json:', e);
|
|
2296
|
+
console.warn('Failed to probe remote agent.json:', e?.message || String(e));
|
|
2275
2297
|
return finish({ active: false });
|
|
2276
2298
|
}
|
|
2277
2299
|
})
|
|
@@ -2279,6 +2301,6 @@ async function probeRemoteExistingTunnel(params) {
|
|
|
2279
2301
|
console.warn('Failed to probe remote agent.json:', err?.message || String(err));
|
|
2280
2302
|
return finish({ active: false });
|
|
2281
2303
|
})
|
|
2282
|
-
.connect({ host, port: sshPort, username: user, password });
|
|
2304
|
+
.connect({ host, port: sshPort, username: user, password, privateKey });
|
|
2283
2305
|
});
|
|
2284
2306
|
}
|