Coder Social home page Coder Social logo

ssh2's Introduction

Description

SSH2 client and server modules written in pure JavaScript for node.js.

Development/testing is done against OpenSSH (8.7 currently).

Changes (breaking or otherwise) in v1.0.0 can be found here.

Table of Contents

Requirements

  • node.js -- v10.16.0 or newer
    • node v12.0.0 or newer for Ed25519 key support
  • (Optional) cpu-features is set as an optional package dependency (you do not need to install it explicitly/separately from ssh2) that will be automatically built and used if possible. See the project's documentation for its own requirements.
    • This addon is currently used to help generate an optimal default cipher list

Installation

npm install ssh2

Client Examples

Execute 'uptime' on a server

const { readFileSync } = require('fs');

const { Client } = require('ssh2');

const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  conn.exec('uptime', (err, stream) => {
    if (err) throw err;
    stream.on('close', (code, signal) => {
      console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
      conn.end();
    }).on('data', (data) => {
      console.log('STDOUT: ' + data);
    }).stderr.on('data', (data) => {
      console.log('STDERR: ' + data);
    });
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  privateKey: readFileSync('/path/to/my/key')
});

// example output:
// Client :: ready
// STDOUT:  17:41:15 up 22 days, 18:09,  1 user,  load average: 0.00, 0.01, 0.05
//
// Stream :: exit :: code: 0, signal: undefined
// Stream :: close

Start an interactive shell session

const { readFileSync } = require('fs');

const { Client } = require('ssh2');

const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  conn.shell((err, stream) => {
    if (err) throw err;
    stream.on('close', () => {
      console.log('Stream :: close');
      conn.end();
    }).on('data', (data) => {
      console.log('OUTPUT: ' + data);
    });
    stream.end('ls -l\nexit\n');
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  privateKey: readFileSync('/path/to/my/key')
});

// example output:
// Client :: ready
// STDOUT: Last login: Sun Jun 15 09:37:21 2014 from 192.168.100.100
//
// STDOUT: ls -l
// exit
//
// STDOUT: frylock@athf:~$ ls -l
//
// STDOUT: total 8
//
// STDOUT: drwxr-xr-x 2 frylock frylock 4096 Nov 18  2012 mydir
//
// STDOUT: -rw-r--r-- 1 frylock frylock   25 Apr 11  2013 test.txt
//
// STDOUT: frylock@athf:~$ exit
//
// STDOUT: logout
//
// Stream :: close

Send a raw HTTP request to port 80 on the server

const { Client } = require('ssh2');

const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  conn.forwardOut('192.168.100.102', 8000, '127.0.0.1', 80, (err, stream) => {
    if (err) throw err;
    stream.on('close', () => {
      console.log('TCP :: CLOSED');
      conn.end();
    }).on('data', (data) => {
      console.log('TCP :: DATA: ' + data);
    }).end([
      'HEAD / HTTP/1.1',
      'User-Agent: curl/7.27.0',
      'Host: 127.0.0.1',
      'Accept: */*',
      'Connection: close',
      '',
      ''
    ].join('\r\n'));
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  password: 'nodejsrules'
});

// example output:
// Client :: ready
// TCP :: DATA: HTTP/1.1 200 OK
// Date: Thu, 15 Nov 2012 13:52:58 GMT
// Server: Apache/2.2.22 (Ubuntu)
// X-Powered-By: PHP/5.4.6-1ubuntu1
// Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT
// Content-Encoding: gzip
// Vary: Accept-Encoding
// Connection: close
// Content-Type: text/html; charset=UTF-8
//
//
// TCP :: CLOSED

Forward local connections to port 8000 on the server to us

const { Client } = require('ssh2');

const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  conn.forwardIn('127.0.0.1', 8000, (err) => {
    if (err) throw err;
    console.log('Listening for connections on server on port 8000!');
  });
}).on('tcp connection', (info, accept, reject) => {
  console.log('TCP :: INCOMING CONNECTION:');
  console.dir(info);
  accept().on('close', () => {
    console.log('TCP :: CLOSED');
  }).on('data', (data) => {
    console.log('TCP :: DATA: ' + data);
  }).end([
    'HTTP/1.1 404 Not Found',
    'Date: Thu, 15 Nov 2012 02:07:58 GMT',
    'Server: ForwardedConnection',
    'Content-Length: 0',
    'Connection: close',
    '',
    ''
  ].join('\r\n'));
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  password: 'nodejsrules'
});

// example output:
// Client :: ready
// Listening for connections on server on port 8000!
//  (.... then from another terminal on the server: `curl -I http://127.0.0.1:8000`)
// TCP :: INCOMING CONNECTION: { destIP: '127.0.0.1',
//  destPort: 8000,
//  srcIP: '127.0.0.1',
//  srcPort: 41969 }
// TCP DATA: HEAD / HTTP/1.1
// User-Agent: curl/7.27.0
// Host: 127.0.0.1:8000
// Accept: */*
//
//
// TCP :: CLOSED

Get a directory listing via SFTP

const { Client } = require('ssh2');

const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  conn.sftp((err, sftp) => {
    if (err) throw err;
    sftp.readdir('foo', (err, list) => {
      if (err) throw err;
      console.dir(list);
      conn.end();
    });
  });
}).connect({
  host: '192.168.100.100',
  port: 22,
  username: 'frylock',
  password: 'nodejsrules'
});

// example output:
// Client :: ready
// [ { filename: 'test.txt',
//     longname: '-rw-r--r--    1 frylock   frylock         12 Nov 18 11:05 test.txt',
//     attrs:
//      { size: 12,
//        uid: 1000,
//        gid: 1000,
//        mode: 33188,
//        atime: 1353254750,
//        mtime: 1353254744 } },
//   { filename: 'mydir',
//     longname: 'drwxr-xr-x    2 frylock   frylock       4096 Nov 18 15:03 mydir',
//     attrs:
//      { size: 1048576,
//        uid: 1000,
//        gid: 1000,
//        mode: 16877,
//        atime: 1353269007,
//        mtime: 1353269007 } } ]

Connection hopping

const { Client } = require('ssh2');

const conn1 = new Client();
const conn2 = new Client();

// Checks uptime on 10.1.1.40 via 192.168.1.1

conn1.on('ready', () => {
  console.log('FIRST :: connection ready');
  // Alternatively, you could use something like netcat or socat with exec()
  // instead of forwardOut(), depending on what the server allows
  conn1.forwardOut('127.0.0.1', 12345, '10.1.1.40', 22, (err, stream) => {
    if (err) {
      console.log('FIRST :: forwardOut error: ' + err);
      return conn1.end();
    }
    conn2.connect({
      sock: stream,
      username: 'user2',
      password: 'password2',
    });
  });
}).connect({
  host: '192.168.1.1',
  username: 'user1',
  password: 'password1',
});

conn2.on('ready', () => {
  // This connection is the one to 10.1.1.40

  console.log('SECOND :: connection ready');
  conn2.exec('uptime', (err, stream) => {
    if (err) {
      console.log('SECOND :: exec error: ' + err);
      return conn1.end();
    }
    stream.on('close', () => {
      conn1.end(); // close parent (and this) connection
    }).on('data', (data) => {
      console.log(data.toString());
    });
  });
});

Forward remote X11 connections

const { Socket } = require('net');

const { Client } = require('ssh2');

const conn = new Client();

conn.on('x11', (info, accept, reject) => {
  const xserversock = new net.Socket();
  xserversock.on('connect', () => {
    const xclientsock = accept();
    xclientsock.pipe(xserversock).pipe(xclientsock);
  });
  // connects to localhost:0.0
  xserversock.connect(6000, 'localhost');
});

conn.on('ready', () => {
  conn.exec('xeyes', { x11: true }, (err, stream) => {
    if (err) throw err;
    let code = 0;
    stream.on('close', () => {
      if (code !== 0)
        console.log('Do you have X11 forwarding enabled on your SSH server?');
      conn.end();
    }).on('exit', (exitcode) => {
      code = exitcode;
    });
  });
}).connect({
  host: '192.168.1.1',
  username: 'foo',
  password: 'bar'
});

Dynamic (1:1) port forwarding using a SOCKSv5 proxy (using socksv5)

const socks = require('socksv5');
const { Client } = require('ssh2');

const sshConfig = {
  host: '192.168.100.1',
  port: 22,
  username: 'nodejs',
  password: 'rules'
};

socks.createServer((info, accept, deny) => {
  // NOTE: you could just use one ssh2 client connection for all forwards, but
  // you could run into server-imposed limits if you have too many forwards open
  // at any given time
  const conn = new Client();
  conn.on('ready', () => {
    conn.forwardOut(info.srcAddr,
                    info.srcPort,
                    info.dstAddr,
                    info.dstPort,
                    (err, stream) => {
      if (err) {
        conn.end();
        return deny();
      }

      const clientSocket = accept(true);
      if (clientSocket) {
        stream.pipe(clientSocket).pipe(stream).on('close', () => {
          conn.end();
        });
      } else {
        conn.end();
      }
    });
  }).on('error', (err) => {
    deny();
  }).connect(sshConfig);
}).listen(1080, 'localhost', () => {
  console.log('SOCKSv5 proxy server started on port 1080');
}).useAuth(socks.auth.None());

// test with cURL:
//   curl -i --socks5 localhost:1080 google.com

Make HTTP(S) connections easily using a custom http(s).Agent

const http = require('http');

const { Client, HTTPAgent, HTTPSAgent } = require('ssh2');

const sshConfig = {
  host: '192.168.100.1',
  port: 22,
  username: 'nodejs',
  password: 'rules'
};

// Use `HTTPSAgent` instead for an HTTPS request
const agent = new HTTPAgent(sshConfig);
http.get({
  host: '192.168.200.1',
  agent,
  headers: { Connection: 'close' }
}, (res) => {
  console.log(res.statusCode);
  console.dir(res.headers);
  res.resume();
});

Invoke an arbitrary subsystem

const { Client } = require('ssh2');

const xmlhello = `
  <?xml version="1.0" encoding="UTF-8"?>
  <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
    <capabilities>
      <capability>urn:ietf:params:netconf:base:1.0</capability>
    </capabilities>
  </hello>]]>]]>`;

const conn = new Client();

conn.on('ready', () => {
  console.log('Client :: ready');
  conn.subsys('netconf', (err, stream) => {
    if (err) throw err;
    stream.on('data', (data) => {
      console.log(data);
    }).write(xmlhello);
  });
}).connect({
  host: '1.2.3.4',
  port: 22,
  username: 'blargh',
  password: 'honk'
});

Server Examples

Password and public key authentication and non-interactive (exec) command execution

const { timingSafeEqual } = require('crypto');
const { readFileSync } = require('fs');
const { inspect } = require('util');

const { utils: { parseKey }, Server } = require('ssh2');

const allowedUser = Buffer.from('foo');
const allowedPassword = Buffer.from('bar');
const allowedPubKey = parseKey(readFileSync('foo.pub'));

function checkValue(input, allowed) {
  const autoReject = (input.length !== allowed.length);
  if (autoReject) {
    // Prevent leaking length information by always making a comparison with the
    // same input when lengths don't match what we expect ...
    allowed = input;
  }
  const isMatch = timingSafeEqual(input, allowed);
  return (!autoReject && isMatch);
}

