agent-ssh-cli 0.1.2 → 0.1.3
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 +7 -1
- package/package.json +1 -1
- package/src/daemon-client.js +8 -28
- package/src/daemon-paths.js +0 -5
- package/src/ssh-daemon.js +1 -12
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/Node.js-%3E%3D18-339933?logo=node.js&logoColor=white" alt="Node.js >=18"></a>
|
|
13
13
|
<a href="https://www.npmjs.com/"><img src="https://img.shields.io/badge/npm-%3E%3D8-CB3837?logo=npm&logoColor=white" alt="npm >=8"></a>
|
|
14
14
|
<a href="https://github.com/sleepinginsummer/agent-ssh-cli"><img src="https://img.shields.io/badge/Windows-MacOS-0078D6?labelColor=0078D6&color=C0C0C0" alt="Windows/MacOS"></a>
|
|
15
|
-
<a href="https://github.com/sleepinginsummer/agent-ssh-cli/releases"><img src="https://img.shields.io/badge/release-v0.1.
|
|
15
|
+
<a href="https://github.com/sleepinginsummer/agent-ssh-cli/releases"><img src="https://img.shields.io/badge/release-v0.1.3-blue" alt="release v0.1.3"></a>
|
|
16
16
|
<a href="https://github.com/sleepinginsummer/agent-ssh-cli/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs welcome"></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
@@ -153,6 +153,12 @@ agentsshcli list
|
|
|
153
153
|
|
|
154
154
|
## 卸载和清理
|
|
155
155
|
|
|
156
|
+
更新到最新版:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm install -g agent-ssh-cli@latest
|
|
160
|
+
```
|
|
161
|
+
|
|
156
162
|
```bash
|
|
157
163
|
npm uninstall -g agent-ssh-cli
|
|
158
164
|
npm cache clean --force
|
package/package.json
CHANGED
package/src/daemon-client.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import crypto from "node:crypto";
|
|
3
|
-
import fs from "node:fs";
|
|
4
2
|
import net from "node:net";
|
|
5
3
|
import path from "node:path";
|
|
6
4
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { getSocketPath,
|
|
5
|
+
import { getSocketPath, unlinkSocketPath } from "./daemon-paths.js";
|
|
8
6
|
|
|
9
7
|
const DAEMON_START_TIMEOUT_MS = 3000;
|
|
10
8
|
const DAEMON_REQUEST_TIMEOUT_MS = 86400000;
|
|
@@ -41,19 +39,8 @@ function connectSocket(socketPath, timeoutMs = DAEMON_REQUEST_TIMEOUT_MS) {
|
|
|
41
39
|
});
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function createToken(tokenPath) {
|
|
49
|
-
const token = crypto.randomBytes(32).toString("hex");
|
|
50
|
-
fs.writeFileSync(tokenPath, token, { mode: 0o600 });
|
|
51
|
-
fs.chmodSync(tokenPath, 0o600);
|
|
52
|
-
return token;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function spawnDaemon(socketPath, configPath, tokenPath) {
|
|
56
|
-
const child = spawn(process.execPath, [getDaemonEntryPath(), "--socket", socketPath, "--config", path.resolve(configPath), "--token-file", tokenPath], {
|
|
42
|
+
function spawnDaemon(socketPath, configPath) {
|
|
43
|
+
const child = spawn(process.execPath, [getDaemonEntryPath(), "--socket", socketPath, "--config", path.resolve(configPath)], {
|
|
57
44
|
detached: true,
|
|
58
45
|
stdio: "ignore"
|
|
59
46
|
});
|
|
@@ -76,15 +63,11 @@ async function waitForDaemon(socketPath) {
|
|
|
76
63
|
throw new Error(`启动 SSH 缓存进程失败: ${lastError?.message || "未知错误"}`);
|
|
77
64
|
}
|
|
78
65
|
|
|
79
|
-
async function ensureDaemon(socketPath, configPath
|
|
66
|
+
async function ensureDaemon(socketPath, configPath) {
|
|
80
67
|
try {
|
|
81
68
|
const socket = await connectSocket(socketPath, 500);
|
|
82
69
|
socket.end();
|
|
83
|
-
|
|
84
|
-
return readToken(tokenPath);
|
|
85
|
-
} catch (error) {
|
|
86
|
-
unlinkSocketPath(socketPath);
|
|
87
|
-
}
|
|
70
|
+
return;
|
|
88
71
|
} catch (error) {
|
|
89
72
|
if (!isMissingSocketError(error)) {
|
|
90
73
|
throw error;
|
|
@@ -93,16 +76,13 @@ async function ensureDaemon(socketPath, configPath, tokenPath) {
|
|
|
93
76
|
unlinkSocketPath(socketPath);
|
|
94
77
|
}
|
|
95
78
|
}
|
|
96
|
-
|
|
97
|
-
spawnDaemon(socketPath, configPath, tokenPath);
|
|
79
|
+
spawnDaemon(socketPath, configPath);
|
|
98
80
|
await waitForDaemon(socketPath);
|
|
99
|
-
return token;
|
|
100
81
|
}
|
|
101
82
|
|
|
102
83
|
export async function requestDaemon(configPath, request) {
|
|
103
84
|
const socketPath = getSocketPath(configPath);
|
|
104
|
-
|
|
105
|
-
const token = await ensureDaemon(socketPath, configPath, tokenPath);
|
|
85
|
+
await ensureDaemon(socketPath, configPath);
|
|
106
86
|
const socket = await connectSocket(socketPath);
|
|
107
87
|
socket.setEncoding("utf8");
|
|
108
88
|
|
|
@@ -148,6 +128,6 @@ export async function requestDaemon(configPath, request) {
|
|
|
148
128
|
settle(reject, new Error("SSH 缓存进程提前关闭连接"));
|
|
149
129
|
}
|
|
150
130
|
});
|
|
151
|
-
socket.write(`${JSON.stringify(
|
|
131
|
+
socket.write(`${JSON.stringify(request)}\n`);
|
|
152
132
|
});
|
|
153
133
|
}
|
package/src/daemon-paths.js
CHANGED
|
@@ -29,11 +29,6 @@ export function getSocketPath(configPath) {
|
|
|
29
29
|
return path.join(getDaemonDir(), `${digest}.sock`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function getTokenPath(configPath) {
|
|
33
|
-
const digest = crypto.createHash("sha256").update(path.resolve(configPath)).digest("hex").slice(0, 24);
|
|
34
|
-
return path.join(getDaemonDir(), `${digest}.token`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
32
|
export function unlinkSocketPath(socketPath) {
|
|
38
33
|
if (isWindowsPlatform()) {
|
|
39
34
|
return;
|
package/src/ssh-daemon.js
CHANGED
|
@@ -20,28 +20,21 @@ let exitTimer;
|
|
|
20
20
|
let server;
|
|
21
21
|
let socketPath;
|
|
22
22
|
let boundConfigPath;
|
|
23
|
-
let daemonToken;
|
|
24
23
|
|
|
25
24
|
function parseArgs(argv) {
|
|
26
25
|
const socketIndex = argv.indexOf("--socket");
|
|
27
26
|
const configIndex = argv.indexOf("--config");
|
|
28
|
-
const tokenFileIndex = argv.indexOf("--token-file");
|
|
29
27
|
const parsedSocketPath = socketIndex === -1 ? undefined : argv[socketIndex + 1];
|
|
30
28
|
const configPath = configIndex === -1 ? undefined : argv[configIndex + 1];
|
|
31
|
-
const tokenFilePath = tokenFileIndex === -1 ? undefined : argv[tokenFileIndex + 1];
|
|
32
29
|
if (!parsedSocketPath) {
|
|
33
30
|
throw new Error("daemon 缺少 --socket 参数");
|
|
34
31
|
}
|
|
35
32
|
if (!configPath) {
|
|
36
33
|
throw new Error("daemon 缺少 --config 参数");
|
|
37
34
|
}
|
|
38
|
-
if (!tokenFilePath) {
|
|
39
|
-
throw new Error("daemon 缺少 --token-file 参数");
|
|
40
|
-
}
|
|
41
35
|
return {
|
|
42
36
|
socketPath: parsedSocketPath,
|
|
43
|
-
configPath: path.resolve(configPath)
|
|
44
|
-
tokenFilePath: path.resolve(tokenFilePath)
|
|
37
|
+
configPath: path.resolve(configPath)
|
|
45
38
|
};
|
|
46
39
|
}
|
|
47
40
|
|
|
@@ -156,9 +149,6 @@ async function runSerialized(entry, operation) {
|
|
|
156
149
|
}
|
|
157
150
|
|
|
158
151
|
async function executeRequest(request) {
|
|
159
|
-
if (request.token !== daemonToken) {
|
|
160
|
-
throw new Error("SSH 缓存进程认证失败");
|
|
161
|
-
}
|
|
162
152
|
const requestConfigPath = path.resolve(request.configPath);
|
|
163
153
|
if (requestConfigPath !== boundConfigPath) {
|
|
164
154
|
throw new Error("SSH 缓存进程拒绝访问非绑定配置文件");
|
|
@@ -246,7 +236,6 @@ try {
|
|
|
246
236
|
const parsedArgs = parseArgs(process.argv.slice(2));
|
|
247
237
|
socketPath = parsedArgs.socketPath;
|
|
248
238
|
boundConfigPath = parsedArgs.configPath;
|
|
249
|
-
daemonToken = fs.readFileSync(parsedArgs.tokenFilePath, "utf8").trim();
|
|
250
239
|
unlinkSocketPath(socketPath);
|
|
251
240
|
server = net.createServer(handleSocket);
|
|
252
241
|
server.listen(socketPath, () => {
|