Monday, October 25, 2021

[SOLVED] ssh and nodejs application

Issue

I have a nodejs application which run some shell commands. I want to execute these commands in another machine by using ssh.

I have this:

snapInfo(snapName: string) {
    return `snap info ${snapName}`;
}

I need something like this:

snapInfo(snapName: string) {
    return `ssh user@host snap info ${snapName}`;
}

the file is a .ts file. How can I do it? Any suggestions? It's the first time I see a nodejs app.

Thanks in regard


Solution

You could use the excellent ssh2 module for Node.js.

npm install ssh2

And then you can connect to your remote system like this by adding a new function execSSHCommand which can be used instead of execCommand in the file shell-commands.ts.

import { Injectable } from '@nestjs/common';
import { promisify } from 'util';
import { exec } from 'child_process';
import { Client } from 'ssh2'

const exec_promise = promisify(exec);

function execute_over_ssh(cmd: string): Promise<{ stdout: string; stderr: string; }> {
  return new Promise<{ stdout: string; stderr: string; }>((resolve, reject) => {
    let conn = new Client();
    conn.on('ready', function () {
      let stdout = "", stderr = "";
      conn.exec(cmd, function (err, stream) {
        if (err) reject(err);
        stream.on('close', function (code, signal) {
          resolve({ stdout, stderr });
          conn.end();
        }).on('data', function (data) {
          stdout += data.toString('utf8');
        }).stderr.on('data', function (data) {
          stderr += data.toString('utf8');
        });
      });

    }).connect({ host: '127.0.0.1', port: 22, username: 'user', password: 'pass' });
  });
}


@Injectable()
export class ShellService {

  async execCommand(cmd: string, password?: string): Promise<string> {
    if (password) {
      // TODO: Possibly remove
      const command = `echo ${password} | sudo -S ${cmd}`;
      const { stdout, stderr } = await exec_promise(command);
      return stdout;
    } else {
      const command = `${cmd}`;
      const { stdout, stderr } = await exec_promise(command);
      return stdout;
    }
  }

  async execSSHCommand(cmd: string): Promise<string> {
    const command = `${cmd}`;
    const { stdout, stderr } = await execute_over_ssh(command);
    return stdout;
  }

}


Answered By - Stephen S