new Server({
  hostKeys: [readFileSync('host.key')]
}, (client) => {
  console.log('Client connected!');

  client.on('authentication', (ctx) => {
    let allowed = true;
    if (!checkValue(Buffer.from(ctx.username), allowedUser))
      allowed = false;

    switch (ctx.method) {
      case 'password':
        if (!checkValue(Buffer.from(ctx.password), allowedPassword))
          return ctx.reject();
        break;
      case 'publickey':
        if (ctx.key.algo !== allowedPubKey.type
            || !checkValue(ctx.key.data, allowedPubKey.getPublicSSH())
            || (ctx.signature && allowedPubKey.verify(ctx.blob, ctx.signature, ctx.hashAlgo) !== true)) {
          return ctx.reject();
        }
        break;
      default:
        return ctx.reject();
    }

    if (allowed)
      ctx.accept();
    else
      ctx.reject();
  }).on('ready', () => {
    console.log('Client authenticated!');

    client.on('session', (accept, reject) => {
      const session = accept();
      session.once('exec', (accept, reject, info) => {
        console.log('Client wants to execute: ' + inspect(info.command));
        const stream = accept();
        stream.stderr.write('Oh no, the dreaded errors!\n');
        stream.write('Just kidding about the errors!\n');
        stream.exit(0);
        stream.end();
      });
    });
  }).on('close', () => {
    console.log('Client disconnected');
  });
}).listen(0, '127.0.0.1', function() {
  console.log('Listening on port ' + this.address().port);
});

SFTP-only server

const { timingSafeEqual } = require('crypto');
const { readFileSync } = require('fs');
const { inspect } = require('util');

const {
  Server,
  sftp: {
    OPEN_MODE,
    STATUS_CODE,
  },
} = require('ssh2');

const allowedUser = Buffer.from('foo');
const allowedPassword = Buffer.from('bar');

function checkValue(input, allowed) {
  const autoReject = (input.length !== allowed.length);
  if (autoReject) {
    // Prevent leaking length information by always making a comparison with the
    // same input when lengths don't match what we expect ...
    allowed = input;
  }
  const isMatch = timingSafeEqual(input, allowed);
  return (!autoReject && isMatch);
}

// This simple SFTP server implements file uploading where the contents get
// ignored ...

new ssh2.Server({
  hostKeys: [readFileSync('host.key')]
}, (client) => {
  console.log('Client connected!');

  client.on('authentication', (ctx) => {
    let allowed = true;
    if (!checkValue(Buffer.from(ctx.username), allowedUser))
      allowed = false;

    switch (ctx.method) {
      case 'password':
        if (!checkValue(Buffer.from(ctx.password), allowedPassword))
          return ctx.reject();
        break;
      default:
        return ctx.reject();
    }

    if (allowed)
      ctx.accept();
    else
      ctx.reject();
  }).on('ready', () => {
    console.log('Client authenticated!');

    client.on('session', (accept, reject) => {
      const session = accept();
      session.on('sftp', (accept, reject) => {
        console.log('Client SFTP session');
        const openFiles = new Map();
        let handleCount = 0;
        const sftp = accept();
        sftp.on('OPEN', (reqid, filename, flags, attrs) => {
          // Only allow opening /tmp/foo.txt for writing
          if (filename !== '/tmp/foo.txt' || !(flags & OPEN_MODE.WRITE))
            return sftp.status(reqid, STATUS_CODE.FAILURE);

          // Create a fake handle to return to the client, this could easily
          // be a real file descriptor number for example if actually opening
          // a file on disk
          const handle = Buffer.alloc(4);
          openFiles.set(handleCount, true);
          handle.writeUInt32BE(handleCount++, 0);

          console.log('Opening file for write')
          sftp.handle(reqid, handle);
        }).on('WRITE', (reqid, handle, offset, data) => {
          if (handle.length !== 4
              || !openFiles.has(handle.readUInt32BE(0))) {
            return sftp.status(reqid, STATUS_CODE.FAILURE);
          }

          // Fake the write operation
          sftp.status(reqid, STATUS_CODE.OK);

          console.log('Write to file at offset ${offset}: ${inspect(data)}');
        }).on('CLOSE', (reqid, handle) => {
          let fnum;
          if (handle.length !== 4
              || !openFiles.has(fnum = handle.readUInt32BE(0))) {
            return sftp.status(reqid, STATUS_CODE.FAILURE);
          }

          console.log('Closing file');
          openFiles.delete(fnum);

          sftp.status(reqid, STATUS_CODE.OK);
        });
      });
    });
  }).on('close', () => {
    console.log('Client disconnected');
  });
}).listen(0, '127.0.0.1', function() {
  console.log('Listening on port ' + this.address().port);
});

Other Examples

Generate an SSH key

const { utils: { generateKeyPair, generateKeyPairSync } } = require('ssh2');

// Generate unencrypted ED25519 SSH key synchronously
let keys = generateKeyPairSync('ed25519');
// ... use `keys.public` and `keys.private`

// Generate unencrypted ECDSA SSH key synchronously with a comment set
keys = generateKeyPairSync('ecdsa', { bits: 256, comment: 'node.js rules!' });
// ... use `keys.public` and `keys.private`

// Generate encrypted RSA SSH key asynchronously
generateKeyPair(
  'rsa',
  { bits: 2048, passphrase: 'foobarbaz', cipher: 'aes256-cbc' },
  (err, keys) => {
    if (err) throw err;
    // ... use `keys.public` and `keys.private`
  }
);

You can find more examples in the examples directory of this repository.

API

require('ssh2').Client is the Client constructor.

require('ssh2').Server is the Server constructor.

require('ssh2').utils is an object containing some useful utilities.

require('ssh2').HTTPAgent is an http.Agent constructor.

require('ssh2').HTTPSAgent is an https.Agent constructor. Its API is the same as HTTPAgent except it's for HTTPS connections.

Agent-related

require('ssh2').AgentProtocol is a Duplex stream class that aids in communicating over the OpenSSH agent protocol.

require('ssh2').BaseAgent is a base class for creating custom authentication agents.

require('ssh2').createAgent is a helper function that creates a new agent instance using the same logic as the agent configuration option: if the platform is Windows and it's the value "pageant", it creates a PageantAgent, otherwise if it's not a path to a Windows pipe it creates a CygwinAgent. In all other cases, it creates an OpenSSHAgent.

require('ssh2').CygwinAgent is an agent class implementation that communicates with agents in a Cygwin environment.

require('ssh2').OpenSSHAgent is an agent class implementation that communicates with OpenSSH agents over a UNIX socket.

require('ssh2').PageantAgent is an agent class implementation that communicates with Pageant agent processes.

Client

Client events

  • banner(< string >message, < string >language) - A notice was sent by the server upon connection.

  • change password(< string >prompt, < function >done) - If using password-based user authentication, the server has requested that the user's password be changed. Call done with the new password.

  • close() - The socket was closed.

  • end() - The socket was disconnected.

  • error(< Error >err) - An error occurred. A 'level' property indicates 'client-socket' for socket-level errors and 'client-ssh' for SSH disconnection messages. In the case of 'client-ssh' messages, there may be a 'description' property that provides more detail.

  • handshake(< object >negotiated) - Emitted when a handshake has completed (either initial or rekey). negotiated contains the negotiated details of the handshake and is of the form:

    // In this particular case `mac` is empty because there is no separate MAC
    // because it's integrated into AES in GCM mode
    { kex: 'ecdh-sha2-nistp256',
      srvHostKey: 'rsa-sha2-512',
      cs: { // Client to server algorithms
        cipher: 'aes128-gcm',
        mac: '',
        compress: 'none',
        lang: ''
      },
      sc: { // Server to client algorithms
        cipher: 'aes128-gcm',
        mac: '',
        compress: 'none',
        lang: ''
      }
    }
  • hostkeys(< array >keys) - Emitted when the server announces its available host keys. keys is the list of parsed (using parseKey()) host public keys.

  • keyboard-interactive(< string >name, < string >instructions, < string >instructionsLang, < array >prompts, < function >finish) - The server is asking for replies to the given prompts for keyboard-interactive user authentication. name is generally what you'd use as a window title (for GUI apps). prompts is an array of { prompt: 'Password: ', echo: false } style objects (here echo indicates whether user input should be displayed on the screen). The answers for all prompts must be provided as an array of strings and passed to finish when you are ready to continue. Note: It's possible for the server to come back and ask more questions.

  • ready() - Authentication was successful.

  • rekey() - Emitted when a rekeying operation has completed (either client or server-initiated).

  • tcp connection(< object >details, < function >accept, < function >reject) - An incoming forwarded TCP connection is being requested. Calling accept accepts the connection and returns a Channel object. Calling reject rejects the connection and no further action is needed. details contains:

    • destIP - string - The remote IP the connection was received on (given in earlier call to forwardIn()).

    • destPort - integer - The remote port the connection was received on (given in earlier call to forwardIn()).

    • srcIP - string - The originating IP of the connection.

    • srcPort - integer - The originating port of the connection.

  • unix connection(< object >details, < function >accept, < function >reject) - An incoming forwarded UNIX socket connection is being requested. Calling accept accepts the connection and returns a Channel object. Calling reject rejects the connection and no further action is needed. details contains:

    • socketPath - string - The originating UNIX socket path of the connection.
  • x11(< object >details, < function >accept, < function >reject) - An incoming X11 connection is being requested. Calling accept accepts the connection and returns a Channel object. Calling reject rejects the connection and no further action is needed. details contains:

    • srcIP - string - The originating IP of the connection.

    • srcPort - integer - The originating port of the connection.

