I'm using ssh2 nodejs client (https://github.com/mscdex/ssh2)
I'm trying to do the following:
SSH into box.
Login to docker.
It will re-prompt for password. Enter that password.
I'm failing on 3rd step.
This is my code
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.exec('sudo docker ps', {pty: true}, function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
conn.end();
// data comes here
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
// stream.end(user.password+'\n');
^^ If i do this, it will work but I won't be able to do anything else afterwards
});
}).connect({
host: 'demo.landingpage.com',
username: 'demo',
password: 'testuser!'
});
How do I enter the password programmatically? (I'm already using {pty: true} while doing conn.exec
Please enlighten!
Assuming your stream is a duplex stream, you have the possibility to write into the stream without ending it by writing
.on('data', (data) => {
stream.write(user.password+'\n');
}
or you can use an cb function
function write(data, cb) {
if (!stream.write(data)) {
stream.once('drain', cb);
} else {
process.nextTick(cb);
}
}
and
.on('data', (data) => {
write(user.password+ '\n', () => {
console.log('done');
}
});
Related
I am using Socket.io to send login credentials for SSH, from React to Node and I want to make an interactive application where I can send the command from client side and display the output on React.
I used Connecting to remote SSH server (via Node.js/html5 console) for initially understanding the structure.
I used one component to enter the login credentials and then open a Popup where I am sending socket information as props and then use props.socket to send the command and get the output. But I am not getting the output from the socket. I believe there is no issue with the React side since I used console.log after stream.on('data', (data) => ).
server.js
io.on("connection", (socket) => {
const conn = new SSHClient();
socket.on("send_message", (login) => {
conn.on('ready', () => {
socket.emit('receive_message', 'true');
conn.shell(function (err, stream) {
console.log('in shell')
return socket.emit('data', '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
socket.on('data', (command) => {
console.log('Sending command', command)
stream.write(command);
});
stream.on('data', function (d) {
console.log('Getting output from stream', d.toString('binary'))
socket.emit('data', d.toString('binary'));
}).on('close', function () {
conn.end();
});
});
}).on('close', function() {
socket.emit('data', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
}).on('error', function(err) {
socket.emit('data', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
}).connect(login);
})
})
Login.js
const submitAction = () => {
let loginData = {host: environment.value, username: username, password: passcode };
socket.emit("send_message", loginData);
};
useEffect(() => {
socket.on("receive_message", (data) => {
if (data==='true')
setOpenConfirm(true)
});
}, [socket]);
Popup.js
const sendMsg = (command) => {
props.socket.emit("data", command);
setLoading(false);
};
useEffect(() => {
if (loading)
sendMsg(command)
}, [loading]);
useEffect(() => {
props.socket.on("data", (data) => {
setDataReceived(data);
setLoading(false)
});
}, [props.socket]);
So, currently, I am able to login, open the popup and I am receiving the command in socket. But the stream.out is again giving the command instead of the output.
I'd really appreciate any explanation or debugging my code.
Thank you
how to return the values (data) of the getData function bellow?
const { Client } = require('ssh2');
const conn = new Client();
function getData() {
//i tried to assign the data to a variable but failed
//var rawData = '';
conn.on('ready', () => {
conn.exec('pwd', (err,stream)=>{
if (err) throw err;
stream.on('data',(data)=>{
//the console successfully displayed - the current path
console.log('Output:' + data);
//if i return the data here the output was undefined
//return data
});
stream.stderr.on('data',(data)=>{
});
stream.on('close',(code,signal)=>{
conn.end();
});
//if i tried to get the data values here, it threw "unhandled 'error' event", so i would not possible to return the data here.
//console.log(data);
});
}).connect({
host: 'myserver',
port: 22,
username: 'root',
password: 'roots!'
});
}
getData();
consoling out from inside stream is success, but how to return the data?
i tried to assign the data to variable (rawaData), but confusing where to put the 'return' code.
You can use a promise to communicate back the final result:
function getData() {
return new Promise((resolve, reject) => {
let allData = "";
conn.on('ready', () => {
conn.exec('pwd', (err, stream) => {
if (err) {
reject(err);
conn.end();
return;
}
stream.on('data', (data) => {
allData += data;
});
stream.on('close', (code, signal) => {
resolve(allData);
conn.end();
});
stream.on('error', reject);
});
}).connect({
host: 'myserver',
port: 22,
username: 'root',
password: 'roots!'
});
});
}
getData().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});;
I am trying to find out the pid of the ssh2 connection and its process. I connect a remote computer and start a process. I am using npm ssh2 library.
Here is my code;
This is in an HTTP query and I need to learn pid of the process because in another HTTP query I need to shut down this process by using pid .
try {
conn.on('ready', () => {
console.log('Client :: ready');
conn.shell((error, stream ) => {
if (error) throw error;
stream.on('close', () => {
console.log('Stream :: close');
conn.end();
}).on('data', (data) => {
console.log('OUTPUT: ' + data);
res.write('OUTPUT: ' + data)
setTimeout(() => {
res.end()
}, 7000);
});
stream.write('cd .. \n');
stream.write('source /opt/ros/melodic/setup.bash \n');
stream.write('cd home/catkin_ws \n');
stream.write('source devel/setup.bash \n');
stream.end('roslaunch package sample.launch \n');
});
}).on('error', (error) => {
res.write(error.message);
res.end()
console.log(error)
}).connect({
host: ip_address,
port: 22,
username: 'root',
password: 'password',
});
} catch (error) {
console.log(error)
res.status(405).send(error)
}
I've tried so much but I couldn't find. Thank you so much for your help.
I am trying to read data in stream from a remote server log file, which is continuously growing. I want to display the new lines added to my local console. I am using ssh for connection from local to remote server.
I found below solution on github which is writing local file content to remote file but i want in other way. Not getting an idea to convert this in reverse direction.
var Connection = require('ssh2');
var fs = require('fs');
var BufferedStream = require('buffered-stream');
console.log('sshstream started')
connectSSH();
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(){
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 - >> /home/username/mylog.log');
readable = readFile('test.log', 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: 'xx.xxx.xx.xxx',
port: 22,
username: 'username',
password: 'password'
});
}
Please suggest
Thanks
This works and it could be customized as you wish.
'use strict';
const SSH = require('simple-ssh');
function run(sshConfig, script) {
return new Promise((resolve, reject) => {
let scriptOutput = '';
const sshFtw = new SSH(sshConfig);
sshFtw.exec(script,
{ out: console.log.bind(console) })
.on('error', (err) => reject(err))
.on('close', () => resolve(scriptOutput))
.start();
});
};
run({
"host": "1.2.3.4",
"user": "my-user",
"pass": "my-psw"
}, 'tail -f /home/my-app/log/api-out.log');
var exec = require('child_process').exec;
exec('ssh my_ip',function(err,stdout,stderr){
console.log(err,stdout,stderr);
});
This just freezes - I guess, because ssh my_ip asks for password, is interactive, etc. How to do it correctly?
There's a node.js module written to perform tasks in SSH using node called ssh2 by mscdex. It can be found here. An example for what you're wanting (from the readme) would be:
var Connection = require('ssh2');
var c = new Connection();
c.on('connect', function() {
console.log('Connection :: connect');
});
c.on('ready', function() {
console.log('Connection :: ready');
c.exec('uptime', function(err, stream) {
if (err) throw err;
stream.on('data', function(data, extended) {
console.log((extended === 'stderr' ? 'STDERR: ' : 'STDOUT: ')
+ 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: '192.168.100.100',
port: 22,
username: 'frylock',
privateKey: require('fs').readFileSync('/here/is/my/key')
});
The other library on this page has a lower level API.
So I've wrote a lightweight wrapper for it. node-ssh which is also available on GitHub under the MIT license.
Here's an example on how to use it.
var driver, ssh;
driver = require('node-ssh');
ssh = new driver();
ssh.connect({
host: 'localhost',
username: 'steel',
privateKey: '/home/steel/.ssh/id_rsa'
})
.then(function() {
// Source, Target
ssh.putFile('/home/steel/.ssh/id_rsa', '/home/steel/.ssh/id_rsa_bkp').then(function() {
console.log("File Uploaded to the Remote Server");
}, function(error) {
console.log("Error here");
console.log(error);
});
// Command
ssh.exec('hh_client', ['--check'], { cwd: '/var/www/html' }).then(function(result) {
console.log('STDOUT: ' + result.stdout);
console.log('STDERR: ' + result.stderr);
});
});
The best way is to use promisify and async/await. Example:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
export default async function (req, res) {
const { username, host, password } = req.query;
const { command } = req.body;
let output = {
stdout: '',
stderr: '',
};
try {
output = await exec(`sshpass -p ${password} ssh -o StrictHostKeyChecking=no ${username}#${host} ${command}`);
} catch (error) {
output.stderr = error.stderr;
}
return res.status(200).send({ data: output, message: 'Output from the command' });
}
Check my code:
// redirect to https:
app.use((req, res, next) => {
if(req.connection.encrypted === true) // or (req.protocol === 'https') for express
return next();
console.log('redirect to https => ' + req.url);
res.redirect("https://" + req.headers.host + req.url);
});
pure js/node way to ssh into hosts. Special thanks to
ttfreeman. assumes ssh keys are on host. No need for request object.
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
require('dotenv').config()
//SSH into host and run CMD
const ssh = async (command, host) => {
let output ={};
try {
output['stdin'] = await exec(`ssh -o -v ${host} ${command}`)
} catch (error) {
output['stderr'] = error.stderr
}
return output
}
exports.ssh = ssh