Skip to content

Commit c19a821

Browse files
Dimitar Markovmscdex
authored andcommitted
client: add support for environment variables when starting SFTP
Fixes: #1433 PR-URL: #1445
1 parent dd5510c commit c19a821

File tree

3 files changed

+78
-7
lines changed

3 files changed

+78
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ You can find more examples in the `examples` directory of this repository.
10281028

10291029
* **setNoDelay**([< _boolean_ >noDelay]) - _Client_ - Calls [`setNoDelay()`](https://nodejs.org/docs/latest/api/net.html#socketsetnodelaynodelay) on the underlying socket. Disabling Nagle's algorithm improves latency at the expense of lower throughput.
10301030

1031-
* **sftp**(< _function_ >callback) - _(void)_ - Starts an SFTP session. `callback` has 2 parameters: < _Error_ >err, < _SFTP_ >sftp. For methods available on `sftp`, see the [`SFTP` client documentation](https://github.com/mscdex/ssh2/blob/master/SFTP.md).
1031+
* **sftp**([< _object_ >env, ]< _function_ >callback) - _(void)_ - Starts an SFTP session. `env` is an environment to use when executing `sftp` methods. `callback` has 2 parameters: < _Error_ >err, < _SFTP_ >sftp. For methods available on `sftp`, see the [`SFTP` client documentation](https://github.com/mscdex/ssh2/blob/master/SFTP.md).
10321032

10331033
* **shell**([[< _mixed_ >window,] < _object_ >options]< _function_ >callback) - _(void)_ - Starts an interactive shell session on the server, with an optional `window` object containing pseudo-tty settings (see 'Pseudo-TTY settings'). If `window === false`, then no pseudo-tty is allocated. `options` supports the `x11` and `env` options as described in `exec()`. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream.
10341034

lib/client.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,17 +1552,22 @@ class Client extends EventEmitter {
15521552
return this;
15531553
}
15541554

1555-
sftp(cb) {
1555+
sftp(env, cb) {
15561556
if (!this._sock || !isWritable(this._sock))
15571557
throw new Error('Not connected');
15581558

1559+
if (typeof env === 'function') {
1560+
cb = env;
1561+
env = undefined;
1562+
}
1563+
15591564
openChannel(this, 'sftp', (err, sftp) => {
15601565
if (err) {
15611566
cb(err);
15621567
return;
15631568
}
15641569

1565-
reqSubsystem(sftp, 'sftp', (err, sftp_) => {
1570+
const reqSubsystemCb = (err, sftp_) => {
15661571
if (err) {
15671572
cb(err);
15681573
return;
@@ -1608,7 +1613,20 @@ class Client extends EventEmitter {
16081613
.on('close', onExit);
16091614

16101615
sftp._init();
1611-
});
1616+
};
1617+
1618+
if (typeof env === 'object' && env !== null) {
1619+
reqEnv(sftp, env, (err) => {
1620+
if (err) {
1621+
cb(err);
1622+
return;
1623+
}
1624+
1625+
reqSubsystem(sftp, 'sftp', reqSubsystemCb);
1626+
});
1627+
} else {
1628+
reqSubsystem(sftp, 'sftp', reqSubsystemCb);
1629+
}
16121630
});
16131631

16141632
return this;
@@ -1842,16 +1860,33 @@ function reqExec(chan, cmd, opts, cb) {
18421860
chan._client._protocol.exec(chan.outgoing.id, cmd, true);
18431861
}
18441862

1845-
function reqEnv(chan, env) {
1846-
if (chan.outgoing.state !== 'open')
1863+
function reqEnv(chan, env, cb) {
1864+
const wantReply = (typeof cb === 'function');
1865+
1866+
if (chan.outgoing.state !== 'open') {
1867+
if (wantReply)
1868+
cb(new Error('Channel is not open'));
18471869
return;
1870+
}
1871+
1872+
if (wantReply) {
1873+
chan._callbacks.push((had_err) => {
1874+
if (had_err) {
1875+
cb(had_err !== true
1876+
? had_err
1877+
: new Error('Unable to set environment'));
1878+
return;
1879+
}
1880+
cb();
1881+
});
1882+
}
18481883

18491884
const keys = Object.keys(env || {});
18501885

18511886
for (let i = 0; i < keys.length; ++i) {
18521887
const key = keys[i];
18531888
const val = env[key];
1854-
chan._client._protocol.env(chan.outgoing.id, key, val, false);
1889+
chan._client._protocol.env(chan.outgoing.id, key, val, wantReply);
18551890
}
18561891
}
18571892

test/test-sftp.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,42 @@ setup('WriteStream', mustCall((client, server) => {
755755
}));
756756
}
757757

758+
{
759+
const { client, server } = setup_(
760+
'SFTP client sets environment',
761+
{
762+
client: { username: 'foo', password: 'bar' },
763+
server: { hostKeys: [ fixture('ssh_host_rsa_key') ] },
764+
},
765+
);
766+
767+
const env = { SSH2NODETEST: 'foo' };
768+
769+
server.on('connection', mustCall((conn) => {
770+
conn.on('authentication', mustCall((ctx) => {
771+
ctx.accept();
772+
})).on('ready', mustCall(() => {
773+
conn.on('session', mustCall((accept, reject) => {
774+
accept().on('env', mustCall((accept, reject, info) => {
775+
accept && accept();
776+
assert(info.key === Object.keys(env)[0], 'Wrong env key');
777+
assert(info.val === Object.values(env)[0], 'Wrong env value');
778+
})).on('sftp', mustCall((accept, reject) => {
779+
accept();
780+
}));
781+
}));
782+
}));
783+
}));
784+
785+
client.on('ready', mustCall(() => {
786+
const timeout = setTimeout(mustNotCall(), 1000);
787+
client.sftp(env, mustCall((err, sftp) => {
788+
clearTimeout(timeout);
789+
assert(!err, `Unexpected exec error: ${err}`);
790+
client.end();
791+
}));
792+
}));
793+
}
758794

759795
// =============================================================================
760796
function setup(title, cb) {

0 commit comments

Comments
 (0)