ssh-client-wrapper 2.2.3 → 2.2.6

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/.dockerignore CHANGED
@@ -1 +1,2 @@
1
1
  node_modules
2
+ run_test_all.sh
package/.eslintrc.json CHANGED
@@ -1,163 +1,34 @@
1
1
  {
2
- "root": true,
3
- "extends": [
4
- "eslint"
5
- ],
6
- "plugins": [
7
- "node",
8
- "jsdoc"
9
- ],
10
2
  "env": {
11
- "node": true,
12
- "es6": true
3
+ "browser": true,
4
+ "commonjs": true,
5
+ "es2021": true
13
6
  },
14
- "rules": {
15
- "no-param-reassign": "warn",
16
- "arrow-parens": [
17
- "error",
18
- "always"
19
- ],
20
- "arrow-body-style": [
21
- "error",
22
- "always"
23
- ],
24
- "arrow-spacing": [
25
- "error",
26
- {
27
- "before": false,
28
- "after": false
29
- }
30
- ],
31
- "camelcase": [
32
- "error",
33
- {
34
- "properties": "never"
35
- }
36
- ],
37
- "eqeqeq": [
38
- "error",
39
- "always",
40
- {
41
- "null": "ignore"
42
- }
43
- ],
44
- "func-style": [
45
- "error",
46
- "declaration",
47
- {
48
- "allowArrowFunctions": true
49
- }
50
- ],
51
- "indent": [
52
- "error",
53
- 2,
54
- {
55
- "SwitchCase": 1
56
- }
57
- ],
58
- "lines-around-comment": [
59
- "error",
60
- {
61
- "beforeBlockComment": true,
62
- "beforeLineComment": false
63
- }
64
- ],
65
- "lines-between-class-members": [
66
- "error",
67
- "always",
68
- {
69
- "exceptAfterSingleLine": true
70
- }
71
- ],
72
- "newline-per-chained-call": "error",
73
- "no-use-before-define": [
74
- "error",
75
- {
76
- "functions": false
77
- }
78
- ],
79
- "no-warning-comments": "warn",
80
- "padded-blocks": [
81
- "error",
82
- "never"
83
- ],
84
- "padding-line-between-statements": [
85
- "error",
86
- {
87
- "blankLine": "any",
88
- "prev": [
89
- "const",
90
- "let",
91
- "var"
92
- ],
93
- "next": "*"
7
+ "extends": ["standard"],
8
+ "overrides": [
9
+ {
10
+ "env": {
11
+ "node": true
94
12
  },
95
- {
96
- "blankLine": "always",
97
- "prev": "*",
98
- "next": [
99
- "block-like",
100
- "class",
101
- "do",
102
- "for",
103
- "function",
104
- "multiline-block-like",
105
- "switch",
106
- "try",
107
- "while"
108
- ]
109
- },
110
- {
111
- "blankLine": "any",
112
- "prev": [
113
- "const",
114
- "let",
115
- "var",
116
- "for",
117
- "while",
118
- "do",
119
- "block-like",
120
- "multiline-block-like"
121
- ],
122
- "next": [
123
- "block-like",
124
- "do",
125
- "for",
126
- "multiline-block-like",
127
- "switch",
128
- "try",
129
- "while"
130
- ]
13
+ "files": [
14
+ ".eslintrc.{js,cjs}"
15
+ ],
16
+ "parserOptions": {
17
+ "sourceType": "script"
131
18
  }
132
- ],
133
- "spaced-comment": [
134
- "error",
135
- "never"
136
- ],
137
- "node/exports-style": [
138
- "error",
139
- "module.exports"
140
- ],
141
- "require-unicode-regexp": "off",
142
- "node/no-unsupported-features": [
19
+ }
20
+ ],
21
+ "parserOptions": {
22
+ "ecmaVersion": "latest"
23
+ },
24
+ "rules": {
25
+ "semi": [
143
26
  "error",
144
- {
145
- "version": 10
146
- }
147
- ],
148
- "jsdoc/require-hyphen-before-param-description": [
149
- "warn",
150
27
  "always"
151
28
  ],
152
- "jsdoc/newline-after-description": "off",
153
- "jsdoc/require-param-description": "warn",
154
- "jsdoc/require-param-name": "warn",
155
- "jsdoc/require-param-type": "warn",
156
- "jsdoc/require-jsdoc": "off",
157
- "jsdoc/require-param": "off",
158
- "jsdoc/require-returns": "off"
159
- },
160
- "parserOptions": {
161
- "ecmaVersion": 2018
29
+ "quotes": [
30
+ "error",
31
+ "double"
32
+ ]
162
33
  }
163
34
  }
package/Dockerfile CHANGED
@@ -1,9 +1,7 @@
1
1
  # syntax=docker/dockerfile:1
2
- FROM --platform=linux/amd64 node:hydrogen-bookworm-slim
3
- #FROM --platform=linux/amd64 node:hydrogen-bullseye-slim
4
- #FROM --platform=linux/amd64 node:hydrogen-buster-slim
2
+ FROM --platform=linux/amd64 node:20-bookworm-slim
5
3
 
6
- WORKDIR /work
4
+ WORKDIR /work/ssh-client-wrapper
7
5
  RUN apt-get update && apt -y install ssh rsync bzip2 python3 g++ build-essential
8
- COPY ./ ssh-client-wrapper
9
- RUN cd ssh-client-wrapper && npm install
6
+ COPY ./ ./
7
+ RUN npm install
@@ -0,0 +1,7 @@
1
+ # syntax=docker/dockerfile:1
2
+ FROM --platform=linux/amd64 node:20-bookworm-slim
3
+
4
+ WORKDIR /work/ssh-client-wrapper
5
+ RUN apt-get update && apt -y install ssh rsync bzip2 python3 g++ build-essential
6
+ COPY ./ ./
7
+ RUN npm install
@@ -0,0 +1,7 @@
1
+ # syntax=docker/dockerfile:1
2
+ FROM --platform=linux/amd64 node:20-bookworm-slim
3
+
4
+ WORKDIR /work/ssh-client-wrapper
5
+ RUN apt-get update && apt -y install ssh rsync bzip2 python3 g++ build-essential
6
+ COPY ./ ./
7
+ RUN npm install
package/README.md CHANGED
@@ -4,9 +4,3 @@
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/8f3c0ea00e755ae31081/maintainability)](https://codeclimate.com/github/so5/ssh-client-wrapper/maintainability)
5
5
  # ssh-client-wrapper
6
6
  open ssh client wrapper library for nodejs
7
-
8
-
9
- # how to test on local machine
10
- ```
11
- docker-compose up --build
12
- ```
@@ -1,9 +1,9 @@
1
1
  version: "3.8"
2
2
  services:
3
- test-bed:
3
+ testbed:
4
4
  image: naoso5/test-sshd
5
5
  ports:
6
- - 4000:22
6
+ - "4000:22"
7
7
  container_name: testbed
8
8
  tester:
9
9
  build:
@@ -14,4 +14,24 @@ services:
14
14
  TEST_PW: passw0rd
15
15
  TEST_HOST: testbed
16
16
  working_dir: /work/ssh-client-wrapper
17
- command: bash -c "mkdir /root/.ssh 2>/dev/null; npm run test"
17
+ command: bash -c "mkdir /root/.ssh 2>/dev/null; npm run mocha"
18
+ tester-bullseye:
19
+ build:
20
+ context: .
21
+ dockerfile: Dockerfile-bullseye
22
+ environment:
23
+ TEST_USER: testuser
24
+ TEST_PW: passw0rd
25
+ TEST_HOST: testbed
26
+ working_dir: /work/ssh-client-wrapper
27
+ command: bash -c "mkdir /root/.ssh 2>/dev/null; npm run mocha"
28
+ tester-buster:
29
+ build:
30
+ context: .
31
+ dockerfile: Dockerfile-buster
32
+ environment:
33
+ TEST_USER: testuser
34
+ TEST_PW: passw0rd
35
+ TEST_HOST: testbed
36
+ working_dir: /work/ssh-client-wrapper
37
+ command: bash -c "mkdir /root/.ssh 2>/dev/null; npm run mocha"
package/lib/fork.js CHANGED
@@ -11,8 +11,8 @@ const nodePtyOpt = {
11
11
  windowsHide: true
12
12
  };
13
13
 
14
- function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
15
- return new Promise((resolve, reject)=>{
14
+ function sshLoginCallback (output, ptyProcess, pw, ph, logger = debugSendPty) {
15
+ return new Promise((resolve, reject) => {
16
16
  if (reNewHostPrompt.test(output)) {
17
17
  sendPty(ptyProcess, "yes\n", logger, 17);
18
18
  resolve();
@@ -26,10 +26,10 @@ function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
26
26
  if (typeof pw === "function") {
27
27
  debug("call password callback function");
28
28
  pw()
29
- .then((v)=>{
29
+ .then((v) => {
30
30
  sendPty(ptyProcess, `${v}\n`, logger, 30);
31
31
  })
32
- .catch((e)=>{
32
+ .catch((e) => {
33
33
  reject(e);
34
34
  });
35
35
  resolve();
@@ -44,10 +44,10 @@ function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
44
44
  if (typeof ph === "function") {
45
45
  debug("call passphrase callback function");
46
46
  ph()
47
- .then((v)=>{
47
+ .then((v) => {
48
48
  sendPty(ptyProcess, `${v}\n`, logger, 45);
49
49
  })
50
- .catch((e)=>{
50
+ .catch((e) => {
51
51
  reject(e);
52
52
  });
53
53
  }
@@ -58,7 +58,7 @@ function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
58
58
  /**
59
59
  * create pty for master ssh session and store to hostInfo.masterPty
60
60
  */
61
- function createMasterPty(hostInfo) {
61
+ function createMasterPty (hostInfo) {
62
62
  debug("fork pty for master connection");
63
63
 
64
64
  if (hostInfo.masterPty) {
@@ -69,13 +69,13 @@ function createMasterPty(hostInfo) {
69
69
  hostInfo.masterPty = ptyProcess;
70
70
  }
71
71
 
72
- async function fork(hostInfo, cmd, args, timeout, outputCallback) {
73
- return new Promise((resolve, reject)=>{
72
+ async function fork (hostInfo, cmd, args, timeout, outputCallback) {
73
+ return new Promise((resolve, reject) => {
74
74
  debug(`cmd=${cmd}: args=${args}`);
75
75
  const ptyProcess = spawn(cmd, args, nodePtyOpt);
76
76
  let ac = null;
77
77
  if (timeout > 0) {
78
- ac = watchDogTimer(timeout, cmd, ()=>{
78
+ ac = watchDogTimer(timeout, cmd, () => {
79
79
  ptyProcess.kill();
80
80
  const err = new Error(`watchdog timer expired ${timeout}`);
81
81
  err.code = "TIMEEXPIRE";
@@ -85,7 +85,7 @@ async function fork(hostInfo, cmd, args, timeout, outputCallback) {
85
85
  ptyProcess.onData(buff2String.bind(null, debugVerbose));
86
86
 
87
87
  if (hostInfo !== null) {
88
- ptyProcess.onData(async (data)=>{
88
+ ptyProcess.onData(async (data) => {
89
89
  const output = data.toString();
90
90
  sshLoginCallback(output, ptyProcess, hostInfo.password, hostInfo.passphrase)
91
91
  .catch(reject);
@@ -102,7 +102,7 @@ async function fork(hostInfo, cmd, args, timeout, outputCallback) {
102
102
  if (typeof outputCallback === "function") {
103
103
  ptyProcess.onData(buff2String.bind(null, outputCallback));
104
104
  }
105
- ptyProcess.onExit(({ exitCode, signal })=>{
105
+ ptyProcess.onExit(({ exitCode, signal }) => {
106
106
  debug("onExit", exitCode, signal);
107
107
 
108
108
  if (ac !== null) {
package/lib/index.js CHANGED
@@ -32,7 +32,7 @@ const { isArrayOfString, sanityCheck } = require("./util.js");
32
32
  * @param {string[]} hostInfo.sshOpt - additional options for ssh
33
33
  */
34
34
 
35
- const logAndReject = (message)=>{
35
+ const logAndReject = (message) => {
36
36
  debug(message);
37
37
  return Promise.reject(new Error(message));
38
38
  };
@@ -42,11 +42,11 @@ const logAndReject = (message)=>{
42
42
  * @constructor
43
43
  */
44
44
  class SshClientWrapper {
45
- constructor(hostInfo) {
45
+ constructor (hostInfo) {
46
46
  debug("constructor called for", hostInfo.host);
47
47
  debugVerbose("hostInfo=", hostInfo);
48
- sanityCheck(hostInfo);
49
48
  this.hostInfo = { ...hostInfo };
49
+ sanityCheck(this.hostInfo);
50
50
  this.hostInfo.masterPty = null;
51
51
  this.hostInfo.rsyncVersion = null;
52
52
 
@@ -67,10 +67,8 @@ class SshClientWrapper {
67
67
  * @param {Integer} timeout - timeout in secconds
68
68
  * @param { Function } outputCallback - call back routine for output
69
69
  * @returns {Integer} - Return code of cmd.
70
- *
71
- * If stdout and stderr is array, last 5 line of stdout and stderr is stored in them.
72
70
  */
73
- async exec(cmd, timeout = 0, outputCallback = null) {
71
+ async exec (cmd, timeout = 0, outputCallback = null) {
74
72
  debug("exec called", cmd);
75
73
 
76
74
  if (typeof cmd !== "string" || cmd === "") {
@@ -79,7 +77,6 @@ class SshClientWrapper {
79
77
  return sshExec(this.hostInfo, cmd, timeout, outputCallback);
80
78
  }
81
79
 
82
-
83
80
  /**
84
81
  * execute ls command and return output
85
82
  * @param {string} target - file or directory path to watch
@@ -87,38 +84,11 @@ class SshClientWrapper {
87
84
  * @param {Integer} timeout - timeout in secconds
88
85
  * @returns {string[]} - output from ls
89
86
  */
90
- async ls(target, lsOpt = [], timeout = 0) {
87
+ async ls (target, lsOpt = [], timeout = 0) {
91
88
  debug("ls called", target, lsOpt);
92
89
  return ls(this.hostInfo, target, lsOpt, timeout);
93
90
  }
94
91
 
95
- /**
96
- * Execute command repeatedly until specified keyword is found in stdout and/or stderr.
97
- * @param {string} cmd - Cmdline which will be executed.
98
- * @param {RegExp} regexp - End condition.
99
- * @param {number} retryDelay - Duration between each try (in sec).
100
- * @param {number} maxRetry - Max retry count.
101
- * @returns {Integer} - Return code of cmd.
102
- */
103
- async watch(cmd, regexp, retryDelay = 3, maxRetry = null) {
104
- debug("watch called", cmd, regexp, retryDelay, maxRetry);
105
-
106
- if (typeof cmd !== "string") {
107
- return logAndReject("cmd must be string");
108
- }
109
- if (!(regexp instanceof RegExp)) {
110
- const err = new Error("illegal regexp specified");
111
- err.regexp = regexp;
112
- err.cmd = cmd;
113
- err.retryDelay = retryDelay;
114
- err.maxRetry = maxRetry;
115
- return Promise.reject(new Error("err"));
116
- }
117
- //not implemented yet !!!
118
- return this.exec(cmd, ()=>{
119
- });
120
- }
121
-
122
92
  /**
123
93
  * Send file or directory and its child to server.
124
94
  * @param {string[]} src - File or directory name which to be recieve.
@@ -127,13 +97,13 @@ class SshClientWrapper {
127
97
  * @param {Integer} timeout - timeout in secconds
128
98
  * @returns {Promise} - Resolved with undefined when file transfer is done.
129
99
  */
130
- async send(src, dst, opt = [], timeout = 0) {
100
+ async send (src, dst, opt = [], timeout = 0) {
131
101
  debug("send called", src, dst, opt);
132
102
 
133
103
  if (!isArrayOfString(src)) {
134
104
  return logAndReject("src must be array of string");
135
105
  }
136
- if (!src.some((e)=>{
106
+ if (!src.some((e) => {
137
107
  return e !== "";
138
108
  })) {
139
109
  return logAndReject("src must contain non-empty string");
@@ -158,13 +128,13 @@ class SshClientWrapper {
158
128
  * @param {Integer} timeout - timeout in secconds
159
129
  * @returns {Promise} - Resolved with undefined when file transfer is done.
160
130
  */
161
- async recv(src, dst, opt = [], timeout = 0) {
131
+ async recv (src, dst, opt = [], timeout = 0) {
162
132
  debug("recv called", src, dst, opt);
163
133
 
164
134
  if (!isArrayOfString(src)) {
165
135
  return logAndReject("src must be array of string");
166
136
  }
167
- if (!src.some((e)=>{
137
+ if (!src.some((e) => {
168
138
  return e !== "";
169
139
  })) {
170
140
  return logAndReject("src must contain non-empty string");
@@ -186,7 +156,7 @@ class SshClientWrapper {
186
156
  * @param {Integer} timeout - timeout in secconds
187
157
  * @returns {Promise} - Resolved with true on success, otherwise rejected with Error.
188
158
  */
189
- async canConnect(timeout = 60) {
159
+ async canConnect (timeout = 60) {
190
160
  debug("canConnect called with timeout=", timeout);
191
161
  debugVerbose("hostInfo=", this.hostInfo);
192
162
 
@@ -199,7 +169,7 @@ class SshClientWrapper {
199
169
  /**
200
170
  * Disconnect master session
201
171
  */
202
- async disconnect() {
172
+ async disconnect () {
203
173
  debug(`disconnect from ${this.hostInfo.host} called`);
204
174
  disconnect(this.hostInfo);
205
175
  }
package/lib/rsyncExec.js CHANGED
@@ -9,9 +9,9 @@ const { fork } = require("./fork.js");
9
9
 
10
10
  const { sshCmd, rsyncCmd, getSshOption } = require("./util.js");
11
11
 
12
- async function checkRsyncVersion(timeout) {
12
+ async function checkRsyncVersion (timeout) {
13
13
  const rt = {};
14
- await fork(null, rsyncCmd, ["--version"], timeout, (output)=>{
14
+ await fork(null, rsyncCmd, ["--version"], timeout, (output) => {
15
15
  const result = /^rsync *version *(\d+)\.(\d+)\.(\d+).*$/m.exec(output);
16
16
 
17
17
  if (result) {
@@ -33,13 +33,13 @@ async function checkRsyncVersion(timeout) {
33
33
  *
34
34
  * this function execute rsync -avv --copy-unsafe-links src rsync://[user@]host[:port]/dst
35
35
  */
36
- async function send(hostInfo, argSrc, dst, rsyncOpt, timeout) {
36
+ async function send (hostInfo, argSrc, dst, rsyncOpt, timeout) {
37
37
  await connect(hostInfo);
38
- const promises = await Promise.allSettled(argSrc.map((e)=>{
38
+ const promises = await Promise.allSettled(argSrc.map((e) => {
39
39
  return glob(e);
40
40
  }));
41
41
  const src = promises
42
- .map((e, i)=>{
42
+ .map((e, i) => {
43
43
  if (e.status !== "fulfilled") {
44
44
  return null;
45
45
  }
@@ -48,10 +48,10 @@ async function send(hostInfo, argSrc, dst, rsyncOpt, timeout) {
48
48
  }
49
49
  return e.value;
50
50
  })
51
- .filter((e)=>{
51
+ .filter((e) => {
52
52
  return e !== null;
53
53
  })
54
- .flatMap((e)=>{
54
+ .flatMap((e) => {
55
55
  return e;
56
56
  });
57
57
 
@@ -87,7 +87,7 @@ async function send(hostInfo, argSrc, dst, rsyncOpt, timeout) {
87
87
  * @param {Object} hostInfo - hostinfo object
88
88
  * @returns {boolean} - rsync command version is higher than 3.2.4 or not
89
89
  */
90
- async function isNewRsync(hostInfo) {
90
+ async function isNewRsync (hostInfo) {
91
91
  if (!hostInfo.rsyncVersion ||
92
92
  !Number.isInteger(hostInfo.rsyncVersion.major) ||
93
93
  !Number.isInteger(hostInfo.rsyncVersion.minor) ||
@@ -107,7 +107,7 @@ async function isNewRsync(hostInfo) {
107
107
  *
108
108
  * this function execute rsync -av --copy-unsafe-links rsync://[user@]host[:port]/src dst
109
109
  */
110
- async function recv(hostInfo, argSrc, dst, rsyncOpt, timeout) {
110
+ async function recv (hostInfo, argSrc, dst, rsyncOpt, timeout) {
111
111
  await connect(hostInfo);
112
112
  const src = `${hostInfo.host}:${argSrc.join(" ")}`;
113
113
  const sshArgs = getSshOption(hostInfo, true);