@hyzyn/dsh-tty 0.10.2 → 0.11.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/README.md +19 -1
- package/client.js +40 -40
- package/lib/index.d.ts +11 -0
- package/lib/index.js +111 -1
- package/lib/index.js.map +1 -1
- package/lib/probe.d.ts +42 -0
- package/lib/probe.js +274 -0
- package/lib/probe.js.map +1 -0
- package/package.json +3 -3
package/lib/probe.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HostKeyStore, SshSpec } from './ssh.js';
|
|
2
|
+
/** TCP 预检超时(毫秒):DNS 解析 + 建连。 */
|
|
3
|
+
export declare const PROBE_TCP_TIMEOUT_MS = 6000;
|
|
4
|
+
/** ssh2 握手/认证阶段超时(毫秒);覆盖 buildConnectConfig 的 readyTimeout。 */
|
|
5
|
+
export declare const PROBE_AUTH_TIMEOUT_MS = 8000;
|
|
6
|
+
/** 分类结果载荷(HTTP 回传;字段全部可 JSON)。 */
|
|
7
|
+
export interface ProbeResult {
|
|
8
|
+
/** tcp 阶段:DNS 解析 + TCP 建连。 */
|
|
9
|
+
tcp: {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
ms?: number;
|
|
13
|
+
};
|
|
14
|
+
/** hostkey 阶段:TOFU 比对(未到握手时为 unknown)。 */
|
|
15
|
+
hostkey: {
|
|
16
|
+
state: 'unknown' | 'matched' | 'recorded' | 'mismatch';
|
|
17
|
+
/** 服务端 host key 的 sha256 指纹(hostHash:'sha256' 下 hostVerifier 收到的原样值)。 */
|
|
18
|
+
fingerprint: string;
|
|
19
|
+
/** 已记录指纹(mismatch 时展示对照)。 */
|
|
20
|
+
known?: string;
|
|
21
|
+
/** mismatch 时的完整指引文案(与 spawnSsh 一致)。 */
|
|
22
|
+
error?: string;
|
|
23
|
+
};
|
|
24
|
+
/** auth 阶段:认证是否通过(ready)。 */
|
|
25
|
+
auth: {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
error?: string;
|
|
28
|
+
ms?: number;
|
|
29
|
+
};
|
|
30
|
+
/** 总耗时。 */
|
|
31
|
+
totalMs: number;
|
|
32
|
+
}
|
|
33
|
+
/** 仅校验一份连接簿 / 对话框条目的形状(新增 / 编辑前先过一遍;不做网络请求)。 */
|
|
34
|
+
export declare function validateSshFields(input: Record<string, unknown>): {
|
|
35
|
+
spec?: SshSpec;
|
|
36
|
+
error?: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* 单次连接诊断。无论成败都会关闭连接、在超时内返回,绝不悬挂。
|
|
40
|
+
* 分类见文件头;tcp 预检通过后才进入 ssh2 握手。
|
|
41
|
+
*/
|
|
42
|
+
export declare function probeSsh(spec: SshSpec, store?: HostKeyStore): Promise<ProbeResult>;
|
package/lib/probe.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hyzyn/dsh-tty — SSH 连接测试(probe)模块。
|
|
3
|
+
*
|
|
4
|
+
* 「连接测试」按钮的数据源:不占会话名额、不开 shell channel,只做一次
|
|
5
|
+
* 链路诊断,把分段结果带回设置卡片 / SSH 连接对话框:
|
|
6
|
+
*
|
|
7
|
+
* 阶段 做法 判定
|
|
8
|
+
* tcp net.connect 预检(DNS + TCP 建连,6s 超时) → 主机可达 / DNS / 拒绝 / 超时
|
|
9
|
+
* hostkey ssh2 握手;hostVerifier 内做 TOFU 比对 → 已匹配 / 新指纹 / 不匹配拒绝
|
|
10
|
+
* auth ssh2 ready / error(认证被拒、协商超时等) → 认证通过或分类失败
|
|
11
|
+
*
|
|
12
|
+
* host key 两种策略(与隧道/SFTP 的 hostKeyStore 用法对齐):
|
|
13
|
+
* - 提供 store(设置卡片「测试」按钮):完整 TOFU——新指纹当场持久化
|
|
14
|
+
* record(测试即「首次连接」语义),不匹配拒绝并给出与 spawnSsh 完全
|
|
15
|
+
* 一致的指引文案(含已记录指纹与本次指纹,供对照);
|
|
16
|
+
* - 不提供 store(SSH 连接对话框试连,尚未保存/未必入库):只比对不
|
|
17
|
+
* 记录(避免给未保存的草稿建立钉扎),不匹配照样拒绝。
|
|
18
|
+
*
|
|
19
|
+
* 认证失败返回服务端标准错误消息原文(如 `All configured authentication
|
|
20
|
+
* methods failed`)不额外臆测——真实原因(密码错 / 用户不存在 / 方法未开)
|
|
21
|
+
* 由服务端决定,用户可据原文排查。
|
|
22
|
+
*/
|
|
23
|
+
import { Client } from 'ssh2';
|
|
24
|
+
import { connect as netConnect } from 'node:net';
|
|
25
|
+
import { buildConnectConfig, sshTarget } from './ssh.js';
|
|
26
|
+
/** TCP 预检超时(毫秒):DNS 解析 + 建连。 */
|
|
27
|
+
export const PROBE_TCP_TIMEOUT_MS = 6_000;
|
|
28
|
+
/** ssh2 握手/认证阶段超时(毫秒);覆盖 buildConnectConfig 的 readyTimeout。 */
|
|
29
|
+
export const PROBE_AUTH_TIMEOUT_MS = 8_000;
|
|
30
|
+
/** 把底层错误分类为人类可读诊断;原文保留在返回串里便于对照排查。 */
|
|
31
|
+
function classifyError(message) {
|
|
32
|
+
if (message === 'Host key verification failed') {
|
|
33
|
+
return '主机密钥校验失败(TOFU 不匹配,见 hostkey 指引)';
|
|
34
|
+
}
|
|
35
|
+
if (message.includes('All configured authentication methods failed')) {
|
|
36
|
+
return '认证被拒绝:所有认证方式均失败(用户名/密码/密钥是否正确,或服务端是否允许该认证方式)';
|
|
37
|
+
}
|
|
38
|
+
if (message.includes('Timed out')) {
|
|
39
|
+
return '超时:主机无响应或认证协商超时(检查地址 / 端口 / 防火墙 / 网络)';
|
|
40
|
+
}
|
|
41
|
+
const lower = message.toLowerCase();
|
|
42
|
+
if (lower.includes('econnrefused'))
|
|
43
|
+
return '连接被拒绝(ECONNREFUSED):端口未监听或服务未启动';
|
|
44
|
+
if (lower.includes('enetunreach'))
|
|
45
|
+
return '网络不可达(ENETUNREACH):路由不通或主机离线';
|
|
46
|
+
if (lower.includes('ehostunreach'))
|
|
47
|
+
return '主机不可达(EHOSTUNREACH)';
|
|
48
|
+
if (lower.includes('eai_again') || lower.includes('eai_noname') || lower.includes('enotfound'))
|
|
49
|
+
return 'DNS 解析失败:主机名无法解析';
|
|
50
|
+
if (lower.includes('getaddrinfo'))
|
|
51
|
+
return 'DNS 解析失败:主机名无法解析';
|
|
52
|
+
if (lower.includes('unable to exchange encryption keys') || lower.includes('encryption') || lower.includes('kex')) {
|
|
53
|
+
return '密钥交换失败:服务端可能不是 SSH 服务,或加密算法不兼容';
|
|
54
|
+
}
|
|
55
|
+
if (lower.includes('keepalive'))
|
|
56
|
+
return '连接保活超时(keepalive)';
|
|
57
|
+
if (lower.includes('protocol'))
|
|
58
|
+
return '协议错误:' + message;
|
|
59
|
+
return message;
|
|
60
|
+
}
|
|
61
|
+
/** 与 spawnSsh 的 applyHostKeyPolicy 一致的 TOFU 指引文案。 */
|
|
62
|
+
function mismatchMessage(target, host, port, known, current) {
|
|
63
|
+
return (`SSH 主机密钥指纹变更:${target} 已记录 sha256:${known},本次为 sha256:${current}。` +
|
|
64
|
+
'可能是主机重装或换钥匙,也可能是中间人(MITM)冒充;确认安全后,到 设置 → 插件 → 终端面板 → SSH 主机密钥记录 删除该主机再重连。');
|
|
65
|
+
}
|
|
66
|
+
/** 收集 hostVerifier 收到的指纹(ssh2 可能对多 host key 调用多次,取最后一次)。 */
|
|
67
|
+
function makeHostKeyVerifier(options) {
|
|
68
|
+
const { spec, store, onResult } = options;
|
|
69
|
+
const port = spec.port ?? 22;
|
|
70
|
+
const target = sshTarget(spec);
|
|
71
|
+
let seen = '';
|
|
72
|
+
return (hash) => {
|
|
73
|
+
seen = hash;
|
|
74
|
+
const known = store?.get(spec.host, port);
|
|
75
|
+
if (known === undefined) {
|
|
76
|
+
if (store !== undefined) {
|
|
77
|
+
// 完整 TOFU:新指纹当场持久化(与 spawnSsh 的 hostVerifier 同语义)
|
|
78
|
+
store.record(spec.host, port, hash);
|
|
79
|
+
onResult({ state: 'recorded', fingerprint: hash });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// 试连(对话框):只比对不落盘
|
|
83
|
+
onResult({ state: 'matched', fingerprint: hash });
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
if (known === hash) {
|
|
88
|
+
onResult({ state: 'matched', fingerprint: hash, known });
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
onResult({ state: 'mismatch', fingerprint: hash, known, error: mismatchMessage(target, spec.host, port, known, hash) });
|
|
92
|
+
return false;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** 仅校验一份连接簿 / 对话框条目的形状(新增 / 编辑前先过一遍;不做网络请求)。 */
|
|
96
|
+
export function validateSshFields(input) {
|
|
97
|
+
const host = typeof input.host === 'string' ? input.host.trim() : '';
|
|
98
|
+
const username = typeof input.username === 'string' ? input.username.trim() : '';
|
|
99
|
+
if (host === '')
|
|
100
|
+
return { error: '主机必填' };
|
|
101
|
+
if (username === '')
|
|
102
|
+
return { error: '用户名必填' };
|
|
103
|
+
let port = 22;
|
|
104
|
+
if (input.port !== undefined && input.port !== '') {
|
|
105
|
+
const value = Number(input.port);
|
|
106
|
+
if (!Number.isInteger(value) || value < 1 || value > 65535)
|
|
107
|
+
return { error: '端口必须是 1~65535 的整数' };
|
|
108
|
+
port = value;
|
|
109
|
+
}
|
|
110
|
+
const auth = input.auth === 'key' || input.auth === 'password' ? input.auth : 'agent';
|
|
111
|
+
const spec = { host, port, username, auth };
|
|
112
|
+
if (auth === 'key') {
|
|
113
|
+
const keyPath = typeof input.keyPath === 'string' ? input.keyPath.trim() : '';
|
|
114
|
+
if (keyPath === '')
|
|
115
|
+
return { error: 'auth=key 需要私钥路径' };
|
|
116
|
+
spec.keyPath = keyPath;
|
|
117
|
+
const passphrase = typeof input.passphrase === 'string' ? input.passphrase : '';
|
|
118
|
+
if (passphrase !== '')
|
|
119
|
+
spec.passphrase = passphrase;
|
|
120
|
+
}
|
|
121
|
+
if (auth === 'password') {
|
|
122
|
+
const password = typeof input.password === 'string' ? input.password : '';
|
|
123
|
+
if (password === '')
|
|
124
|
+
return { error: 'auth=password 需要密码' };
|
|
125
|
+
spec.password = password;
|
|
126
|
+
}
|
|
127
|
+
if (input.agentForward === true)
|
|
128
|
+
spec.agentForward = true;
|
|
129
|
+
return { spec };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 单次连接诊断。无论成败都会关闭连接、在超时内返回,绝不悬挂。
|
|
133
|
+
* 分类见文件头;tcp 预检通过后才进入 ssh2 握手。
|
|
134
|
+
*/
|
|
135
|
+
export async function probeSsh(spec, store) {
|
|
136
|
+
const startedAt = Date.now();
|
|
137
|
+
const result = {
|
|
138
|
+
tcp: { ok: false },
|
|
139
|
+
hostkey: { state: 'unknown', fingerprint: '' },
|
|
140
|
+
auth: { ok: false },
|
|
141
|
+
totalMs: 0,
|
|
142
|
+
};
|
|
143
|
+
const finish = () => {
|
|
144
|
+
result.totalMs = Date.now() - startedAt;
|
|
145
|
+
return result;
|
|
146
|
+
};
|
|
147
|
+
const port = spec.port ?? 22;
|
|
148
|
+
const target = sshTarget(spec);
|
|
149
|
+
// ---- 阶段 1:agent 预检(与 spawnSsh 同款,快速失败) ----
|
|
150
|
+
if (spec.auth === 'agent' && (process.env.SSH_AUTH_SOCK === undefined || process.env.SSH_AUTH_SOCK === '')) {
|
|
151
|
+
const message = 'agent 认证需要 SSH_AUTH_SOCK(本机未运行 ssh-agent 或变量未设置)';
|
|
152
|
+
result.tcp = { ok: false, error: message, ms: 0 };
|
|
153
|
+
result.auth = { ok: false, error: message };
|
|
154
|
+
return finish();
|
|
155
|
+
}
|
|
156
|
+
// ---- 阶段 1:TCP 预检(DNS + 建连) ----
|
|
157
|
+
const tcpResult = await new Promise((resolve) => {
|
|
158
|
+
const sock = netConnect({ host: spec.host, port });
|
|
159
|
+
const tcpStart = Date.now();
|
|
160
|
+
const done = (ok, error) => {
|
|
161
|
+
try {
|
|
162
|
+
sock.destroy();
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* 已关闭 */
|
|
166
|
+
}
|
|
167
|
+
resolve({ ok, error, ms: Date.now() - tcpStart });
|
|
168
|
+
};
|
|
169
|
+
sock.setTimeout(PROBE_TCP_TIMEOUT_MS, () => {
|
|
170
|
+
done(false, 'TCP 连接超时:主机无响应(检查地址 / 防火墙 / 网络)');
|
|
171
|
+
});
|
|
172
|
+
sock.once('connect', () => done(true));
|
|
173
|
+
sock.once('error', (error) => {
|
|
174
|
+
done(false, classifyError(error.message));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
result.tcp = tcpResult;
|
|
178
|
+
if (!tcpResult.ok) {
|
|
179
|
+
result.auth = { ok: false, error: tcpResult.error };
|
|
180
|
+
return finish();
|
|
181
|
+
}
|
|
182
|
+
// ---- 阶段 2+3:ssh2 握手(host key 交换 + 认证) ----
|
|
183
|
+
let connectConfig;
|
|
184
|
+
try {
|
|
185
|
+
connectConfig = buildConnectConfig(spec);
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
189
|
+
result.auth = { ok: false, error: classifyError(message) };
|
|
190
|
+
return finish();
|
|
191
|
+
}
|
|
192
|
+
// 探针专属更短握手超时(buildConnectConfig 默认 20s 对测试太长)
|
|
193
|
+
connectConfig.readyTimeout = PROBE_AUTH_TIMEOUT_MS;
|
|
194
|
+
const password = spec.auth === 'password' ? connectConfig.password ?? '' : '';
|
|
195
|
+
const tryKeyboard = connectConfig.tryKeyboard === true;
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
let settled = false;
|
|
198
|
+
let seenHostKey = false;
|
|
199
|
+
let hostkeyState = { state: 'unknown', fingerprint: '' };
|
|
200
|
+
const settle = () => {
|
|
201
|
+
if (settled)
|
|
202
|
+
return;
|
|
203
|
+
settled = true;
|
|
204
|
+
clearTimeout(timer);
|
|
205
|
+
try {
|
|
206
|
+
conn.end();
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
/* 已断开 */
|
|
210
|
+
}
|
|
211
|
+
resolve(finish());
|
|
212
|
+
};
|
|
213
|
+
// hostVerifier 的 onResult 同步回调:把结论收集到 hostkeyState
|
|
214
|
+
connectConfig.hostVerifier = makeHostKeyVerifier({
|
|
215
|
+
spec,
|
|
216
|
+
store,
|
|
217
|
+
onResult: (next) => {
|
|
218
|
+
seenHostKey = true;
|
|
219
|
+
hostkeyState = { ...next, error: next.error };
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
// password 认证挂 keyboard-interactive 自动应答(同 spawnSsh/tunnels/sftp)
|
|
223
|
+
const conn = new Client();
|
|
224
|
+
if (tryKeyboard) {
|
|
225
|
+
conn.on('keyboard-interactive', (_name, _instructions, _lang, _prompts, finishKb) => {
|
|
226
|
+
finishKb([password]);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const authStart = Date.now();
|
|
230
|
+
const timer = setTimeout(() => {
|
|
231
|
+
if (seenHostKey) {
|
|
232
|
+
result.hostkey = hostkeyState;
|
|
233
|
+
result.auth = { ok: false, error: '认证/协商超时(服务端在 8s 内未完成认证)', ms: Date.now() - authStart };
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
result.auth = { ok: false, error: '握手超时(服务端未在 8s 内完成密钥交换)', ms: Date.now() - authStart };
|
|
237
|
+
}
|
|
238
|
+
settle();
|
|
239
|
+
}, PROBE_AUTH_TIMEOUT_MS + 1000);
|
|
240
|
+
timer.unref?.();
|
|
241
|
+
conn.on('ready', () => {
|
|
242
|
+
result.hostkey = hostkeyState;
|
|
243
|
+
result.auth = { ok: true, ms: Date.now() - authStart };
|
|
244
|
+
settle();
|
|
245
|
+
});
|
|
246
|
+
conn.on('error', (error) => {
|
|
247
|
+
const classified = classifyError(error.message);
|
|
248
|
+
if (error.message === 'Host key verification failed' && hostkeyState.state === 'mismatch') {
|
|
249
|
+
result.hostkey = hostkeyState;
|
|
250
|
+
result.auth = { ok: false, error: '主机密钥校验失败(见 hostkey 指引)', ms: Date.now() - authStart };
|
|
251
|
+
settle();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
result.hostkey = seenHostKey ? hostkeyState : { state: 'unknown', fingerprint: '' };
|
|
255
|
+
// TCP 已通:这里只可能是协商 / 认证 / 协议层错误
|
|
256
|
+
result.auth = { ok: false, error: classified, ms: Date.now() - authStart };
|
|
257
|
+
settle();
|
|
258
|
+
});
|
|
259
|
+
conn.on('close', () => {
|
|
260
|
+
// 正常路径(ready / error / 超时)已 settle;未 settle 的 close 兜底
|
|
261
|
+
result.auth = { ok: false, error: '连接已关闭(服务端主动断开)', ms: Date.now() - authStart };
|
|
262
|
+
settle();
|
|
263
|
+
});
|
|
264
|
+
try {
|
|
265
|
+
conn.connect(connectConfig);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
269
|
+
result.auth = { ok: false, error: classifyError(message), ms: Date.now() - authStart };
|
|
270
|
+
settle();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=probe.js.map
|
package/lib/probe.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyzyn/dsh-tty",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "DSH Web GUI 的终端面板插件:侧边栏「终端」大弹窗,xterm.js + PTY 全交互终端(路线1),ssh2 原生 SSH 远程连接(方案 C),tmux 会话持久化(0.10.0)。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
45
|
+
"@hyzyn/dsh-kit": "0.1.2",
|
|
45
46
|
"@xterm/headless": "^5.5.0",
|
|
46
47
|
"ssh2": "^1.17.0",
|
|
47
|
-
"ws": "^8.18.0"
|
|
48
|
-
"@hyzyn/dsh-kit": "0.1.2"
|
|
48
|
+
"ws": "^8.18.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1"
|