ssh-client-wrapper 2.1.1 → 2.2.1
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/lib/fork.js +44 -40
- package/lib/sshExec.js +18 -11
- package/lib/util.js +4 -1
- package/package.json +2 -2
package/lib/fork.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const debug = require("debug")("sshClientWrapper:debug:fork");
|
|
3
3
|
const debugVerbose = require("debug")("sshClientWrapper:verbose:fork");
|
|
4
|
-
const debugMasterVerbose = require("debug")("sshClientWrapper:insecure:fork_masterPty");
|
|
5
4
|
const debugSendPty = require("debug")("sshClientWrapper:insecure:fork_sendpty");
|
|
6
5
|
const { spawn } = require("node-pty");
|
|
7
6
|
|
|
@@ -13,45 +12,53 @@ const nodePtyOpt = {
|
|
|
13
12
|
};
|
|
14
13
|
|
|
15
14
|
function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (rePwPrompt.test(output)) {
|
|
21
|
-
if (typeof pw === "string") {
|
|
22
|
-
debug("use given password");
|
|
23
|
-
sendPty(ptyProcess, `${pw}\n`, logger, 23);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (typeof pw === "function") {
|
|
27
|
-
debug("call password callback function");
|
|
28
|
-
pw()
|
|
29
|
-
.then((v)=>{
|
|
30
|
-
sendPty(ptyProcess, `${v}\n`, logger, 30);
|
|
31
|
-
});
|
|
32
|
-
return;
|
|
15
|
+
return new Promise((resolve, reject)=>{
|
|
16
|
+
if (reNewHostPrompt.test(output)) {
|
|
17
|
+
sendPty(ptyProcess, "yes\n", logger, 17);
|
|
18
|
+
resolve();
|
|
33
19
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
20
|
+
if (rePwPrompt.test(output)) {
|
|
21
|
+
if (typeof pw === "string") {
|
|
22
|
+
debug("use given password");
|
|
23
|
+
sendPty(ptyProcess, `${pw}\n`, logger, 23);
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
if (typeof pw === "function") {
|
|
27
|
+
debug("call password callback function");
|
|
28
|
+
pw()
|
|
29
|
+
.then((v)=>{
|
|
30
|
+
sendPty(ptyProcess, `${v}\n`, logger, 30);
|
|
31
|
+
})
|
|
32
|
+
.catch((e)=>{
|
|
33
|
+
reject(e);
|
|
34
|
+
});
|
|
35
|
+
resolve();
|
|
36
|
+
}
|
|
40
37
|
}
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
if (rePhPrompt.test(output)) {
|
|
39
|
+
if (typeof ph === "string") {
|
|
40
|
+
debug("use given passphrase");
|
|
41
|
+
sendPty(ptyProcess, `${ph}\n`, logger, 38);
|
|
42
|
+
resolve();
|
|
43
|
+
}
|
|
44
|
+
if (typeof ph === "function") {
|
|
45
|
+
debug("call passphrase callback function");
|
|
46
|
+
ph()
|
|
47
|
+
.then((v)=>{
|
|
48
|
+
sendPty(ptyProcess, `${v}\n`, logger, 45);
|
|
49
|
+
})
|
|
50
|
+
.catch((e)=>{
|
|
51
|
+
reject(e);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
|
-
}
|
|
55
|
+
});
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
/**
|
|
52
59
|
* create pty for master ssh session and store to hostInfo.masterPty
|
|
53
60
|
*/
|
|
54
|
-
function
|
|
61
|
+
function createMasterPty(hostInfo) {
|
|
55
62
|
debug("fork pty for master connection");
|
|
56
63
|
|
|
57
64
|
if (hostInfo.masterPty) {
|
|
@@ -59,11 +66,6 @@ function getMasterPty(hostInfo, logger) {
|
|
|
59
66
|
hostInfo.masterPty.kill();
|
|
60
67
|
}
|
|
61
68
|
const ptyProcess = spawn(nodePtyOpt.shell, [], nodePtyOpt);
|
|
62
|
-
ptyProcess.onData(buff2String.bind(null, debugMasterVerbose));
|
|
63
|
-
ptyProcess.onData((data)=>{
|
|
64
|
-
const output = data.toString();
|
|
65
|
-
sshLoginCallback(output, ptyProcess, hostInfo.password, hostInfo.passphrase, logger);
|
|
66
|
-
});
|
|
67
69
|
hostInfo.masterPty = ptyProcess;
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -83,9 +85,10 @@ async function fork(hostInfo, cmd, args, timeout, outputCallback) {
|
|
|
83
85
|
ptyProcess.onData(buff2String.bind(null, debugVerbose));
|
|
84
86
|
|
|
85
87
|
if (hostInfo !== null) {
|
|
86
|
-
ptyProcess.onData((data)=>{
|
|
88
|
+
ptyProcess.onData(async (data)=>{
|
|
87
89
|
const output = data.toString();
|
|
88
|
-
sshLoginCallback(output, ptyProcess, hostInfo.password, hostInfo.passphrase)
|
|
90
|
+
sshLoginCallback(output, ptyProcess, hostInfo.password, hostInfo.passphrase)
|
|
91
|
+
.catch(reject);
|
|
89
92
|
|
|
90
93
|
if (/kex_exchange_identification: Connection closed by remote host/.test(output)) {
|
|
91
94
|
ptyProcess.kill();
|
|
@@ -122,5 +125,6 @@ async function fork(hostInfo, cmd, args, timeout, outputCallback) {
|
|
|
122
125
|
}
|
|
123
126
|
module.exports = {
|
|
124
127
|
fork,
|
|
125
|
-
|
|
128
|
+
createMasterPty,
|
|
129
|
+
sshLoginCallback
|
|
126
130
|
};
|
package/lib/sshExec.js
CHANGED
|
@@ -5,7 +5,7 @@ const debug = require("debug")("sshClientWrapper:debug:sshExec");
|
|
|
5
5
|
const debugVerbose = require("debug")("sshClientWrapper:verbose:sshExec");
|
|
6
6
|
const debugSendMasterPty = require("debug")("sshClientWrapper:insecure:sshExec_masterPty");
|
|
7
7
|
const { sendPty, sshCmd, getSshOption, sanityCheck, watchDogTimer } = require("./util.js");
|
|
8
|
-
const { fork,
|
|
8
|
+
const { fork, createMasterPty, sshLoginCallback } = require("./fork.js");
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Execute command on remote host.
|
|
@@ -15,6 +15,7 @@ const { fork, getMasterPty } = require("./fork.js");
|
|
|
15
15
|
* @param {Function} outputCallback - Callback routine for stdout and stderr.
|
|
16
16
|
*/
|
|
17
17
|
async function sshExec(hostInfo, cmd, timeout, outputCallback) {
|
|
18
|
+
debug("sshExec called");
|
|
18
19
|
await connect(hostInfo);
|
|
19
20
|
debug("exec", cmd, "on remote server");
|
|
20
21
|
const args = getSshOption(hostInfo, false);
|
|
@@ -46,16 +47,13 @@ async function sshExec(hostInfo, cmd, timeout, outputCallback) {
|
|
|
46
47
|
* @param {Integer} timeout - timeout in secconds
|
|
47
48
|
*/
|
|
48
49
|
async function canConnect(hostInfo, timeout = 60) {
|
|
49
|
-
debug("
|
|
50
|
+
debug("canConnect called");
|
|
50
51
|
sanityCheck(hostInfo);
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} finally {
|
|
57
|
-
await disconnect(hostInfo);
|
|
58
|
-
}
|
|
53
|
+
await connect(hostInfo, timeout);
|
|
54
|
+
await disconnect(hostInfo);
|
|
55
|
+
//if connection fail, Error is throwed.
|
|
56
|
+
//so, if we reach here, connection must be succeeded
|
|
59
57
|
return true;
|
|
60
58
|
}
|
|
61
59
|
|
|
@@ -97,16 +95,17 @@ async function existsMaster(hostInfo, argTimeout) {
|
|
|
97
95
|
* @param {Object} hostInfo - hostinfo object
|
|
98
96
|
*/
|
|
99
97
|
async function connect(hostInfo, timeout = 60) {
|
|
98
|
+
debug("connect called");
|
|
99
|
+
|
|
100
100
|
if (await existsMaster(hostInfo, timeout)) {
|
|
101
101
|
debugVerbose("master connection exists");
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
debug(`create master pty for ${hostInfo.host}`);
|
|
106
|
-
|
|
106
|
+
createMasterPty(hostInfo, debugSendMasterPty);
|
|
107
107
|
|
|
108
108
|
debug(`create master ssh session to ${hostInfo.host}`);
|
|
109
|
-
|
|
110
109
|
const words = crypto.randomUUID();
|
|
111
110
|
const re = new RegExp(`^${words}`);
|
|
112
111
|
|
|
@@ -146,6 +145,11 @@ async function connect(hostInfo, timeout = 60) {
|
|
|
146
145
|
reject(new Error("Operation timed out"));
|
|
147
146
|
}
|
|
148
147
|
});
|
|
148
|
+
hostInfo.masterPty.onData((data)=>{
|
|
149
|
+
const output = data.toString();
|
|
150
|
+
sshLoginCallback(output, hostInfo.masterPty, hostInfo.password, hostInfo.passphrase, debugSendMasterPty)
|
|
151
|
+
.catch(reject);
|
|
152
|
+
});
|
|
149
153
|
hostInfo.masterPty.onExit((e)=>{
|
|
150
154
|
debug("master pty exit", e);
|
|
151
155
|
resolve(e);
|
|
@@ -172,6 +176,8 @@ async function connect(hostInfo, timeout = 60) {
|
|
|
172
176
|
* @param {Object} hostInfo - hostinfo object
|
|
173
177
|
*/
|
|
174
178
|
async function disconnect(hostInfo) {
|
|
179
|
+
debug("disconnect called");
|
|
180
|
+
|
|
175
181
|
if (await existsMaster(hostInfo)) {
|
|
176
182
|
const args = getSshOption(hostInfo);
|
|
177
183
|
args.push("-Oexit");
|
|
@@ -213,6 +219,7 @@ async function disconnect(hostInfo) {
|
|
|
213
219
|
* @returns {string[]} - output from ls
|
|
214
220
|
*/
|
|
215
221
|
async function ls(hostInfo, target, lsOpt, timeout) {
|
|
222
|
+
debug("ls called");
|
|
216
223
|
const outputArray = [];
|
|
217
224
|
try {
|
|
218
225
|
await sshExec(hostInfo, `ls ${lsOpt.join(" ")} ${target}`, timeout, (data)=>{
|
package/lib/util.js
CHANGED
|
@@ -26,6 +26,8 @@ const buff2String = (func, data)=>{
|
|
|
26
26
|
* @param { Object} hostInfo - host information object defined in index.js
|
|
27
27
|
*/
|
|
28
28
|
const sanityCheck = (hostInfo)=>{
|
|
29
|
+
debug("sanityCheck called");
|
|
30
|
+
|
|
29
31
|
if (typeof hostInfo.host !== "string" || hostInfo.host === "") {
|
|
30
32
|
throw new Error("host must be non-empty string");
|
|
31
33
|
}
|
|
@@ -43,6 +45,7 @@ const sanityCheck = (hostInfo)=>{
|
|
|
43
45
|
* @param {boolean} withoutDestination - return except for hostname
|
|
44
46
|
*/
|
|
45
47
|
const getSshOption = (hostInfo, withoutDestination)=>{
|
|
48
|
+
debug("getSshOption called");
|
|
46
49
|
const args = [];
|
|
47
50
|
|
|
48
51
|
if (!withoutDestination) {
|
|
@@ -140,7 +143,7 @@ const watchDogTimer = (timeout, label, cb)=>{
|
|
|
140
143
|
})
|
|
141
144
|
.catch((err)=>{
|
|
142
145
|
if (err.name === "AbortError") {
|
|
143
|
-
debug(`timeout was aborted because ${label} has
|
|
146
|
+
debug(`timeout was aborted because ${label} has finished or canceled`);
|
|
144
147
|
} else {
|
|
145
148
|
throw err;
|
|
146
149
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh-client-wrapper",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "wrapper library for open ssh client and rsync",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ssh",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"debug": "^4.3.4",
|
|
38
|
-
"glob": "^10.3.
|
|
38
|
+
"glob": "^10.3.10",
|
|
39
39
|
"node-pty": "^0.10.1",
|
|
40
40
|
"nyc": "^15.1.0",
|
|
41
41
|
"promise-retry": "^2.0.1",
|