Interactive session of Socket.io with SSH from Node.js and React - node.js

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

Related

How to avoid executing same shell command multiple times in NodeJS?

I have module which executes a shell command when user clicks submit on the UI,but the problem here is that at the time of clicking submit command:
number of times command executed= number of tabs that this UI is being opened while clicking submit button
Server side code:
const wsServer = new WebSocket.Server({
noServer: true,
});
wsServer.on("connection", function (ws) {
ws.on("message", function (msg) {
wsServer.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
var coffeeProcess = exec(msg.toString());
coffeeProcess.stdout.on("data", function (data) {
console.log(data);
client.send(data);
});
}
});
});
});
myServer.on("upgrade", async function upgrade(request, socket, head) {
//handling upgrade(http to websocekt) event
//emit connection when request accepted
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit("connection", ws, request);
});
});
Client side code:
//Creating DOM element to show received messages on browser page
function msgGeneration(msg, from) {
console.log("msg:" + msg + "-from:" + from);
}
//enabling send message when connection is open
mywsServer.onopen = function () {
console.log("Socket Connection Established");
};
//handling message event
mywsServer.onmessage = function (event) {
const { data } = event;
console.log("Message Event", data);
results.push(data);
result.innerText+=results.slice(-1)[0]
};
Hiding the details that has info here in the client side
I am very new to this :
I learned javascript sessions would be helpful here

How to transfer data from a controller to a socket.io in nodejs?

I'm building an web app to receive data from an api using nodejs as backend, and show this data on the client side using React. But it's my first time using socket.io.
Sockets.ts
function socket( io ){
io.on("connection", socket => {
var socketId = socket.id;
var clientIp = socket.request.connection.remoteAddress;
console.log('New connection ' + socketId + ' from ' + clientIp);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
}
export default socket;
router.controller.ts
export const getData: RequestHandler = async (req, res) => {
const options= {
method: 'GET',
};
const response = await fetch(citybikeurl, options)
.then((res: any) => res.json())
.catch((e: any) => {
console.error({ error: e });
});
console.log("RESPONSE: ", response);
res.json(response);
}
routes.ts
router.get('/', dataController.getData)
At the moment, I don't know if I'm passing any data from controller.ts to Sockets.ts, and after of this be able to emit the results.
You should be using a socket on the server-side as well.
Please refer to this guide for how to set up a socket server:
https://medium.com/#raj_36650/integrate-socket-io-with-node-js-express-2292ca13d891

socket io on client side only runs after I save the file containing the connection

Hey super new to socket io and web sockets in general. I have a chatting app scenario with socket io where client emits to the server and the server emits back to the client.
In my case the emits from the client side are picked up on the server side so far no problems.
However on the client side there are some socket.on statements there to pick up stuff from the server. A generic console.log after connection fires, but the other socket.on statements do not.
My thought was that maybe the server side emits aren't firing. Where it gets weird though is that when I change something in the client side file with the socket.on statements, the client side statements will pick up the emits from the server until the next time I refresh the page.
It is also work noting that these client on statements work with the info that was gathered before the save: if something is like
Client-side:
socket.on("message", (data) => {
console.log(foo)
});
and I change it to
socket.on("message", (data) => {
console.log(bar)
});
and then trigger the chain of emits,
the socket.on("message... will fire properly but it will log "foo". My guess is that saving the client side socket file is creating a new connection or something, but I'm curious as to why only the old connection is picking up things from the server and not the new one?
My code for reference:
(client)
const token = localStorage.getItem("messenger-token");
const socket = io.connect('http://localhost:3001', {
query: {token}
});
//const socket = io('http://localhost:3001');
socket.on("connect", () => {
console.log("connected to server");
socket.on("new-message", (data) => {
console.log(data.message)
store.dispatch(setNewMessage(data.message, data.sender));
});
socket.on("mark-as-read", (data) => {
store.dispatch(markedAsRead(data.convoToUpdate,'socket'));
});
});
(server)
//www
const server = http.createServer(app);
app.io.attach(server,{'pingInterval': 2000, 'pingTimeout': 50000});
//app
app.io = require('socket.io')();
require('./sockets')(app)
app.io.use(function(socket, next){
const token = socket.handshake.query.token
if (token) {
jwt.verify(token, process.env.SESSION_SECRET, (err, decoded) => {
if (err) {
return next(new Error('Authentication error'));
}
User.findOne({
where: { id: decoded.id },
}).then((user) => {
return next();
});
});
} else {
return next();
}
})
//sockets module
module.exports = (app) => {
app.io.on("connection", (socket) => {
console.log("connected")
socket.on("new-message", (data) => {
socket.broadcast.emit("new-message", {
message: data.message,
sender: data.sender,
});
socket.on("mark-as-read", (data) => {
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
});
I don't know if this is appropriate but it turns out I didn't have a problem.
the server logic:
socket.broadcast.emit("mark-as-read", {
convoToUpdate:data.convoId
});
});
uses broadcast.emit instead of regular emit. This sends the new info to everyone except the sender as seen in the docs. oops

Call a function everytime the client is idle

First time trying TCP and made a program which returns the square of the number sent by the client.
How to ask the client for a number everytime they are idle for 'n' seconds?
I tried the setTimeout method but it triggers after those 'n' seconds have passed and then it does does not get triggered again.
Client:
const net = require('net');
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
const options = {
port : 1234
};
const client = net.createConnection(options, () => {
console.log("Connected to server")
});
client.on('data', (data) => {
console.log(data.toString());
});
client.setTimeout(2000, () => {
readline.question('Number to be squared: ',(num) => {
client.write(num);
});
});
Server:
const net = require('net');
const port = 1234;
const server = net.createServer(conn => {
console.log('New client joined');
conn.on('data', (data) => {
console.log(`Data received from client: ${data}`)
data = parseInt(data);
data = Math.pow(data,2);
conn.write('From server- '+data.toString());
});
conn.on('end',() => {
console.log('Connection stopped');
});
conn.on('error',(e) => {
console.log('Connection stopped-', e.message);
});
});
server.listen(port);
You need to listen to the timeout event, callback will be called only once. From the doc:
The optional callback parameter will be added as a one-time listener for the 'timeout' event.
socket.setTimeout(3000);//setting here.
socket.on('timeout', () => {
console.log('socket timeout');
socket.end();
});

Entering password programmatically in ssh2 nodejs

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');
}
});

Resources