Client methods

  • (constructor)() - Creates and returns a new Client instance.

  • connect(< object >config) - (void) - Attempts a connection to a server using the information given in config:

    • agent - string - Path to ssh-agent's UNIX socket for ssh-agent-based user authentication. Windows users: set to 'pageant' for authenticating with Pageant or (actual) path to a cygwin "UNIX socket." Default: (none)

    • agentForward - boolean - Set to true to use OpenSSH agent forwarding ([email protected]) for the life of the connection. agent must also be set to use this feature. Default: false

    • algorithms - object - This option allows you to explicitly override the default transport layer algorithms used for the connection. The value for each category must either be an array of valid algorithm names to set an exact list (with the most preferable first) or an object containing append, prepend, and/or remove properties that each contain an array of algorithm names or RegExps to match to adjust default lists for each category. Valid keys:

      • cipher - mixed - Ciphers.

        • Default list (in order from most to least preferable):
        • Other supported names:
          • 3des-cbc
          • aes256-cbc
          • aes192-cbc
          • aes128-cbc
          • arcfour256
          • arcfour128
          • arcfour
          • blowfish-cbc
          • cast128-cbc
      • compress - mixed - Compression algorithms.

        • Default list (in order from most to least preferable):
        • Other supported names:
      • hmac - mixed - (H)MAC algorithms.

      • kex - mixed - Key exchange algorithms.

        • Default list (in order from most to least preferable):
          • curve25519-sha256 (node v14.0.0+)
          • [email protected] (node v14.0.0+)
          • ecdh-sha2-nistp256
          • ecdh-sha2-nistp384
          • ecdh-sha2-nistp521
          • diffie-hellman-group-exchange-sha256
          • diffie-hellman-group14-sha256
          • diffie-hellman-group15-sha512
          • diffie-hellman-group16-sha512
          • diffie-hellman-group17-sha512
          • diffie-hellman-group18-sha512
        • Other supported names:
          • diffie-hellman-group-exchange-sha1
          • diffie-hellman-group14-sha1
          • diffie-hellman-group1-sha1
      • serverHostKey - mixed - Server host key formats.

        • Default list (in order from most to least preferable):
          • ssh-ed25519 (node v12.0.0+)
          • ecdsa-sha2-nistp256
          • ecdsa-sha2-nistp384
          • ecdsa-sha2-nistp521
          • rsa-sha2-512
          • rsa-sha2-256
          • ssh-rsa
        • Other supported names:
          • ssh-dss
    • authHandler - mixed - Must be an array of objects as described below, an array of strings containing valid authentication method names (username and credentials are pulled from the object passed to connect()), or a function with parameters (methodsLeft, partialSuccess, callback) where methodsLeft and partialSuccess are null on the first authentication attempt, otherwise are an array and boolean respectively. Return or call callback() with either the name of the authentication method or an object containing the method name along with method-specific details to try next (return/pass false to signal no more methods to try). Valid method names are: 'none', 'password', 'publickey', 'agent', 'keyboard-interactive', 'hostbased'. Default: function that follows a set method order: None -> Password -> Private Key -> Agent (-> keyboard-interactive if tryKeyboard is true) -> Hostbased

      • When returning or calling callback() with an object, it can take one of the following forms:

        {
          type: 'none',
          username: 'foo',
        }
        {
          type: 'password'
          username: 'foo',
          password: 'bar',
        }
        {
          type: 'publickey'
          username: 'foo',
          // Can be a string, Buffer, or parsed key containing a private key
          key: ...,
          // `passphrase` only required for encrypted keys
          passphrase: ...,
        }
        {
          type: 'hostbased'
          username: 'foo',
          localHostname: 'baz',
          localUsername: 'quux',
          // Can be a string, Buffer, or parsed key containing a private key
          key: ...,
          // `passphrase` only required for encrypted keys
          passphrase: ...,
        }
        {
          type: 'agent'
          username: 'foo',
          // Can be a string that is interpreted exactly like the `agent`
          // connection config option or can be a custom agent
          // object/instance that extends and implements `BaseAgent`
          agent: ...,
        }
        {
          type: 'keyboard-interactive'
          username: 'foo',
          // This works exactly the same way as a 'keyboard-interactive'
          // Client event handler
          prompt: (name, instructions, instructionsLang, prompts, finish) => {
            // ...
          },
        }
    • debug - function - Set this to a function that receives a single string argument to get detailed (local) debug information. Default: (none)

    • forceIPv4 - boolean - Only connect via resolved IPv4 address for host. Default: false

    • forceIPv6 - boolean - Only connect via resolved IPv6 address for host. Default: false

    • host - string - Hostname or IP address of the server. Default: 'localhost'

    • hostHash - string - Any valid hash algorithm supported by node. The host's key is hashed using this algorithm and passed to the hostVerifier function as a hex string. Default: (none)

    • hostVerifier - function - Function with parameters (hashedKey[, callback]) where hashedKey is a string hex hash of the host's key for verification purposes. Return true to continue with the handshake or false to reject and disconnect, or call callback() with true or false if you need to perform asynchronous verification. Default: (auto-accept if hostVerifier is not set)

    • keepaliveCountMax - integer - How many consecutive, unanswered SSH-level keepalive packets that can be sent to the server before disconnection (similar to OpenSSH's ServerAliveCountMax config option). Default: 3

    • keepaliveInterval - integer - How often (in milliseconds) to send SSH-level keepalive packets to the server (in a similar way as OpenSSH's ServerAliveInterval config option). Set to 0 to disable. Default: 0

    • localAddress - string - IP address of the network interface to use to connect to the server. Default: (none -- determined by OS)

    • localHostname - string - Along with localUsername and privateKey, set this to a non-empty string for hostbased user authentication. Default: (none)

    • localPort - string - The local port number to connect from. Default: (none -- determined by OS)

    • localUsername - string - Along with localHostname and privateKey, set this to a non-empty string for hostbased user authentication. Default: (none)

    • passphrase - string - For an encrypted privateKey, this is the passphrase used to decrypt it. Default: (none)

    • password - string - Password for password-based user authentication. Default: (none)

    • port - integer - Port number of the server. Default: 22

    • privateKey - mixed - Buffer or string that contains a private key for either key-based or hostbased user authentication (OpenSSH format). Default: (none)

    • readyTimeout - integer - How long (in milliseconds) to wait for the SSH handshake to complete. Default: 20000

    • sock - ReadableStream - A ReadableStream to use for communicating with the server instead of creating and using a new TCP connection (useful for connection hopping).

    • strictVendor - boolean - Performs a strict server vendor check before sending vendor-specific requests, etc. (e.g. check for OpenSSH server when using openssh_noMoreSessions()) Default: true

    • tryKeyboard - boolean - Try keyboard-interactive user authentication if primary user authentication method fails. If you set this to true, you need to handle the keyboard-interactive event. Default: false

    • username - string - Username for authentication. Default: (none)

  • end() - (void) - Disconnects the socket.

  • exec(< string >command[, < object >options], < function >callback) - (void) - Executes command on the server. callback has 2 parameters: < Error >err, < Channel >stream. Valid options properties are:

    • env - object - An environment to use for the execution of the command.

    • pty - mixed - Set to true to allocate a pseudo-tty with defaults, or an object containing specific pseudo-tty settings (see 'Pseudo-TTY settings'). Setting up a pseudo-tty can be useful when working with remote processes that expect input from an actual terminal (e.g. sudo's password prompt).

    • x11 - mixed - Set to true to use defaults below, set to a number to specify a specific screen number, or an object with the following valid properties:

      • cookie - mixed - The authentication cookie. Can be a hex string or a Buffer containing the raw cookie value (which will be converted to a hex string). Default: (random 16 byte value)

      • protocol - string - The authentication protocol name. Default: 'MIT-MAGIC-COOKIE-1'

      • screen - number - Screen number to use Default: 0

      • single - boolean - Allow just a single connection? Default: false

  • forwardIn(< string >remoteAddr, < integer >remotePort, < function >callback) - (void) - Bind to remoteAddr on remotePort on the server and forward incoming TCP connections. callback has 2 parameters: < Error >err, < integer >port (port is the assigned port number if remotePort was 0). Here are some special values for remoteAddr and their associated binding behaviors:

    • '' - Connections are to be accepted on all protocol families supported by the server.

    • '0.0.0.0' - Listen on all IPv4 addresses.

    • '::' - Listen on all IPv6 addresses.

    • 'localhost' - Listen on all protocol families supported by the server on loopback addresses only.

    • '127.0.0.1' and '::1' - Listen on the loopback interfaces for IPv4 and IPv6, respectively.

  • forwardOut(< string >srcIP, < integer >srcPort, < string >dstIP, < integer >dstPort, < function >callback) - (void) - Open a connection with srcIP and srcPort as the originating address and port and dstIP and dstPort as the remote destination address and port. callback has 2 parameters: < Error >err, < Channel >stream.

  • openssh_forwardInStreamLocal(< string >socketPath, < function >callback) - (void) - OpenSSH extension that binds to a UNIX domain socket at socketPath on the server and forwards incoming connections. callback has 1 parameter: < Error >err.

  • openssh_forwardOutStreamLocal(< string >socketPath, < function >callback) - (void) - OpenSSH extension that opens a connection to a UNIX domain socket at socketPath on the server. callback has 2 parameters: < Error >err, < Channel >stream.

  • openssh_noMoreSessions(< function >callback) - (void) - OpenSSH extension that sends a request to reject any new sessions (e.g. exec, shell, sftp, subsys) for this connection. callback has 1 parameter: < Error >err.

  • openssh_unforwardInStreamLocal(< string >socketPath, < function >callback) - (void) - OpenSSH extension that unbinds from a UNIX domain socket at socketPath on the server and stops forwarding incoming connections. callback has 1 parameter: < Error >err.

  • rekey([< function >callback]) - (void) - Initiates a rekey with the server. If callback is supplied, it is added as a one-time handler for the rekey event.

  • setNoDelay([< boolean >noDelay]) - Client - Calls setNoDelay() on the underlying socket. Disabling Nagle's algorithm improves latency at the expense of lower throughput.

  • 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.

  • 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.

  • subsys(< string >subsystem, < function >callback) - (void) - Invokes subsystem on the server. callback has 2 parameters: < Error >err, < Channel >stream.

  • unforwardIn(< string >remoteAddr, < integer >remotePort, < function >callback) - (void) - Unbind from remoteAddr on remotePort on the server and stop forwarding incoming TCP connections. Until callback is called, more connections may still come in. callback has 1 parameter: < Error >err.

Server

Server events

  • connection(< Connection >client, < object >info) - A new client has connected. info contains the following properties:

    • family - string - The remoteFamily of the connection.

    • header - object - Information about the client's header:

      • identRaw - string - The raw client identification string.

      • versions - object - Various version information:

        • protocol - string - The SSH protocol version (always 1.99 or 2.0).

        • software - string - The software name and version of the client.

      • comments - string - Any text that comes after the software name/version.

    Example: the identification string SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 would be parsed as:

        { identRaw: 'SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2',
          version: {
            protocol: '2.0',
            software: 'OpenSSH_6.6.1p1'
          },
          comments: 'Ubuntu-2ubuntu2' }
* **ip** - _string_ - The `remoteAddress` of the connection.

* **port** - _integer_ - The `remotePort` of the connection.

Server methods

  • (constructor)(< object >config[, < function >connectionListener]) - Creates and returns a new Server instance. Server instances also have the same methods/properties/events as net.Server. connectionListener if supplied, is added as a connection listener. Valid config properties:

    • algorithms - object - This option allows you to explicitly override the default transport layer algorithms used for incoming client connections. Each value must be an array of valid algorithms for that category. The order of the algorithms in the arrays are important, with the most favorable being first. For a list of valid and default algorithm names, please review the documentation for the version of ssh2 used by this module. Valid keys:

      • cipher - array - Ciphers.

      • compress - array - Compression algorithms.

      • hmac - array - (H)MAC algorithms.

      • kex - array - Key exchange algorithms.

      • serverHostKey - array - Server host key formats.

    • banner - string - A message that is sent to clients once, right before authentication begins. Default: (none)

    • debug - function - Set this to a function that receives a single string argument to get detailed (local) debug information. Default: (none)

    • greeting - string - A message that is sent to clients immediately upon connection, before handshaking begins. Note: Most clients usually ignore this. Default: (none)

    • highWaterMark - integer - This is the highWaterMark to use for the parser stream. Default: 32 * 1024

    • hostKeys - array - An array of either Buffers/strings that contain host private keys or objects in the format of { key: <Buffer/string>, passphrase: <string> } for encrypted private keys. (Required) Default: (none)

    • ident - string - A custom server software name/version identifier. Default: 'ssh2js' + moduleVersion + 'srv'

  • injectSocket(< DuplexStream >socket) - Injects a bidirectional stream as though it were a TCP socket connection. Additionally, socket should include net.Socket-like properties to ensure the best compatibility (e.g. socket.remoteAddress, socket.remotePort, socket.remoteFamily).

Connection events

  • authentication(< AuthContext >ctx) - The client has requested authentication. ctx.username contains the client username, ctx.method contains the requested authentication method, and ctx.accept() and ctx.reject([< Array >authMethodsLeft[, < Boolean >isPartialSuccess]]) are used to accept or reject the authentication request respectively. 'abort' is emitted if the client aborts the authentication request. Other properties/methods available on ctx depends on the ctx.method of authentication the client has requested:

    • hostbased:

      • blob - Buffer - This contains the data to be verified that is passed to (along with the signature) key.verify() where key is a public key parsed with parseKey().

      • key - object - Contains information about the public key sent by the client:

        • algo - string - The name of the key algorithm (e.g. ssh-rsa).

        • data - Buffer - The actual key data.

      • localHostname - string - The local hostname provided by the client.

      • localUsername - string - The local username provided by the client.

      • signature - Buffer - This contains a signature to be verified that is passed to (along with the blob) key.verify() where key is a public key parsed with parseKey().

      • hashAlgo - mixed - This is either undefined or a string containing an explicit hash algorithm to be used during verification (passed to key.verify()).

    • keyboard-interactive:

      • prompt(< array >prompts[, < string >title[, < string >instructions]], < function >callback) - (void) - Send prompts to the client. prompts is an array of { prompt: 'Prompt text', echo: true } objects (prompt being the prompt text and echo indicating whether the client's response to the prompt should be echoed to their display). callback is called with (responses), where responses is an array of string responses matching up to the prompts.

      • submethods - array - A list of preferred authentication "sub-methods" sent by the client. This may be used to determine what (if any) prompts to send to the client.

    • password:

      • password - string - This is the password sent by the client.

      • requestChange(< string >prompt, < function >callback) - (void) - Sends a password change request to the client. callback is called with (newPassword), where newPassword is the new password supplied by the client. You may accept, reject, or prompt for another password change after callback is called.

    • publickey:

      • blob - mixed - If the value is undefined, the client is only checking the validity of the key. If the value is a Buffer, then this contains the data to be verified that is passed to (along with the signature) key.verify() where key is a public key parsed with parseKey().

      • key - object - Contains information about the public key sent by the client:

        • algo - string - The name of the key algorithm (e.g. ssh-rsa).

        • data - Buffer - The actual key data.

      • signature - mixed - If the value is undefined, the client is only checking the validity of the key. If the value is a Buffer, then this contains a signature to be verified that is passed to (along with the blob) key.verify() where key is a public key parsed with parseKey().

      • hashAlgo - mixed - This is either undefined or a string containing an explicit hash algorithm to be used during verification (passed to key.verify()).

  • close() - The client socket was closed.

  • end() - The client socket disconnected.

  • error(< Error >err) - An error occurred.

  • handshake(< object >negotiated) - Emitted when a handshake has completed (either initial or rekey). negotiated contains the negotiated details of the handshake and is of the form:

    // In this particular case `mac` is empty because there is no separate MAC
    // because it's integrated into AES in GCM mode
    { kex: 'ecdh-sha2-nistp256',
      srvHostKey: 'rsa-sha2-512',
      cs: { // Client to server algorithms
        cipher: 'aes128-gcm',
        mac: '',
        compress: 'none',
        lang: ''
      },
      sc: { // Server to client algorithms
        cipher: 'aes128-gcm',
        mac: '',
        compress: 'none',
        lang: ''
      }
    }
  • openssh.streamlocal(< function >accept, < function >reject, < object >info) - Emitted when the client has requested a connection to a UNIX domain socket. accept() returns a new Channel instance representing the connection. info contains:

    • socketPath - string - Destination socket path of outgoing connection.
  • ready() - Emitted when the client has been successfully authenticated.

  • rekey() - Emitted when a rekeying operation has completed (either client or server-initiated).

  • request(< mixed >accept, < mixed >reject, < string >name, < object >info) - Emitted when the client has sent a global request for name (e.g. tcpip-forward or cancel-tcpip-forward). accept and reject are functions if the client requested a response. If bindPort === 0, you should pass the chosen port to accept() so that the client will know what port was bound. info contains additional details about the request:

    • cancel-tcpip-forward and tcpip-forward:

      • bindAddr - string - The IP address to start/stop binding to.

      • bindPort - integer - The port to start/stop binding to.

    • [email protected] and [email protected]:

      • socketPath - string - The socket path to start/stop binding to.
  • session(< function >accept, < function >reject) - Emitted when the client has requested a new session. Sessions are used to start interactive shells, execute commands, request X11 forwarding, etc. accept() returns a new Session instance.

  • tcpip(< function >accept, < function >reject, < object >info) - Emitted when the client has requested an outbound (TCP) connection. accept() returns a new Channel instance representing the connection. info contains:

    • destIP - string - Destination IP address of outgoing connection.

    • destPort - string - Destination port of outgoing connection.

    • srcIP - string - Source IP address of outgoing connection.

    • srcPort - string - Source port of outgoing connection.

Connection methods

  • end() - (void) - Closes the client connection.

  • forwardOut(< string >boundAddr, < integer >boundPort, < string >remoteAddr, < integer >remotePort, < function >callback) - (void) - Alert the client of an incoming TCP connection on boundAddr on port boundPort from remoteAddr on port remotePort. callback has 2 parameters: < Error >err, < Channel >stream.

  • openssh_forwardOutStreamLocal(< string >socketPath, < function >callback) - (void) - Alert the client of an incoming UNIX domain socket connection on socketPath. callback has 2 parameters: < Error >err, < Channel >stream.

  • rekey([< function >callback]) - (void) - Initiates a rekey with the client. If callback is supplied, it is added as a one-time handler for the rekey event.

  • setNoDelay([< boolean >noDelay]) - Connection - Calls setNoDelay() on the underlying socket. Disabling Nagle's algorithm improves latency at the expense of lower throughput.

  • x11(< string >originAddr, < integer >originPort, < function >callback) - (void) - Alert the client of an incoming X11 client connection from originAddr on port originPort. callback has 2 parameters: < Error >err, < Channel >stream.

Session events

  • auth-agent(< mixed >accept, < mixed >reject) - The client has requested incoming ssh-agent requests be forwarded to them. accept and reject are functions if the client requested a response.

  • close() - The session was closed.

  • env(< mixed >accept, < mixed >reject, < object >info) - The client requested an environment variable to be set for this session. accept and reject are functions if the client requested a response. info has these properties:

    • key - string - The environment variable's name.

    • value - string - The environment variable's value.

  • exec(< mixed >accept, < mixed >reject, < object >info) - The client has requested execution of a command string. accept and reject are functions if the client requested a response. accept() returns a Channel for the command execution. info has these properties:

    • command - string - The command line to be executed.
  • pty(< mixed >accept, < mixed >reject, < object >info) - The client requested allocation of a pseudo-TTY for this session. accept and reject are functions if the client requested a response. info has these properties:

    • term - string - The terminal type for the pseudo-TTY.

    • cols - integer - The number of columns for the pseudo-TTY.

    • height - integer - The height of the pseudo-TTY in pixels.

    • modes - object - Contains the requested terminal modes of the pseudo-TTY keyed on the mode name with the value being the mode argument. (See the table at the end for valid names).

    • rows - integer - The number of rows for the pseudo-TTY.

    • width - integer - The width of the pseudo-TTY in pixels.

  • sftp(< mixed >accept, < mixed >reject) - The client has requested the SFTP subsystem. accept and reject are functions if the client requested a response. accept() returns an SFTP instance in server mode (see the SFTP documentation for details). info has these properties:

  • shell(< mixed >accept, < mixed >reject) - The client has requested an interactive shell. accept and reject are functions if the client requested a response. accept() returns a Channel for the interactive shell.

  • signal(< mixed >accept, < mixed >reject, < object >info) - The client has sent a signal. accept and reject are functions if the client requested a response. info has these properties:

    • name - string - The signal name (e.g. SIGUSR1).
  • subsystem(< mixed >accept, < mixed >reject, < object >info) - The client has requested an arbitrary subsystem. accept and reject are functions if the client requested a response. accept() returns a Channel for the subsystem. info has these properties:

    • name - string - The name of the subsystem.
  • window-change(< mixed >accept, < mixed >reject, < object >info) - The client reported a change in window dimensions during this session. accept and reject are functions if the client requested a response. info has these properties:

    • cols - integer - The new number of columns for the client window.

    • height - integer - The new height of the client window in pixels.

    • rows - integer - The new number of rows for the client window.

    • width - integer - The new width of the client window in pixels.

  • x11(< mixed >accept, < mixed >reject, < object >info) - The client requested X11 forwarding. accept and reject are functions if the client requested a response. info has these properties:

    • cookie - string - The X11 authentication cookie encoded in hexadecimal.

    • protocol - string - The name of the X11 authentication method used (e.g. MIT-MAGIC-COOKIE-1).

    • screen - integer - The screen number to forward X11 connections for.

    • single - boolean - true if only a single connection should be forwarded.

Channel

This is a normal streams2 Duplex Stream (used both by clients and servers), with the following changes:

  • A boolean property allowHalfOpen exists and behaves similarly to the property of the same name for net.Socket. When the stream's end() is called, if allowHalfOpen is true, only EOF will be sent (the server can still send data if they have not already sent EOF). The default value for this property is true.

  • A close event is emitted once the channel is completely closed on both the client and server.

  • Client-specific:

    • For exec():

      • An exit event may (the SSH2 spec says it is optional) be emitted when the process finishes. If the process finished normally, the process's return value is passed to the exit callback. If the process was interrupted by a signal, the following are passed to the exit callback: null, < string >signalName, < boolean >didCoreDump, < string >description.

      • If there was an exit event, the close event will be passed the same arguments for convenience.

      • A stderr property contains a Readable stream that represents output from stderr.

    • For exec() and shell():

      • The readable side represents stdout and the writable side represents stdin.

      • setWindow(< integer >rows, < integer >cols, < integer >height, < integer >width) - (void) - Lets the server know that the local terminal window has been resized. The meaning of these arguments are described in the 'Pseudo-TTY settings' section.

      • signal(< string >signalName) - (void) - Sends a POSIX signal to the current process on the server. Valid signal names are: 'ABRT', 'ALRM', 'FPE', 'HUP', 'ILL', 'INT', 'KILL', 'PIPE', 'QUIT', 'SEGV', 'TERM', 'USR1', and 'USR2'. Some server implementations may ignore this request if they do not support signals. Note: If you are trying to send SIGINT and you find signal() doesn't work, try writing '\x03' to the Channel stream instead.

  • Server-specific:

    • For exec-enabled channel instances there is an additional method available that may be called right before you close the channel. It has two different signatures:

      • exit(< integer >exitCode) - (void) - Sends an exit status code to the client.

      • exit(< string >signalName[, < boolean >coreDumped[, < string >errorMsg]]) - (void) - Sends an exit status code to the client.

    • For exec and shell-enabled channel instances, channel.stderr is a writable stream.

Pseudo-TTY settings

  • cols - < integer > - Number of columns. Default: 80

  • height - < integer > - Height in pixels. Default: 480

  • modes - < object > - An object containing Terminal Modes as keys, with each value set to each mode argument. Default: null

  • rows - < integer > - Number of rows. Default: 24

  • term - < string > - The value to use for $TERM. Default: 'vt100'

  • width - < integer > - Width in pixels. Default: 640

rows and cols override width and height when rows and cols are non-zero.

Pixel dimensions refer to the drawable area of the window.

Zero dimension parameters are ignored.

Terminal modes

Name Description
CS7 7 bit mode.
CS8 8 bit mode.
ECHOCTL Echo control characters as ^(Char).
ECHO Enable echoing.
ECHOE Visually erase chars.
ECHOKE Visual erase for line kill.
ECHOK Kill character discards current line.
ECHONL Echo NL even if ECHO is off.
ICANON Canonicalize input lines.
ICRNL Map CR to NL on input.
IEXTEN Enable extensions.
IGNCR Ignore CR on input.
IGNPAR The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE, and 1 if it is TRUE.
IMAXBEL Ring bell on input queue full.
INLCR Map NL into CR on input.
INPCK Enable checking of parity errors.
ISIG Enable signals INTR, QUIT, [D]SUSP.
ISTRIP Strip 8th bit off characters.
IUCLC Translate uppercase characters to lowercase.
IXANY Any char will restart after stop.
IXOFF Enable input flow control.
IXON Enable output flow control.
NOFLSH Don't flush after interrupt.
OCRNL Translate carriage return to newline (output).
OLCUC Convert lowercase to uppercase.
ONLCR Map NL to CR-NL.
ONLRET Newline performs a carriage return (output).
ONOCR Translate newline to carriage return-newline (output).
OPOST Enable output processing.
PARENB Parity enable.
PARMRK Mark parity and framing errors.
PARODD Odd parity, else even.
PENDIN Retype pending input.
TOSTOP Stop background jobs from output.
TTY_OP_ISPEED Specifies the input baud rate in bits per second.
TTY_OP_OSPEED Specifies the output baud rate in bits per second.
VDISCARD Toggles the flushing of terminal output.
VDSUSP Another suspend character.
VEOF End-of-file character (sends EOF from the terminal).
VEOL2 Additional end-of-line character.
VEOL End-of-line character in addition to carriage return and/or linefeed.
VERASE Erase the character to left of the cursor.
VFLUSH Character to flush output.
VINTR Interrupt character; 255 if none. Similarly for the other characters. Not all of these characters are supported on all systems.
VKILL Kill the current input line.
VLNEXT Enter the next character typed literally, even if it is a special character
VQUIT The quit character (sends SIGQUIT signal on POSIX systems).
VREPRINT Reprints the current input line.
VSTART Continues paused output (normally control-Q).
VSTATUS Prints system status line (load, command, pid, etc).
VSTOP Pauses output (normally control-S).
VSUSP Suspends the current program.
VSWTCH Switch to a different shell layer.
VWERASE Erases a word left of cursor.
XCASE Enable input and output of uppercase characters by preceding their lowercase equivalents with "".

HTTPAgent

HTTPAgent methods

  • (constructor)(< object >sshConfig[, < object >agentConfig]) - Creates and returns a new http.Agent instance used to tunnel an HTTP connection over SSH. sshConfig is what is passed to client.connect() and agentOptions is passed to the http.Agent constructor.

HTTPSAgent

HTTPSAgent methods

  • (constructor)(< object >sshConfig[, < object >agentConfig]) - Creates and returns a new https.Agent instance used to tunnel an HTTP connection over SSH. sshConfig is what is passed to client.connect() and agentOptions is passed to the https.Agent constructor.

Utilities

  • generateKeyPair(< string >keyType[, < object >options], < function >callback) - (void) - Generates an SSH key pair of the given type. keyType may be one of 'rsa', 'ecdsa', or 'ed25519' (node.js v12+). callback has the signature (err, keys) where keys is an object containing private and public properties containing the generated SSH keys. options may contain:

    • bits - integer - For ECDSA and RSA keys, this is the key strength. For ECDSA, this is restricted to 256, 384, or 521. Default: (none)

    • cipher - string - The (SSH, not OpenSSL) cipher to use to encrypt the key. Default: (none)

    • comment - string - A comment to include in the private and public keys. Default: ''

    • format - string - The SSH key format to use. Currently only 'new' is supported, which represents the current OpenSSH key formats. Default: 'new'

    • passphrase - mixed - The desired passphrase for encrypting the key. This can either be a string or Buffer. Default: (none)

    • rounds - integer - For 'new'-formatted SSH keys, this is the number of bcrypt rounds to use when generating cipher parameters for encrypted keys. Default: 16

  • generateKeyPairSync(< string >keyType[, < object >options]) - object - Generates an SSH key pair of the given type. This is a synchronous version of generateKeyPair().

  • parseKey(< mixed >keyData[, < string >passphrase]) - mixed - Parses a private/public key in OpenSSH, RFC4716, or PPK format. For encrypted private keys, the key will be decrypted with the given passphrase. keyData can be a Buffer or string value containing the key contents. The returned value will be an array of objects (currently in the case of modern OpenSSH keys) or an object with these properties and methods:

    • comment - string - The comment for the key

    • equals(< mixed >otherKey) - boolean - This returns true if otherKey (a parsed or parseable key) is the same as this key. This method does not compare the keys' comments

    • getPrivatePEM() - string - This returns the PEM version of a private key

    • getPublicPEM() - string - This returns the PEM version of a public key (for either public key or derived from a private key)

    • getPublicSSH() - string - This returns the SSH version of a public key (for either public key or derived from a private key)

    • isPrivateKey() - boolean - This returns true if the key is a private key or not

    • sign(< mixed >data) - mixed - This signs the given data using this key and returns a Buffer containing the signature on success. On failure, an Error will be returned. data can be anything accepted by node's sign.update().

    • type - string - The full key type (e.g. 'ssh-rsa')

    • verify(< mixed >data, < Buffer >signature) - mixed - This verifies a signature of the given data using this key and returns true if the signature could be verified. On failure, either false will be returned or an Error will be returned upon a more critical failure. data can be anything accepted by node's verify.update().

  • sftp.OPEN_MODE - OPEN_MODE

  • sftp.STATUS_CODE - STATUS_CODE

  • sftp.flagsToString - flagsToString()

  • sftp.stringToFlags - stringToFlags()

AgentProtocol

AgentProtocol events

  • identities(< opaque >request) - (Server mode only) The client has requested a list of public keys stored in the agent. Use failureReply() or getIdentitiesReply() to reply appropriately.

  • sign(< opaque >request, < mixed >pubKey, < Buffer >data, < object >options) - (Server mode only) The client has requested data to be signed using the key identified by pubKey. Use failureReply() or signReply() to reply appropriately. options may contain any of:

    • hash - string - The explicitly desired hash to use when computing the signature. Currently if set, this may be either 'sha256' or 'sha512' for RSA keys.

AgentProtocol methods

  • (constructor)(< boolean >isClient) - Creates and returns a new AgentProtocol instance. isClient determines whether the instance operates in client or server mode.

  • failureReply(< opaque >request) - (void) - (Server mode only) Replies to the given request with a failure response.

  • getIdentities(< function >callback) - (void) - (Client mode only) Requests a list of public keys from the agent. callback is passed (err, keys) where keys is a possible array of public keys for authentication.

  • getIdentitiesReply(< opaque >request, < array >keys) - (void) - (Server mode only) Responds to a identities list request with the given array of keys in keys.

  • sign(< mixed >pubKey, < Buffer >data, < object >options, < function >callback) - (void) - (Client mode only) Requests that the agent sign data using the key identified by pubKey. pubKey can be any parsed (using utils.parseKey()) or parseable key value. callback is passed (err, signature) where signature is a possible Buffer containing the signature for the data. options may contain any of:

    • hash - string - The explicitly desired hash to use when computing the signature. Currently if set, this may be either 'sha256' or 'sha512' for RSA keys.
  • signReply(< opaque >request, < Buffer >signature) - (void) - (Server mode only) Responds to a sign request with the given signature in signature.

BaseAgent

In order to create a custom agent, your class must:

  • Extend BaseAgent

  • Call super() in its constructor

  • Implement at least the following methods:

  • getIdentities(< function >callback) - (void) - Passes (err, keys) to callback where keys is a possible array of public keys for authentication.

  • sign(< mixed >pubKey, < Buffer >data, < object >options, < function >callback) - (void) - Signs data using the key identified by pubKey. pubKey can be any parsed (using utils.parseKey()) or parseable key value. callback should be passed (err, signature) where signature is a possible Buffer containing the signature for the data. options may contain any of:

    • hash - string - The explicitly desired hash to use when computing the signature. Currently if set, this may be either 'sha256' or 'sha512' for RSA keys.

Additionally your class may implement the following method in order to support agent forwarding on the client:

  • getStream(< function >callback) - (void) - Passes (err, stream) to callback where stream is a possible Duplex stream to be used to communicate with your agent. You will probably want to utilize AgentProtocol as agent forwarding is an OpenSSH feature, so the stream needs to be able to transmit/receive OpenSSH agent protocol packets.

createAgent

  • createAgent(< string >agentValue) - (Agent) - Creates and returns a new agent instance using the same logic as the Client's agent configuration option: if the platform is Windows and it's the value "pageant", it creates a PageantAgent, otherwise if it's not a path to a Windows pipe it creates a CygwinAgent. In all other cases, it creates an OpenSSHAgent.

CygwinAgent

CygwinAgent methods

  • (constructor)(< string >socketPath) - Communicates with an agent listening at socketPath in a Cygwin environment.

OpenSSHAgent

OpenSSHAgent methods

  • (constructor)(< string >socketPath) - Communicates with an OpenSSH agent listening on the UNIX socket at socketPath.

PageantAgent

PageantAgent methods

  • (constructor)() - Creates a new agent instance for communicating with a running Pageant agent process.

ssh2's People

Contributors

131 avatar alsotang avatar bagder avatar bl-ue avatar cole-mujadzic-liongard avatar danielroe avatar dqminh avatar forbeslindesay avatar fredericosilva avatar gknauf avatar imatlopez avatar jaredhanson avatar jkingyens avatar jswk avatar kodestar avatar mafintosh avatar marcel-a avatar mingqi avatar mmalecki avatar mscdex avatar petethepig avatar pzrq avatar schoofskelvin avatar sh-vi avatar suisho avatar timbertson avatar timoxley avatar tlunter avatar wdavidw avatar xxorax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ssh2's Issues

SSH doesn't connect (auth::ready) anymore

I've upgraded my old status bot node to the newest node version. Previous version was v0.8.7 now we run v0.10.5.

Since I upgraded, the status bot doesn't connect properly anymore. We run OpenSSH_5.3p1 and the secure log states the following;

May  5 14:04:01 sshd[7780]: Bad packet length 1469807856.
May  5 14:04:21 sshd[7811]: Bad packet length 3010211349.
May  5 14:04:41 sshd[7821]: Bad packet length 2215667743.
May  5 14:05:01 sshd[7832]: Bad packet length 2092073108.
May  5 14:05:21 sshd[7846]: Bad packet length 2416978723.
May  5 14:05:41 sshd[7861]: Bad packet length 3922530746.
May  5 14:06:01 sshd[7872]: Bad packet length 3756914114.
May  5 14:06:21 sshd[7879]: Bad packet length 1458609236.
May  5 14:06:41 sshd[7886]: Bad packet length 2811535146.
May  5 14:07:01 sshd[7895]: Bad packet length 1332097811.

(on each connection attempt).

I tried:

  • Basic AUTH
  • Key AUTH

I tried versions:

  • v0.10.5 (not working auth)
  • v0.10.4 (not working auth)
  • v0.10.2 (not working auth)
  • v0.9.12 (not working auth)
  • v0.9.4 (not working auth)
  • v0.8.23 (works)

It seems that the node upgrade does have impact on this combination. I will try to debug it more and hopefully even fix it. But in the hope there already is a fix; this issue.

stream buffer

Hi, I have a question regarding the stream's 'data' event: if I'm not wrong it is fired only when stream's buffer is full. This causes data to be split in chunks equal to the buffer size. Is there a way to use tools like https://github.com/dodo/node-bufferstream instead of the standard stream?
This would help a lot when working with long string streams which needs to be splitted for example on newline char.
Thanks

Javascript globals leak detected (w/ patch)

I am using ssh2 for my own module. I have some tests under mocha, which offers the interesting possibility to detect global variables leaks. It finds some in ssh2:

     Error: global leaks detected: i, len, info
      at Runner.checkGlobals (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/mocha/lib/runner.js:167:21)
      at Runner.<anonymous> (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/mocha/lib/runner.js:59:44)
      at Runner.EventEmitter.emit (events.js:96:17)
      at Runner.hook (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/mocha/lib/runner.js:240:12)
      at done (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/mocha/lib/runnable.js:187:5)
      at Connection.Runnable.run.duration (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/mocha/lib/runnable.js:199:9)
      at Connection.EventEmitter.emit (events.js:93:17)
      at Parser.<anonymous> (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/ssh2/lib/Connection.js:737:10)
      at Parser.EventEmitter.emit (events.js:93:17)
      at Parser.parsePacket (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/ssh2/lib/Parser.js:451:12)
      at Parser.execute (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/ssh2/lib/Parser.js:221:14)
      at Socket.Connection.connect._sock.once.err.level (/Users/kowalskif/Desktop/GIT/enyojs/ares-webos-sdk/node_modules/ssh2/lib/Connection.js:1241:18)
      at Socket.EventEmitter.emit (events.js:96:17)
      at TCP.onread (net.js:397:14)

Here are the 2 patches (against 0.2.7) to fix this issue:

--- Parser.js~  2013-05-30 18:01:51.000000000 +0200
+++ Parser.js   2013-06-11 08:41:59.000000000 +0200
@@ -339,7 +339,8 @@
 };

 Parser.prototype.parseChRequest = function() {
-  var payload = this._payload;
+  var payload = this._payload,
+      info;

   var recipient = payload.readUInt32BE(1, true),
       request = readString(payload, 5, 'ascii');
@@ -381,7 +382,8 @@
 };

 Parser.prototype.parsePacket = function() {
-  var payload = this._payload;
+  var payload = this._payload,
+      lang, message, info;
   if (++this._seqno > MAX_SEQNO)
     this._seqno = 0;

and:

--- Connection.js~      2013-05-30 18:01:51.000000000 +0200
+++ Connection.js       2013-06-11 08:38:17.000000000 +0200
@@ -174,7 +174,7 @@
   function checkSKEXInit(init, cb) {
     self._debug&&self._debug('DEBUG: Connection: Comparing KEXInits...');
     // check for agreeable server->client cipher
-    for (i=0,len=ALGORITHMS.CIPHER.length;
+    for (var i=0,len=ALGORITHMS.CIPHER.length;
          i<len && init.algorithms.sc.encrypt.indexOf(ALGORITHMS.CIPHER[i])
                   === -1;
          ++i);
@@ -783,7 +783,7 @@
               buf, i,
               len = (nprompts < nanswers ? nprompts : nanswers),
               p = 0;
-          for (i = 0; i < len; ++i) {
+          for (var i = 0; i < len; ++i) {
             size += 4;
             size += Buffer.byteLength(answers[i]);
           }

exec stream: 'exit' event triggered before 'data' events

That happens sometimes, 'exit' event is triggered before 'data' events.
This is the correct flow? If yes, how do I handle this because I created a function with a callback to return the output of the ssh command and i trigger this callback in the event 'exit', and sometimes it is empty because the data comes later.

What is the correct way to close a sftp session?

I am having a problem getting the 'end' of an sftp session.

The following test code is modified from the sftp directory listing example

var Connection = require('ssh2');
var fs = require('fs');

var c = new Connection();
c.on('connect', function() {
  console.log('Connection :: connect');
});
c.on('ready', function() {
  console.log('Connection :: ready');
  c.sftp(function(err, sftp) {
    if (err) throw err;
    var rs = sftp.createReadStream('.bashrc'),
      ws = fs.createWriteStream('test.sh');
    rs.on('end', function() {
      //sftp.end();  //SEE COMMENTS
      console.log('SFTP :: readStream end');
      ws.end();
      //c.end();    //SEE COMMENTS
    });
    rs.on('error', function(err) { console.log('rs: '+err); });
    sftp.on('end', function() {
      console.log('SFTP :: SFTP session closed');
      c.end();
    });
    rs.pipe(ws);
  });
});
c.on('error', function(err) {
  console.log('Connection :: error :: ' + err);
});
c.on('end', function() {
  console.log('Connection :: end');
});
c.on('close', function(had_error) {
  console.log('Connection :: close');
});
c.connect({
  host: 'host',
  username: 'user',
  agent: process.env.SSH_AUTH_SOCK
});

The end event is fired on the sftp.readStream object, but the connection is never ended or closed. Uncommenting out the sftp.end(); line will generate the following output:

Connection :: connect
Connection :: ready
SFTP :: readStream end
rs: Error: Underlying stream not writable

So it seems that the SFTP connection has already been closed https://github.com/mscdex/ssh2/blob/master/lib/SFTP/SFTPv3.js#L1639
But there was no 'end' event.

If I add a c.end(); call to the end event on the readStream, I do close the connection, and end the script, but I would like to copy another file from the same host without opening a new connection.

Intermittent RangeError: length > kMaxLength

I set up a script using your first example (that runs 'uptime') and configured it for my SSH key to log in to my hosting account on dreamhost. It is intermittently giving an error - and by the way does not print the output from uptime.

tippy:akashacms.com davidherron$ node ../tsync.js 
Connection :: connect

buffer.js:242
      this.parent = new SlowBuffer(this.length);
                    ^
RangeError: length > kMaxLength
    at new Buffer (buffer.js:242:21)
    at Parser.expect (/Users/davidherron/node_modules/ssh2/lib/Parser.js:680:25)
    at Parser.execute (/Users/davidherron/node_modules/ssh2/lib/Parser.js:203:16)
    at Socket.Connection.connect._sock.once.err.level (/Users/davidherron/node_modules/ssh2/lib/Connection.js:1186:18)
    at Socket.EventEmitter.emit (events.js:93:17)
    at TCP.onread (net.js:396:14)
tippy:akashacms.com davidherron$ node ../tsync.js 
Connection :: connect
Connection :: end
Connection :: close

Client machine is Mac OS X

$ uname -a
Darwin tippy.local 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64

Server machine is Dreamhosts version of Debian

$ ssh -l user example.com uname -a
Linux cardinals 2.6.32.36-grsec #1 SMP Sun Apr 3 00:02:25 PDT 2011 x86_64 GNU/Linux

Reverse SSH Tunneling

Hello, is it possible to do a reverse SSH? ssh -R port:address:port user@remoteAddress ?

SSH Tunneling

So starting to grok the underlying stream passing between Connection, Channel and ChannelStream, but still unsure how to implement this correctly.

My approach was to allow Connection instances to accept a stream to replace this._sock in .connect(), but that doesn't seem to be working as I expected: https://github.com/indexzero/ssh2/compare/proxy-command

This was how I was testing it. I'm really not sure if I should be calling conn.exec() or conn.shell() here to use stdio as a duplex pipe as is done in ssh -o ProxyCommand ... examples.

var fs = require('fs'),
    Connection = require('ssh2');

var conn = new Connection();

function logSsh(obj, name) {
  obj.on('connect', function ()    { console.log(name + ' :: connect'); });
  obj.on('error',   function (err) { console.log(name + ' :: error :: ' + err); });
  obj.on('end',     function ()    { console.log(name + ' :: end');   });
  obj.on('close',   function ()    { console.log(name + ' :: close'); });
}

function logStream(stream, conn, name) {
  stream.on('data', function(data, extended) {
    console.log(name + (extended === 'stderr' ? ' STDERR: ' : ' STDOUT: ')
                + data);
  });
  stream.on('end', function() {
    console.log(name + ' Stream :: EOF');
  });
  stream.on('close', function() {
    console.log(name + ' Stream :: close');
  });
  stream.on('exit', function(code, signal) {
    console.log(name + ' Stream :: exit :: code: ' + code + ', signal: ' + signal);
    conn.end();
  });
}

logSsh(conn, 'Connection')

conn.on('ready', function () {
  console.log('Connection :: ready');

  //
  // Use an interactive shell to nc
  //
  conn.exec('nc dest.host 22', function (err, tunnelStream) {
    if (err) throw err;
    logStream(tunnelStream, conn, 'Connection');

    var tunnel = new Connection();

    logSsh(tunnel, 'Tunnel')

    tunnel.connect({
      host: 'dest.host',
      port: 22,
      username: 'root',
      debug: function (msg) {
        console.log('Tunnel: ' + msg);
      },
      privateKey: require('fs').readFileSync('/path/to/key'),
      stream: tunnelStream
    });

    tunnel.exec('ls -la /root', function (err, stream) {
      if (err) throw err;
      logStream(stream, tunnel, 'Tunnel');
    })
  });
});

conn.connect({
  host: 'tunnel.dest',
  port: 22,
  username: 'root',
  debug: function (msg) {
    console.log('Connection: ' + msg);
  },
  privateKey: require('fs').readFileSync('/path/to/key'),
});

from: https://gist.github.com/4508734

The output to the above is (when using real tunnel.host and dest.host values):

Connection :: connect
Connection :: ready
Tunnel :: connect
Tunnel :: error :: Error: Disconnected by host (PROTOCOL_ERROR): protocol error: rcvd type 90
Tunnel :: end
Tunnel :: close

Would love to get this working. It's the only thing that it blocking us from using this in pkgcloud.

Possible memory leak in ssh.exec

When running this code system eventually runs out of memory:

ย setInterval(function() {
ย  ย  ย  ย ssh.exec("ls ~", function(err, stream) {
ย  ย  ย  ย  ย  ย if (err) throw err;
ย  ย  ย  ย });
ย }, 1000);

exit event not always delivered in case of exec failure

When a remove command (via Session.exec) fails, sometimes (5% - 10%), the failure exit code is not reported by ssh2. I am using:

    "ssh2": "0.1.12",

Here is a successful log (command failure successfully reported):

novacom.spec info Session#_run() (stderr) sh: can't create /dev/null/mocha90693: nonexistent directory
novacom.spec verb Session#_run() ssh: EOF
novacom.spec verb Session#_run() ssh: exit code=1, signal=undefined
novacom.spec verb Session#_run() ssh: close, arguments={}

Here is a failure log (command failure not reported):

novacom.spec info Session#_run() (stderr) sh: 
novacom.spec info Session#_run() (stderr) can't create /dev/null/mocha90704:    nonexistent directory
novacom.spec info Session#_run() 
novacom.spec verb Session#_run() ssh: EOF
novacom.spec verb Session#_run() ssh: close, arguments={}

Two more notes:

  1. The error above happens when the event on stderr is broken-down into two pieces (first one being "sh: ", second one being "can't create /dev/null/mocha ..."
  2. The exit event is never delivered in case of success (exit code == 0).

I am not sure wether those are related to the main issue or not.

How to connect without passphrase?

I'm trying to understand why the following command:

ssh 192.168.100.100

works without prompting for a passphrase (using id_rsa as my key, and with id_rsa.pub in the target machines authorized_keys), but connecting with SSH2 doesn't work unless I include the passphrase option.

...
c.connect({
    host: '192.168.100.100',
    privateKey: require('fs').readFileSync('/Users/me/.ssh/id_rsa')
});

Hangs on Windows

ssh2 installed fine on Windows, but when I tried running the uptime example it seems to hang after connecting before timing out. Here is the output:

Connection :: connect
Connection :: end
Connection :: close

Using Node 0.8.4. Windows 7.

Password auth failed on mac os

Trying to connect to localhost with password (and tryKeyboard option set to true), but the connection process is hanging.

Im running Mac os 10.8.2, ssh2(master), node v0.8.16

Connection :: connect
DEBUG: Parser: STATE_INIT
DEBUG: Parser: STATE_GREETING
DEBUG: Parser: STATE_HEADER
DEBUG: Parser: STATE_PACKETBEFORE (expecting 8)
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 896
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: KEXINIT
DEBUG: Parser: STATE_PACKETBEFORE (expecting 8)
DEBUG: Connection: Sent KEXINIT
DEBUG: Connection: Sent KEXDH_INIT
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 824
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: KEXDH_REPLY
DEBUG: Connection: Sent NEWKEYS
DEBUG: Parser: STATE_PACKETBEFORE (expecting 8)
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 8
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: NEWKEYS
DEBUG: Connection: Sent SERVICE_REQUEST
DEBUG: Parser: STATE_PACKETBEFORE (expecting 16)
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 16
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: hmacSize === 16
DEBUG: Parser: STATE_PACKETDATAVERIFY
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: SERVICE_ACCEPT
DEBUG: Connection: Sent USERAUTH_REQUEST (password)
DEBUG: Parser: STATE_PACKETBEFORE (expecting 16)
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 32
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: hmacSize === 16
DEBUG: Parser: STATE_PACKETDATAVERIFY
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: USERAUTH_FAILURE
DEBUG: Connection: Sent USERAUTH_REQUEST (keyboard-interactive)
DEBUG: Parser: STATE_PACKETBEFORE (expecting 16)
DEBUG: Parser: STATE_PACKET
DEBUG: Parser: remainLen === 32
DEBUG: Parser: STATE_PACKETDATA
DEBUG: Parser: hmacSize === 16
DEBUG: Parser: STATE_PACKETDATAVERIFY
DEBUG: Parser: STATE_PACKETDATAAFTER, packet: undefined
DEBUG: Parser: STATE_PACKETBEFORE (expecting 16)

Any libraries with higher-level primitives out there?

Just a question to see if anyone involved in this repo is aware of a project built on top of this providing higher level operations such as a 1-liner to copy a local file to a remote server and so forth. Didn't find any when I web searched, but thought I'd post an issue since finding something suitable to use/build on might save me some busywork.

SSH forwardOut Question

Is it possible setup forwardOut so all TCP traffic is forwarded from the local port to the remote one or does everything have to be written to the channel in order for the forwarding to work?

I'm trying to use the library inside node-webkit (mix of node and client-side javascript). I'd like to setup ssh port forwarding and then forward web socket traffic through the tunnel.

Closing SFTP connection after WriteStream

This is probably just me doing something wrong, but I am trying to copy over a file from my local machine to a remote machine over SFTP. The file gets sent OK, but I can't close the connection, so it just hangs.

Heres what I am doing:

    var c = new Connection();
    c.on('connect', function () {
      console.log('Connection :: connect');
    });
    c.on('ready', function () {
      console.log('Connection :: ready');
      c.sftp(function (err, sftp) {
        if (err) throw err;
        sftp.on('end', function () {
          console.log('SFTP :: SFTP session closed');
        });
        sftp.on('close', function () {
          console.log('SFTP :: close');
          sftp.end();
        });

        var from = fs.createReadStream('grunt.js');
        var to = sftp.createWriteStream('grunt.js');

        from.on('close', function(){
          console.log('end from');
          sftp.end();
        });
        to.on('close', function(){
          console.log('end to');
          sftp.end();
        });

        from.pipe(to);
        });
    });
    c.on('error', function (err) {
      console.log('Connection :: error :: ' + err);
    });
    c.on('end', function () {
      console.log('Connection :: end');
    });
    c.on('close', function (had_error) {
      console.log('Connection :: close');
    });
    c.connect({
      host: '...',
      port: 22,
      username: '...',
      password: '...'
    });

The output looks like:

Connection :: connect
Connection :: ready
end from
end to
SFTP :: SFTP close

Then it just hangs.

I have tried some variations on this, using different events on the streams (such as end), but haven't worked out how to properly close the connection once the file has been transferred.

Am I doing something wrong?

Thanks again.

cd command not worked

On ready event i do following:

    c.exec('cd /var/www/site',function(err,stream){
    if (err) throw err;

    stream.on('data',function(){
        console.log(data.toString());
    });

    stream.on('exit',function(){
        c.exec('git pull',function(err,_stream){
            if (err) throw err;
            _stream.on('data',function(data){
                console.log(data.toString());
            });
        });
    });
});

it return - fatal: Not a git repository (or any of the parent directories): .git
(site folder is git repository)
So, i think cd command not worked

how much effort to add server-side ssh2

hi. have you done any thinking as to what has to be added to the module in order to have a minimal server? i'm interested in doing the work, but wouldn't like to duplicate any effort. any comments? thanks!

createWriteStream in recent release may have encoding issue (more bytes written than sent)

I have been using the ssh2 library for about 6 months now to SFTP files onto a remote server via SSH.

I typically use code like the following:

conn.sftp(
    function (err, sftp) {
        if ( err ) {
            console.error( "[%s] Error, problem starting SFTP: %s", ip, err );
            process.exit( 3 );
        }

        if ( options.debug ) {
            console.error( "[%s] SFTP started", ip );
        }

        // start upload
        var readStream = fs.createReadStream( localFileName );
        var writeStream = sftp.createWriteStream(
            remoteFileName,
            { flags: 'w', encoding: null, mode: 0666 }
        );

        writeStream.on(
            'close',
            function () {
                if ( options.debug ) {
                    console.error( "[%s] end transfer of \"%s\"", ip, localFileName );
                }
                sftp.end();
                process.exit( 0 ); // all done
            }
        );

        readStream.pipe( writeStream );
    }
);

This has been working fine for me for some months. However a few days ago I installed the latest ssh2 using npm onto a different machine.

When I tried to upload a .jar file of 824961 bytes the resulting file size on the remote system was 1611393 bytes. I tried lots of different encoding methods but couldn't transfer the binary file properly.

Finally I rsync'd the older ssh2 library from another machine, re-ran the script, and finally it uploaded correctly with the right file size.

So something has broken in the write stream. I tested, by listening to the 'data' event on the read stream, the number of bytes read which was correct. So I can only assume something has broken in the write stream.

Sorry I can't provide more information on where the bug lies.

Details of working library: from package.json was ssh2 version 0.1.13 (last modified 9 February 2013).

NPM Version

Could you please push a new version to NPM containing the exec pty change.

Keep connection open and periodically run command

Hi,

I'm trying to open an SSH connection, then keep the connection open and use setInterval to periodically run an ssh command rather than connecting then disconnecting each time.

Where is the best place to insert setInterval based on the following code:

var Connection = require('ssh2');

function command(command, host) {

    var c = new Connection();
    c.on('connect', function() {
        console.log('Connection :: connect');
    });
    c.on('ready', function() {
        console.log('Connection :: ready');


        c.exec(command , function(err, stream) {
            if (err) throw err;
            stream.on('data', function(data, extended) {
                console.log((extended === 'stderr' ? 'STDERR: ' : 'STDOUT: ') + 'command= '+ data);
            });

            stream.on('end', function() {
                console.log('Stream :: EOF');
            });
            stream.on('close', function() {
                console.log('Stream :: close');
            });

            stream.on('exit', function(code, signal) {
                console.log('Stream :: exit :: code: ' + code + ', signal: ' + signal);
                c.end();
            });
        })

    });

    c.on('error', function(err) {
        console.log('Connection :: error :: ' + err);
    });
    c.on('end', function() {
        console.log('Connection :: end');
    });
    c.on('close', function(had_error) {
        console.log('Connection :: close');
    });
    c.connect({
        host: host,
        port: 22,
        username: 'carl',
//        privateKey: require('fs').readFileSync('/Users/carl/.ssh/id_rsa')
        password: '1234'
    });

};


Tunnel with forwardOut question.

Hi,

First I wanted to say that I am loving this library. Fantastic work!!

I have a question because I have a server at a remote location that I would like to tunnel through to. I'm not sure that it's that unusual and I'm pretty sure I must be missing something here. There is a firewall in between that uses a key on port 222. Anyway, the way I normally do it is with a command like:

ssh -L localhost:2221:[SERVER IP]:22 -p 222 [F/WALL UNAME]@[F/WALL IP]

Then I just ssh into it:

ssh -p 2221 [SERVER UNAME]@localhost

This is an example of what I'm trying to do.

var  fs = require('fs'),
     Connection = require('ssh2');

var c1 = new Connection();

c1.connect({
  host: '[F/WALL IP]', 
  port: 222, 
  username: '[F/WALL UNAME]', 
  privateKey: require('fs').readFileSync('./keys/sample.key') 
});

c1.on('ready', function(){
  c1.forwardOut('localhost', 2221, '[SERVER IP]', 22, function(err, stream) {

    if(err) throw err;
    console.log('ForwardOut Ready!');

    var c2 = new Connection();

    c2.connect({
      host: 'localhost', 
      port: 2221, 
      username: '[SERVER UNAME]', 
      password: '[SERVER PASSWORD]' 
    });

    c2.on('ready', function(){
      console.log('Connected!');
    });

    c2.on('error', function(err) {
      console.log('Connection :: error :: ' + err);
    });
  })
});

c1.on('error', function(err) {
  console.log('Connection :: error :: ' + err);
});

The ouput I get is:

ForwardOut Ready!
Connection :: error :: Error: connect ECONNREFUSED

Is there anything glaring that you can see I'm missing?

Cheers,
Paul

ReferenceError: remotepath is not defined SFTP.fastGet (/lib/SFTP/SFTPv3.js:280:13)

the error like:
/home/wul/node_modules/ssh2/lib/SFTP/SFTPv3.js:280
self.stat(remotepath, function(err, attrs) {
^
ReferenceError: remotepath is not defined
at SFTP.fastGet (/home/wul/node_modules/ssh2/lib/SFTP/SFTPv3.js:280:13)
at /home/wul/zone/deploy-it/ssh.js:29:18
at SFTP._parse (/home/wul/node_modules/ssh2/lib/SFTP/SFTPv3.js:944:13)
at ChannelStream. (/home/wul/node_modules/ssh2/lib/SFTP/SFTPv3.js:49:12)
at ChannelStream.EventEmitter.emit as _emit
at ChannelStream.emit (/home/wul/node_modules/ssh2/lib/Channel.js:529:12)
at Parser. (/home/wul/node_modules/ssh2/lib/Channel.js:76:20)

it cause by it is "remotePath" in line 243 in lib/SFTP/SFTPv3.js, but 280 is "remotepath".

How to pipe data through ssh connection ?

I am trying to read a file from my local computer and write it to a remote computer using ssh.

    var Connection = require('ssh2');
    var BufferedStream = require('buffered-stream');

    function readFile(filepath, startOffset, outputStream) {
        var fileSize = fs.statSync(filepath).size;
        var length = fileSize - startOffset;
        var myFD = fs.openSync(filepath, 'r');
        var readable = fs.createReadStream(filepath, {
            fd: myFD, start: startOffset, end: fileSize, autoClose: true
        })
        return readable;
    }
    function connectSSH(remoteServer, remoteUser, identityFile){
        var c = new Connection();
        c.on('connect', function() {
          console.log('Connection :: connect');
        });
        c.on('ready', function() {
          console.log('Connection :: ready');
          c.shell('', function(err, stream) {
            if (err) throw err;
            stream.on('data', function(data, extended) {
              console.log((extended === 'stderr' ? 'STDERR: ' : 'STDOUT: ')
                          + data);
            });
            stream.on('end', function(code, signal) {
              console.log('Stream :: EOF', code, signal);
            });
            stream.on('close', function(code, signal) {
              console.log('Stream :: close', code, signal);
            });
            stream.on('exit', function(code, signal) {
              console.log('Stream :: exit :: code: ' + code + ', signal: ' + signal);
              c.end();
            });
            stream.on('drain', function() {
              console.log('Stream :: drain');
            });

            var bufferStream = new BufferedStream(4*1024*1024);
            bufferStream.pipe(stream);
            stream.write('cat - >> myRemoteFile.txt');
            readable = readFile('./myLocalFile.txt', 0, bufferStream);
            readable.once('end', function(){
                    console.log("ENDED");
            });
            readable.pipe(bufferStream).pipe(stream);
          });
        });
        c.on('error', function(err) {
          console.log('Connection :: error :: ' + err);
        });
        c.on('end', function() {
          console.log('Connection :: end');
        });
        c.on('close', function(had_error) {
          console.log('Connection :: close');
        });
        c.connect({
          host: remoteServer,
          port: 22,
          username: remoteUser,
          privateKey: require('fs').readFileSync(identityFile)
        });
    }

This does not work (It outputs the file content to remote stdout) and I wonder if you could give me a lead for this ?

I use shell() function : should I use exec() and how ?

How to make a pipe ? Using signal('PIPE') ? But then on which object call this function ?

Also, I need to send some commands, retrieve their output and then send again commands according to the ouptut. I guess this is the same type of problem.

Can't get agent option to work

I haven't been able to get the "agent" option to work...

When passing:

{ hostname: hostname, 
  username: username, 
  agent: process.env.SSH_AUTH_SOCK }

I see this error.

node_modules/ssh2/lib/Connection.js:1008
  if (!this._privateKey.public) {

TypeError: Cannot read property 'public' of undefined

When passing in a username and password, I've been able to successfully make a connection.

Exec cmd via bash

I'm trying to using ssh2 exec some command, all basic cmd working perfact like: "ls", "uptime"....

But when I exec "node --version", it's show me that "node: command not found".

Then I found it's because the exec didn't use bash as the shell to exec the cmd.

So is there any way I can set using bash to exec cmd?

Interactive usage

Hi,

Could you provide some guidance on the usage of the "tryKeyboard" option and the "keyboard-interactive" event.

c = new Connection()
c.on 'ready', ->
  console.log 'Connection :: ready'
c.on 'keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) ->
  console.log '>>', name, instructions, instructionsLang, prompts
c.connect 
  host: hostname
  username: username
  tryKeyboard: true

Thanks,
d.

scp support

Apologies if this is a n00b question, but I'm unfamiliar with the differences between sftp and scp.

Does ssh2 support scp currently? If not, do you plan to?

SFTP readdir() Fails on WS_FTP server v7.5

It hangs indefinitely. Connecting and reading specific files works fine. After a quick round of debugging, the data is being received, but looks like its never completing. Works fine using the command line sftp client. Let me know if I can provide debug info from the server I'm working with.

Cannot set stats of uploaded file either via setstat or open/write

I'm writing a tool to synchronize files to a server (node-ssh2sync) and one thing I want is to set the file create/access/modify times to match those on my laptop.

The attributes object isn't documented .. so I'm guessing that the fields required would be the same as returned by fs.stat or sftp.stat.

Hence,

sftp.mkdir(remotedir, {
                                ctime: statz.ctime,
                                atime: statz.atime,
                                mtime: statz.mtime
                            }, function(err) {

or

sftp.setstat(remotedir, {
                                        ctime: statz.ctime,
                                        atime: statz.atime,
                                        mtime: statz.mtime
                                    }, function(err) {
                                        doit(root_local, root_remote, sftp, thepath, function(err) {
                                            if (err) cb(err); else cb();
                                        });
                                    });

Visit my repository to see the exact script ..

Open env in exec causes crash

Using node 10.0.9, while this is working:

c = new Connection()
c.on 'ready', () ->
  c.exec 'uptime', {env:{}}, (err, stream) ->
    stream.on 'data', (data, extended) ->
      console.log data.toString()
    stream.on 'exit', (code, signal) ->
      c.end()
c.connect {}

The following:

c = new Connection()
c.on 'ready', () ->
  c.exec 'uptime', {env:{http_proxy:'...'}}, (err, stream) ->
    stream.on 'data', (data, extended) ->
      console.log data.toString()
    stream.on 'exit', (code, signal) ->
      c.end()
c.connect {}

Generate an error:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: write EPIPE
  at errnoException (net.js:884:11)
  at Object.afterWrite (net.js:701:19)

Trying to digg into the code, but this might be a bit hard to get.

Latest Connection.js uses MESSAGE before MESSAGE defined

I checked out the latest ssh2 and got the following error:

/usr/local/node/tmp/ssh2/lib/Connection.js:19
    PING_PACKET = new Buffer([MESSAGE.IGNORE, 0, 0, 0, 0]),
                                 ^
TypeError: Cannot read property 'IGNORE' of undefined
    at Object.<anonymous> (/usr/local/node/tmp/ssh2/lib/Connection.js:19:38)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/tmp/launcher.js:5:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)

This error does not appear in the commit before (6018e0f). It appears commit 38816b2 is at fault.

Looking at the code of lib/Connection.js it appears that line was moved:

PING_PACKET = new Buffer([MESSAGE.IGNORE, 0, 0, 0, 0]),

but this now appears ABOVE the definition of MESSAGE instead of BELOW it as before:

MESSAGE = consts.MESSAGE,

Question: Auth with SSH Agent

Can you provide an example of authentication with an SSH agent?

I'm having trouble getting it working, persistently getting:

Connection :: connect
Connection :: error :: Error: Authentication failure. Available authentication methods: undefined
Connection :: close

I'm providing the path to the SSH Agent socket, and other details:

c.connect({
  host: 'some-server.com',
  port: 22,
  username: 'me',
  agent: "/path/to/agent/socket",
});

Platform is OSX (perhaps this isn't supported?)
node.js 0.8.18

Any suggestions/help would be appreciated!

mkdir creates folder with with wrong permissions

Hey,
I'm trying to deploy an application over ssh2. But when creating folder on the server they always have the wrong permissions.
I do call it in the following way: sftpConn.mkdir(remotePath, {mode: '775'}, function(err) {}
but the folder always has the permissions 405.
Am I simply using it wrong?

Edit: Tried it sometimes but then it suddenly worked. \o/ computers

Failed to ssh with password

I followed sample code, but saw this error

{ [Error: Authentication failure. Available authentication methods: publickey,keyboard-interactive] level: 'authentication', partial: false }

Should I use tryKeyboard?

bad sigbloblen when using keyauth

Hello when using private/public (dsa) key see the following error on the sshd side:

fatal: bad sigbloblen 0 != SIGBLOB_LEN

Connect options:
{
host: 'xxx',
port: 22,
username: 'someone',
passphrase: 'xxx',
privateKey: fs.readFileSync('.../id_dsa'),
publicKey: fs.readFileSync('.../id_dsa.pub')
}

--- progress (with debug callback)
Connection :: connect
header [object Object] undefined
packet KEXINIT 20
packet KEXDH_REPLY 31
packet NEWKEYS 21
packet SERVICE_ACCEPT 6
packet undefined 60
Connection :: end

Connection :: close false

Hard time figuring out how to use sftp.mkdir

It isn't clear about the usage of mkdir, also, the doc suggest 2 arguments (path and callback) while source code take an additionnal attributes arguments which doesn't seem to be optional. Maybe creating a samples directory could help.

Thanks for this library. I was looking for it for the last 2 years.
d.

Send pty commands like resize

Would it be possible to send resize commands to the remote shell? I want to pair this with a terminal emulator that runs in a browser. I can detect resizes on the client just fine and resize my tty emulator, but I also need to tell the shell that the pty is the new size. Can this be done using just data over the tty stream or does it need to be controlled at the pty level?

Exec not working correctly with & every now and then.

I'm running this command specifically:

cd ~/dir1/dir2 ; LD_LIBRARY_PATH=../lib/ ../bin/node app.js run &

This seems to work 50%ish of the time. When it doesn't work, I get no stdout or stderr. When it does work, I get stdout as expected.

It always seem to work without &

If I run it through ssh directly, the command with & works 100% of the time.

Essentially I get

stream: exit (no signal name set, only program return value, and it's 0)
stream: close

instead of

stream:data (expected data.)
stream:exit (no signal name set, only program return value, and it's 0)
stream:close

Got any idea's to why this happens? (is & suppose to work properly?)

handling sudo interactive password requests

Any guidance on how to go about executing sudo on the remote server and dealing with interactive password prompts? Ideally I'd like to do the prompting on the client side and allow interactive authentication to work (basically shooting for how Fabric does this in python), but I'm not sure if A) I need to force tty creation during the connection (and if so, how would I do that as I don't see any connection config option) or B) whether I can specify an "askpass" program on the remote side and somehow wire that up to the ssh2 session or C) something else entirely or D) this is sufficiently nontrivial that I should consider alternatives.

As I would mostly expect, currently running a remote sudo results in:

sudo: no tty present and no askpass program specified
Sorry, try again.
sudo: no tty present and no askpass program specified
Sorry, try again.
sudo: no tty present and no askpass program specified
Sorry, try again.
sudo: 3 incorrect password attempts

Large, quick buffers seem to crash the readable stream

Hello,

My application is set up roughly like so:

server.js: Sits at a central server and is capable of reaching out to many of several servers via SSH
interface.html: Sits on the central server and communicates via socket.io to server.js.

I use ssh2 to handle communication with servers via SSH, e.g.:

socket.on('connect_to_box', function(data) {
...
ssh_stream = new ssh2();
ssh_stream.on('ready', function() {
ssh_stream.shell(function(err, stream) {
stream.on('data', function(data) {
socket.emit(data);
});
});
...
});

socket.on('ssh_command', function(command) {
ssh_stream.write(command + '\n');
});

The idea being that I send commands via the HTML interface over websockets; the server relays those commands via ssh2 and pipes the output back.

This all works beautifully! Except, sometimes, if I do something somewhat bulky (like run "ls -al" on a directory with a hundred items, or run "ps ax" a couple times, or if I'm tailing network traffic and it's particularly speedy), something peculiar happens -- the server.js's stream stops receiving SSH output. I can still write to it, which I verified by creating files blindly, but server.js no longer gets "data" events in its stream.

Any ideas why this might occur?

Upload of a 0 byte file fails

In my file synchronize tool (https://github.com/robogeek/node-ssh2sync) I had to work around a zero length file issue.

I'm doing

fs.readFile(localfile, function(err, data) {

followed by

sftp.write(handle, data, 0, data.length, 0, function(err) {

But was given an error about the offset being out of bounds. Well, yes, it is a zero length file, so therefore data.length is zero. Seems to me it shouldn't throw an error but should just go about writing a 0 length file on the server. FWIW the file does get created.

In my script I'm testing for 0 length buffer and handling it this way

if (data.length === 0) {
                                            closehandle(handle, remotefile, statz, cb);
                                        } else {
                                            sftp.write(handle, data, 0, data.length, 0, function(err) {
                                                if (err) {
                                                    cb(err);
                                                } else {
                                                    closehandle(handle, remotefile, statz, cb);
                                                }
                                            });
                                        }

Hangs on fully-patched Ubuntu 12.10

First sample app hangs:

Connection :: ready
STDOUT:  17:44:44 up 82 days, 15:59,  2 users,  load average: 7.95, 6.20, 5.71

Stream :: exit :: code: 0, signal: undefined
Stream :: EOF
Stream :: close
Connection :: end
Connection :: close
{ [Error: connect ETIMEDOUT] code: 'ETIMEDOUT', errno: 'ETIMEDOUT', syscall: 'connect' }

Node: v0.8.18
OpenSSL: v1.0.1c

Cannot get the stream content

I cannot get the 'uptime executionREADME example' work from a windows host to a server using a password.
What I get is like the answer stream is empty, but it isn't:
Connection :: connect
Connection :: ready
Connection :: end
Connection :: close

BTW, I use nodejs v0.10.4
Pascal

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.