ssh-client-wrapper 1.8.0 → 1.8.2

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 CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const debug = require("debug")("sshClientWrapper:fork");
3
3
  const debugVerbose = require("debug")("sshClientWrapper:fork_verbose");
4
+ const debugMasterVerbose = require("debug")("sshClientWrapper:fork_masterPty_verbose");
4
5
  const debugSendPty = require("debug")("sshClientWrapper:fork_sendpty");
5
6
  const { spawn } = require("node-pty");
6
7
 
@@ -53,7 +54,7 @@ function sshLoginCallback(output, ptyProcess, pw, ph) {
53
54
  function getMasterPty(hostInfo) {
54
55
  debug("fork pty for master connection");
55
56
  const ptyProcess = spawn(nodePtyOpt.shell, [], nodePtyOpt);
56
- ptyProcess.onData(buff2String.bind(null, debugVerbose));
57
+ ptyProcess.onData(buff2String.bind(null, debugMasterVerbose));
57
58
  ptyProcess.onData((data)=>{
58
59
  const output = data.toString();
59
60
  sshLoginCallback(output, ptyProcess, hostInfo.password, hostInfo.passphrase);
@@ -62,9 +63,10 @@ function getMasterPty(hostInfo) {
62
63
  }
63
64
 
64
65
  async function fork(hostInfo, cmd, args, outputCallback) {
65
- return new Promise((resolve, reject)=>{
66
+ let ptyProcess = null;
67
+ const p = new Promise((resolve, reject)=>{
66
68
  debug(`cmd=${cmd}: args=${args}`);
67
- const ptyProcess = spawn(cmd, args, nodePtyOpt);
69
+ ptyProcess = spawn(cmd, args, nodePtyOpt);
68
70
  ptyProcess.onData(buff2String.bind(null, debugVerbose));
69
71
  ptyProcess.onData((data)=>{
70
72
  const output = data.toString();
@@ -97,6 +99,8 @@ async function fork(hostInfo, cmd, args, outputCallback) {
97
99
  return reject(err);
98
100
  });
99
101
  });
102
+ p.pty = ptyProcess;
103
+ return p;
100
104
  }
101
105
  module.exports = {
102
106
  fork,
package/lib/sshExec.js CHANGED
@@ -64,6 +64,9 @@ async function canConnect(hostInfo, timeout = 60) {
64
64
  * @returns {boolean} - true if master session exists
65
65
  */
66
66
  async function existsMaster(hostInfo) {
67
+ const ac = new AbortController();
68
+ const signal = ac.signal;
69
+
67
70
  const args = getSshOption(hostInfo);
68
71
  args.push("-Ocheck");
69
72
 
@@ -72,16 +75,39 @@ async function existsMaster(hostInfo) {
72
75
  output += e;
73
76
  };
74
77
 
78
+ let rt = true; //if timeout occurred during ssh -Ocheck, it will turn to false
79
+ let p;
80
+ const timeout = hostInfo.ConnectTimeout || 60;
81
+ setTimeoutPromise(timeout * 1000, "neverUsedValue", { signal })
82
+ .then(()=>{
83
+ debug(`can not finish master session check within ${timeout} sec`);
84
+
85
+ if (p.pty) {
86
+ p.pty.kill();
87
+ }
88
+ rt = false;
89
+ })
90
+ .catch((err)=>{
91
+ if (err.name === "AbortError") {
92
+ debug("timeout was aborted because master session check has done");
93
+ } else {
94
+ throw err;
95
+ }
96
+ });
97
+
75
98
  try {
76
99
  debug(`check master session: ${sshCmd} ${args.join(" ")}`);
77
- await fork(hostInfo, sshCmd, args, cb);
100
+ p = fork(hostInfo, sshCmd, args, cb);
101
+ await p;
102
+ ac.abort();
78
103
  } catch (err) {
79
104
  if (err.rt !== 255) {
80
105
  debug("check master session failed", err);
81
106
  throw err;
82
107
  }
83
108
  }
84
- return !/Control socket connect.*: No such file or directory/.test(output);
109
+
110
+ return rt && !/Control socket connect.*: No such file or directory/.test(output);
85
111
  }
86
112
 
87
113
  /**
@@ -94,24 +120,33 @@ async function connect(hostInfo, timeout = 60) {
94
120
  return;
95
121
  }
96
122
  debug(`create master ssh session to ${hostInfo.host}`);
97
- const pty = getMasterPty(hostInfo);
98
- hostInfo.masterPty = pty;
123
+
124
+ if (!hostInfo.masterPty) {
125
+ debug(`create master pty for ${hostInfo.host}`);
126
+ hostInfo.masterPty = getMasterPty(hostInfo);
127
+ } else {
128
+ debug(`master pty for ${hostInfo.host} exists`);
129
+ }
99
130
 
100
131
  const ac = new AbortController();
101
132
  const signal = ac.signal;
102
133
  setTimeoutPromise(timeout * 1000, "neverUsedValue", { signal })
103
134
  .then(()=>{
135
+ debug(`can not connect within ${timeout} sec`);
136
+ hostInfo.masterPty.write("\n");
137
+ hostInfo.masterPty.write("exit\n");
138
+
104
139
  const err = new Error(`can not connect within ${timeout} sec`);
105
140
  err.host = hostInfo.host;
106
141
  err.user = hostInfo.user;
107
142
  err.port = hostInfo.port;
108
- pty.write("\n");
109
- pty.write("exit\n");
110
143
  throw err;
111
144
  })
112
145
  .catch((err)=>{
113
146
  if (err.name === "AbortError") {
114
147
  debug("timeout was aborted because connection check has done");
148
+ } else {
149
+ throw err;
115
150
  }
116
151
  });
117
152
 
@@ -119,8 +154,9 @@ async function connect(hostInfo, timeout = 60) {
119
154
  const re = new RegExp(`^${words}`);
120
155
  const p = new Promise((resolve, reject)=>{
121
156
  let done = false;
122
- pty.onData((data)=>{
157
+ hostInfo.masterPty.onData((data)=>{
123
158
  if (done) {
159
+ //safeguard
124
160
  return;
125
161
  }
126
162
  const output = data.toString();
@@ -128,7 +164,7 @@ async function connect(hostInfo, timeout = 60) {
128
164
 
129
165
  if (re.test(output)) {
130
166
  debug("test done. call exit on remotehost");
131
- pty.write("exit\n");
167
+ hostInfo.masterPty.write("exit\n");
132
168
  done = true;
133
169
  resolve();
134
170
  } else if (/Permission denied \(/.test(output)) {
@@ -141,7 +177,7 @@ async function connect(hostInfo, timeout = 60) {
141
177
  reject(new Error("Operation timed out"));
142
178
  }
143
179
  });
144
- pty.onExit((e)=>{
180
+ hostInfo.masterPty.onExit((e)=>{
145
181
  debug("master pty exit", e);
146
182
  resolve(e);
147
183
  });
@@ -151,7 +187,7 @@ async function connect(hostInfo, timeout = 60) {
151
187
  args.push(`echo ${words}`);
152
188
  const cmd = `${sshCmd} ${args.join(" ")}\n`;
153
189
  debugVerbose(cmd);
154
- pty.write(cmd);
190
+ hostInfo.masterPty.write(cmd);
155
191
  await p;
156
192
  ac.abort();
157
193
  debug(`connected to ${hostInfo.host}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh-client-wrapper",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
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.1",
38
+ "glob": "^10.3.3",
39
39
  "node-pty": "^0.10.1",
40
40
  "nyc": "^15.1.0",
41
41
  "promise-retry": "^2.0.1"