node-ssh

repository·main·Indexed 21 days ago

https://github.com/steelbrain/node-ssh

A Promise-based wrapper around the 'ssh2' library for Node.js. It provides a simplified API for SSH operations, including command execution via execCommand and exec, file and directory transfers (SFTP), port forwarding (TCP and Unix sockets), and shell session management. Supports TypeScript and keyboard-interactive authentication.

Tokens
2.6K
Snippets
11
Records
12
Agent score
27%

What's inside node-ssh

  1. Set up node-ssh with TypeScript support

    main

    node-ssh requires @types/ssh2 for TypeScript support. Install it as a development dependency.

    # Using npm
    npm install --save-dev @types/ssh2
    
    # Using yarn
    yarn add --dev @types/ssh2

    If you encounter issues, ensure your tsconfig.json includes the following settings:

    {
      "compilerOptions": {
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true
      }
    }
    npm install --save-dev @types/ssh2
  2. Handle keyboard-interactive authentication

    main

    If your server requires keyboard-interactive authentication, set tryKeyboard: true in your connection config. You can also provide a custom onKeyboardInteractive handler to respond to specific prompts.

    ssh.connect({
      host: 'localhost',
      username: 'steel',
      port: 22,
      password: 'test',
      tryKeyboard: true,
      onKeyboardInteractive(name, instructions, instructionsLang, prompts, finish) {
        if (prompts.length > 0 && prompts[0].prompt.toLowerCase().includes('password')) {
          finish(['test'])
        }
      }
    })
    ssh.connect({
      host: 'localhost',
      username: 'steel',
      port: 22,
      password: 'test',
      tryKeyboard: true,
    })
  3. Connect to an SSH server with NodeSSH

    main

    To establish a connection, instantiate NodeSSH and call .connect(config). You can authenticate using a privateKeyPath or an inline privateKey (as a Buffer).

    const {NodeSSH} = require('node-ssh')
    const ssh = new NodeSSH()
    
    // Using a private key file path
    ssh.connect({
      host: 'localhost',
      username: 'steel',
      privateKeyPath: '/home/steel/.ssh/id_rsa'
    })
    
    // OR using an inline private key
    ssh.connect({
      host: 'localhost',
      username: 'steel',
      privateKey: Buffer.from('...')
    })
    const {NodeSSH} = require('node-ssh')
    const ssh = new NodeSSH()
    
    ssh.connect({
      host: 'localhost',
      username: 'steel',
      privateKeyPath: '/home/steel/.ssh/id_rsa'
    })
  4. Transfer files and directories

    main

    node-ssh supports several file transfer methods:

    • putFile(localFile, remoteFile, ...): Uploads a single file.
    • putFiles(files, options): Uploads an array of files defined as { local: string, remote: string }[].
    • getFile(localFile, remoteFile, ...): Downloads a file from the remote server.
    • putDirectory(localDirectory, remoteDirectory, options): Uploads an entire directory. Supports recursive transfers and a validate function to filter files.

    Example: Uploading a directory with validation

    ssh.putDirectory('/home/steel/Lab', '/home/steel/Lab', {
      recursive: true,
      concurrency: 10,
      validate: function(itemPath) {
        const baseName = path.basename(itemPath)
        return baseName.substr(0, 1) !== '.' && baseName !== 'node_modules'
      }
    })
    ssh.putFile('/home/steel/Lab/localPath/fileName', '/home/steel/Lab/remotePath/fileName')
  5. Execute commands on a remote server

    main

    node-ssh provides two primary ways to execute commands:

    1. execCommand(command, options): Best for simple commands. Returns a Promise resolving to an SSHExecCommandResponse containing stdout, stderr, code, and signal. By default, output is trimmed.
    2. exec(command, parameters, options): Best for commands with arguments. If options.stream is set to 'stdout', 'stderr', or 'both', it returns a Promise resolving to the output string or an SSHExecCommandResponse respectively.

    Running commands with a Pseudo-TTY

    For terminal programs like screen or tmux, pass pty: true inside execOptions.

    const result = await ssh.execCommand('screen -r', {
      execOptions: { pty: true }
    })
    // Simple command
    ssh.execCommand('hh_client --json', { cwd:'/var/www' }).then(function(result) {
      console.log('STDOUT: ' + result.stdout)
      console.log('STDERR: ' + result.stderr)
    })
    
    // Command with arguments and streaming
    ssh.exec('hh_client', ['--json'], {
      cwd: '/var/www',
      onStdout(chunk) {
        console.log('stdoutChunk', chunk.toString('utf8'))
      }
    })
  6. NodeSSH API Reference

    main

    The NodeSSH class is the primary interface for the library. Below are the key methods and their signatures.

    Core Methods

    • connect(config: Config): Promise<this>
    • isConnected(): boolean
    • dispose(): void

    Command Execution

    • execCommand(givenCommand: string, options?: SSHExecCommandOptions): Promise<SSHExecCommandResponse>
    • exec(command: string, parameters: string[], options?: SSHExecOptions & { stream?: 'stdout' | 'stderr' }): Promise<string | SSHExecCommandResponse>

    File & Directory Operations

    • mkdir(path: string, method?: SSHMkdirMethod, givenSftp?: SFTPWrapper | null): Promise<void>
    • getFile(localFile: string, remoteFile: string, givenSftp?: SFTPWrapper | null, transferOptions?: TransferOptions | null): Promise<void>
    • putFile(localFile: string, remoteFile: string, givenSftp?: SFTPWrapper | null, transferOptions?: TransferOptions | null): Promise<void>
    • putFiles(files: { local: string, remote: string }[], { concurrency, sftp, transferOptions }?: SSHPutFilesOptions): Promise<void>
    • putDirectory(localDirectory: string, remoteDirectory: string, { concurrency, sftp, transferOptions, recursive, tick, validate }?: SSHGetPutDirectoryOptions): Promise<boolean>

    Shell & SFTP

    • requestShell(options?: PseudoTtyOptions | ShellOptions | false): Promise<ClientChannel>
    • withShell(callback: (channel: ClientChannel) => Promise<void>, options?: PseudoTtyOptions | ShellOptions | false): Promise<void>
    • requestSFTP(): Promise<SFTPWrapper>
    • withSFTP(callback: (sftp: SFTPWrapper) => Promise<void>): Promise<void>
  7. Use Shell and SFTP sessions with withShell() and withSFTP()

    main

    To ensure resources are properly cleaned up, use the withShell and withSFTP helper methods. These methods automatically destroy the channel or end the SFTP session once the provided callback completes.

    • withShell(callback, options): Provides a ClientChannel to the callback.
    • withSFTP(callback): Provides an SFTPWrapper to the callback.
    // Using withSFTP for safe resource management
    await ssh.withSFTP(async (sftp) => {
      const stats = await sftp.stat('/remote/path');
      console.log(stats.size);
    });
  8. Execute commands with execCommand()

    main

    The execCommand(givenCommand: string, options?: SSHExecCommandOptions) method executes a single command and returns a promise that resolves to an SSHExecCommandResponse object containing stdout, stderr, code, and signal.

    Options:

    • cwd: The working directory for the command.
    • stdin: A string or readable stream to pass to the command's standard input.
    • onStdout / onStderr: Callbacks for receiving data chunks as they arrive.
    • noTrim: If true, prevents the automatic trimming of stdout and stderr results.
    const result = await ssh.execCommand('ls -la', { cwd: '/var/log' });
    console.log(result.stdout);
  9. Manage SSH Port Forwarding

    main

    Node-SSH supports both TCP and Unix socket forwarding:

    TCP Forwarding

    • forwardIn(remoteAddr, remotePort, onConnection?): Forwards a port from the remote server to your local machine. Returns a dispose function to stop the forwarding.
    • forwardOut(srcIP, srcPort, dstIP, dstPort): Forwards a port from your local machine to a destination via the SSH server. Returns a Channel.

    Unix Socket Forwarding

    • forwardInStreamLocal(socketPath, onConnection?): Forwards a remote Unix socket to a local socket path.
    • forwardOutStreamLocal(socketPath): Forwards a local Unix socket to the remote server.
    // TCP Forwarding In
    const { port, dispose } = await ssh.forwardIn('127.0.0.1', 8080);
    console.log(`Forwarding on local port: ${port}`);
    
    // Stop forwarding later
    await dispose();
  10. Execute commands with exec()

    main

    The exec(command: string, parameters: string[], options?: SSHExecOptions) method is a high-level wrapper for execCommand. It automatically escapes parameters to prevent shell injection.

    Return Values based on options.stream:

    • If options.stream is undefined or 'stdout': Returns a Promise<string> containing the trimmed stdout. It throws an error if stderr is not empty.
    • If options.stream is 'stderr': Returns a Promise<string> containing the trimmed stderr.
    • If options.stream is 'both': Returns a Promise<SSHExecCommandResponse> containing the full response object.
    // Returns stdout as a string
    const output = await ssh.exec('ls', ['-la', '/tmp']);
    
    // Returns full response object
    const response = await ssh.exec('git', ['status'], { stream: 'both' });
  11. Manage remote directories with mkdir()

    main

    Create directories on the remote server using mkdir(path: string, method: SSHMkdirMethod = 'sftp', givenSftp?: SFTPWrapper).

    Methods:

    • 'sftp' (default): Uses the SFTP protocol. It will attempt to create parent directories recursively if they do not exist.
    • 'exec': Uses a shell command (mkdir -p) to create the directory.

    If you are performing multiple directory operations, passing an existing SFTPWrapper via givenSftp is more efficient as it avoids re-establishing an SFTP session.

    // Using SFTP (default)
    await ssh.mkdir('/home/user/new_folder/sub_folder');
    
    // Using exec
    await ssh.mkdir('/home/user/new_folder', 'exec');