Websocket - browser websocket is not receiving messages from server - javascript

I built a websocket server and client with Node and both is working fine. But, I built a client on a single html page and there, websocket is listening messages just when I call sendUTF from browser. The messages sent by node client can´t be read by browser client. Is this a security issue/feature or am I stupid?
Server code:
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer( (req, res) => {
console.log((new Date()) + ' Received request for ' + request.url);
res.writeHead(404);
res.end();
});
server.listen(8080, () => {
console.log((new Date()) + ' Server is listening on port 8080');
});
wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
}
wsServer.on('request', (request) => {
/* if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}*/
var connection = {};
try {
connection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received and send Message: ' + message.utf8Data);
connection.sendUTF(message.utf8Data);
}
else if (message.type === 'binary') {
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
connection.sendBytes(message.binaryData);
}
else {
console.log('Received unknown format message: ' + message);
connection.send(message);
}
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
}
catch(e) {
console.error("Client fail trying to connect to websocket: " + e);
}
});
Node client code:
var express = require('express');
var app = express();
server = require('http').createServer(app);
var WebSocketClient = require('websocket').client;
var kinect = new Kinect2();
app.use(express.static(__dirname + 'js/View'));
//app.use(express.static(__dirname + 'js/Script'));
//instance of WebSocket object
var wsClient = new WebSocketClient();
//Websocket connection events
wsClient.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
process.exit(0);
});
wsClient.on('connect',(connection) => {
connection.on('error', (error) => {
console.error("Connection Error: " + error.toString());
process.exit(0);
});
connection.on('close',() => {
console.log("Websocket connection is closed!");
});
// connection.on('message',(message) => {
// if (message.type === 'utf8') {
// console.log("Received: '" + message.utf8Data + "'");
// }
// });
console.log('Websocket connection OK!');
setInterval(() => {
console.log("sending message...");
connection.send("This is a test!");
},1000);
//startKinect(connection);
});
wsClient.connect('ws://127.0.0.1:8080','echo-protocol');
Finally my browser client
<!DOCTYPE html>
<html>
<head>
<title>
Websocket test
</title>
</head>
<body>
<h1>Websocket client test</h1>
<script>
console.log("Open Websocket...");
var websocket = new WebSocket('ws://127.0.0.1:8080','echo-protocol');
websocket.onopen = function () {
console.log("websocket was open");
//websocket.send('Websocket is working(I gess)');
};
websocket.onclose = () => {
console.log("Websocket was closed!");
}
websocket.onerror = (error) =>{
console.error("Websocket error: " + JSON.stringify(error));
};
websocket.onmessage = (message) => {
// Web Socket message:
console.log("MSG: " + message.data );
};
websocket.addEventListener('message',(e) => {
websocket.onmessage(e);
})
</script>
</body>
</html>
Any help is welcome! Thanks!

Your server is working as an echo (client -> server -> client), but what you describe is a broadcast (client -> server -> clients). You should keep a reference of clients and then send to all of them.
Outside of the request event handler, add:
var connections = [];
After your accept the request, add the connection to the array:
connections.push( connection );
And then when you want to send data to everyone, loop through the connections:
for ( var i = 0; i < connections.length; i++ )
connections[ i ].sendUTF( message.utf8Data );

It seems I miss the 'broadcast' part. Fortunately, 'ws' module allows me to do this extreamly easy!
const WebSocket = require('ws');
var port = 8080;
const wss = new WebSocket.Server({ "port": port });
// Broadcast to all.
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if ( client.readyState == WebSocket.OPEN && data != undefined )
client.send(data);
});
};
wss.on('connection', function connection(ws) {
console.log("CONNECTION OK...");
ws.on('message', function incoming(data) {
// Broadcast to everyone else.
wss.broadcast(data);
});
});

Related

MQTT | Publisher automatically disconnect and connect on his own

I use mosca (for node js) to create a MQTT server and MQTT (still node js) package to create publishers and subscribers. Everything work good except one thing: publisher reload automatically
I guess it may be due to incorrect mqtt.connect options. I read npm mqtt manual but still don't understand my mistake (or mistakes)
P.s. Sorry for my grammatical, I'm not an English speaker
UPD: i'm beginner :)
MQTT Server:
const mosca = require("mosca");
const MqttServer = new mosca.Server({
port: 1884
});
MqttServer.on("clientConnected", function(client) {
console.log('\x1b[0m', 'Клиент ' + '\x1b[32m' + client.id + '\x1b[32m' + ' подключен!' + '\x1b[0m');
});
MqttServer.on("clientDisconnected", function(client) {
console.log('\x1b[0m', 'Клиент ' + '\x1b[32m' + client.id + '\x1b[31m' + ' Отключен' + '\x1b[0m');
})
MqttServer.on("ready", function() {
console.log("Server MQTT Room1 running");
});
MqttServer.on("error", function(error) {
console.log("error!");
client.end();
})
Subscribe script:
const mqtt = require("mqtt");
const options = {
clientId: 'mqtt_room1_SUB',
clean: true
};
const client = mqtt.connect("mqtt://127.0.0.1:1884", options);
client.on("connect", function() {
console.log("Connected");
// connected = client.connected
client.subscribe("room1/temp", { qos: 0 });
});
client.on("message", function(top, message) {
console.log("Current temperature:", message.toString());
});
client.on("disconnect", function () {
console.log('Server disabled.')
})
Publish script:
const mqtt = require("mqtt");
const options = {
clientId: 'mqtt_room1_PUB',
clean: true
};
const client = mqtt.connect("mqtt://127.0.0.1:1884", options);
client.on("connect", function() {
console.log("Connected");
setInterval(() => {
var value = Math.floor(Math.random() * 20);
client.publish("room1/temp", value.toString());
}, 2000);
});
client.on("disconnect", function () {
console.log('Server disabled.');
});

how do I use npm module ssh2 to tunnel a port

I have a working node.js Server that uses a socket.io websocket connection and ssh2 connection to open a shell and return it to a react client in the browser that uses xterm-for-react. I'm now trying to also tunnel a port over the same ssh connection but am having some difficulty. The code is below and the commented out part is where I've been trying to do the port forwarding - equivalent to
ssh -L 2233:192.168.2.1:80 test#192.168.0.65
const socketIO = require("socket.io");
const sshClient = require("ssh2").Client;
const utf8 = require("utf8");
const fs = require("fs");
class SocketServiceFwd {
constructor() {
this.socket = null;
this.pty = null;
this.devicesList = [
{
name: "Device 1",
host: "192.168.0.65",
port: "22",
username: "test",
password: "test12345",
},
];
attachServer(server) {
if (!server) {
throw new Error("Server not found...");
}
const io = socketIO(server, {cors: {origin: "*",},});
console.log("Created socket server. Waiting for client connection.");
// "connection" event happens when any client connects to this io instance.
io.on("connection", (socket) => {
console.log("Client connect to socket.", socket.id);
this.socket = socket;
const ssh = new sshClient();
this.socket.on("devices", (cb) => {
console.log("Get devices list from " + socket.id);
return cb(null,this.devicesList.map((d) => ({ name: d.name }))
);
});
this.socket.on("connectToDevice", (deviceName) => {
console.log(socket.id + " connecting to device " + deviceName);
const selectedDevice = this.devicesList.find(
(d) => d.name === deviceName
);
if (selectedDevice) {
ssh.on("ready", function () {
console.log(socket.id + " successfully connected to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION ESTABLISHED ***\r\n");
// ssh.forwardOut("127.0.0.1", 2233, "192.168.2.1", 80,
// (err, stream) => {
// console.log(
// "ssh forwardOut '127.0.0.1:2233' '192.168.2.1:80'"
// );
// if (err)
// return socket.emit(
// "output",
// "\r\n*** SSH FORWARDOUT ERROR: " + err.message + " ***\r\n"
// );
// }
// );
ssh.shell(function (err, stream) {
if (err)
return socket.emit(
"output",
"\r\n*** SSH SHELL ERROR: " + err.message + " ***\r\n"
);
socket.on("input", function (data) {
stream.write(data);
});
stream.on("data", function (d) {
socket.emit("output", utf8.decode(d.toString("binary")));
});
stream.on("close", function () {
console.log(socket.id + " terminal stream close");
ssh.end();
});
});
});
ssh.on("close", function () {
console.log(socket.id + " ssh connection closed to " + deviceName);
socket.emit("output", "\r\n*** SSH CONNECTION CLOSED ***\r\n");
socket.removeListener("input", () => {});
});
ssh.on("error", function (err) {
console.log(err);
socket.emit("output","\r\n*** SSH CONNECTION ERROR: " + err.message + " ***\r\n");
});
ssh.connect(selectedDevice);
}
});
this.socket.on("disconnectFromDevice", () => {
console.log(socket.id + " disconnecting from device");
ssh.destroy();
});
});
}
}
module.exports = SocketServiceFwd;
***** EDITED *****
It would be great if someone could please provide some advice :-) I have been pushing ahead but still need some assistance...
I have had a little more success using the npm "tunnel-ssh" module. The tunnel does open long enough for me to view the website but shortly after that, the tunnel stops working. Is there something else I'm supposed to be doing after opening the tunnel?
The code below goes where the commented out section above is. I have tried to follow the examples I've seen online - can anyone please advise me what I'm doing wrong?
I'm running DEBUG=* in my npm start and see the following :
tunnel-ssh sshConnection:ready +3s
tunnel-ssh sshConnection:ready +1ms
tunnel-ssh sshStream:create +19ms
tunnel-ssh sshStream:create +0ms
TCP :: ERROR: read ECONNRESET
TCP :: ERROR: read ECONNRESET
So It's clear that the tunnel starts up but then an error occurs. Often the connection recovers and I can continue browsing the website through the tunnel, but eventually an unrecoverable error occurs. So the tunnel is unstable. If i run the tunnel using openssh it is stable. Therefore my question really now boils down to a request for assistance in determining reasons for the instability. Am I not handling something in my code or my configuration correctly? Please Help! Note also, that despite this my shell session continues to work without any problem.
const tunnel = require("tunnel-ssh");
const tnl = tunnel({host: '192.168.0.65', username: 'test', password: 'test12345',
dstHost: '192.168.2.1', dstPort: 80, localHost: '127.0.0.1',
localPort: 2233}, (er, stream) => {
if(er) {
console.log("something went wrong " + er.message);
stream.close();
}
stream.on("data", (data) => {
console.log("TCP :: DATA: " + data);
});
stream.on("error", (error) => {
console.log("TCP :: ERROR: " + error.message);
});
});

How to maintained network connection in Node.js for unlimited requests

I want to make connection for unlimited times in Nodejs. For example, i write something on some server and after writing on server, server send me response of error (as expected from server) and disconnect. But i want to again make a connection to that server and again want to send request with different parameters. I am not sure where and what logic/code to be put in my following segment of code , so that i can make unlimited requests.
var net = require('net');
var HOST = '40.14.121.178'
var PORT = 12537;
var byteToSend = [0x56, 0x34, ...]
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
client.on('data', function(data) {
console.log('DATA: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
});
EDITED:
actually, i want to make another connection upon disconnect like following style (which is i think wrong)
client.on('close', function() {
console.log('Connection closed');
client.connect(PORT, HOST, function() {
console.log('again CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
});
above re connection raise following error.
events.js:174
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at afterWriteDispatched (internal/stream_base_commons.js:78:25)
at writeGeneric (internal/stream_base_commons.js:73:3)
at Socket._writeGeneric (net.js:713:5)
at Socket._write (net.js:725:8)
at doWrite (_stream_writable.js:415:12)
at writeOrBuffer (_stream_writable.js:399:5)
at Socket.Writable.write (_stream_writable.js:299:11)
at bitflipping (C:\Users\...\Desktop\myScripts.js:130:8)
at Socket.<anonymous> (C:\Users\...\Desktop\myScripts.js:104:9)
at Object.onceWrapper (events.js:286:20)
Emitted 'error' event at:
at errorOrDestroy (internal/streams/destroy.js:107:12)
at onwriteError (_stream_writable.js:430:5)
at onwrite (_stream_writable.js:461:5)
at _destroy (internal/streams/destroy.js:49:7)
at Socket._destroy (net.js:613:3)
at Socket.destroy (internal/streams/destroy.js:37:8)
at afterWriteDispatched (internal/stream_base_commons.js:78:17)
at writeGeneric (internal/stream_base_commons.js:73:3)
at Socket._writeGeneric (net.js:713:5)
at Socket._write (net.js:725:8)
I don't think you can re-use the existing client connection to connect again. Therefore, you'll want to wrap it all in a nice closure/function that you can call again to create a new socket and connect.
Try something like this:
var net = require('net');
var HOST = '40.14.121.178'
var PORT = 12537;
var byteToSend = [0x56, 0x34, ...]
function connect() {
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
client.write(byteToSend);
});
client.on('data', function(data) {
console.log('DATA: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
connect();
});
}
connect();
If I understood correctly, you want to keep your server enabled for requests for a sort amount of time without waiting for 3-way handshake etc. To do that you should use the keep-alive attribute like this.
const net = require('net');
const HOST = '40.14.121.178'
const PORT = 12537;
const byteToSend = [0x56, 0x34, ...];
const server = net.createServer(client => {
client.setKeepAlive(true, 60000); // milliseconds.
client.on('data', data => {
console.log(`DATA: ${data}`);
client.destroy();
});
client.on('end', data => {
console.log('Connection closed');
});
client.on('connect', data => {
client.write(byteToSend);
});
client.on('error', err => {
console.log(`Error: ${err.message}`);
})
});
server.listen(PORT, HOST, () => {
console.log("server started");
});

unable to create simple websocket - NodeJS

I am trying to follow this tutorial: https://www.simonewebdesign.it/101-web-socket-protocol-handshake/ for developing simple websocket protocol.
I am visiting localhost:1337/index.html but I get:
This localhost page can’t be found
No web page was found for the web address: http://localhost:1337/index.html
Search Google for localhost 1337 index
HTTP ERROR 404
if I visit this url: file:///C:/Users/.../websocket-demo/index.html
I atleast see the index.html page being rendered. But in console I get this error:
WebSocket connection to 'ws://localhost:1337/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I am not sure what's wrong?
I have 3 files: index.html, server.js and client.js
server.js
#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log('Received request from ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(1337, function() {
console.log('Server is listening on port 1337.');
});
wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false // because security matters
});
function isAllowedOrigin(origin) {
console.log('Connection requested from origin ' + origin);
valid_origins = [
'http://localhost:8080',
'127.0.0.1',
'null'
];
if (valid_origins.indexOf(origin) != -1) {
console.log('Connection accepted from origin ' + origin);
return true;
}
console.log('Origin ' + origin + ' is not allowed.')
return false;
}
wsServer.on('connection', function(webSocketConnection) {
console.log('Connection started.');
});
wsServer.on('request', function(request) {
var connection = isAllowedOrigin(request.origin) ?
request.accept('echo-protocol', request.origin)
: request.reject();
connection.on('message', function(message) {
var response = '';
console.log('Received Message: ' + message.utf8Data);
if (message.type === 'utf8') {
switch (message.utf8Data) {
case 'hi':
response = 'Hey there';
break;
case 'hello':
response = 'Heya!';
break;
case 'xyzzy':
response = 'Nothing happens.';
break;
case 'desu':
response = 'Keep typing, man. Keep typing.';
break;
default:
response = "Hello. Uh... what am I supposed to do with '" +
message.utf8Data + "'?";
}
connection.sendUTF(response);
}
});
connection.on('close', function(reasonCode, description) {
console.log(connection.remoteAddress + ' has been disconnected.');
});
});
client.js
(function () {
var ws = new WebSocket('ws://localhost:1337', 'echo-protocol');
ws.onopen = function (event) {
console.log('Connection opened.');
}
ws.onmessage = function (event) {
console.log('Response from server: ' + event.data);
}
ws.onclose = function (event) {
console.log('Connection closed.');
}
ws.onerror = function (event) {
console.log('An error occurred. Sorry for that.');
}
WebSocket.prototype.sendMessage = function (message) {
this.send(message);
console.log('Message sent: ' + message);
}
document.getElementById('send').addEventListener('click', function (event) {
event.preventDefault();
var message = document.getElementById('message').value;
ws.sendMessage(message);
});
})();
index.html - consist of forms
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>WebSocket Client Demo</title>
</head>
<body>
<h1>WebSocket Client</h1>
<form>
<label for="message">Send a message</label>
<input id="message" name="message" type="text">
<button id="send" name="send">Send</button>
</form>
<script src="client.js"></script>
</body>
</html>
Your web server doesn't serve your index.html file.
You can see this post to get an idea how to serve static files, or you can just boot up another HTTP server to serve your index file, like with python, the way they suggested in the README file of the tutorial that you are following: https://github.com/simonewebdesign/websocket-demo

How to authenticate every request over a websocket in javascript?

Have setup a javascript server and configured the websocket to it. On the client side using react and npm. So, I want to authenticate every request to web socket using rest API. The authentication will be the first step and then all the information transfer will be happening using the same web socket after authentication is done. Is it possible to pass headers for authentication to websocket ? Can anybody please tell how to proceed ?
Below is the code for the server and client that I was experimenting with.
Server code -
#!/usr/bin/env node
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(5005, function() {
console.log((new Date()) + ' Server is listening on port 5005');
});
wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
});
function originIsAllowed(origin) {
return true;
}
wsServer.on('request', function(request) {
if (!originIsAllowed(request.origin)) {
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
console.log(" ################ Authorization ##################");
var auth = request.headers['authorization'];
if(!auth) {
response.statusCode = 401;
response.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
console.log(" Authorization failed !!! ");
response.end('<html><body>Need some creds son</body></html>');
}
else if(auth) {
var tmp = auth.split(' ');
var buf = new Buffer(tmp[1], 'base64');
var plain_auth = buf.toString();
console.log("Decoded Authorization :", plain_auth);
var creds = plain_auth.split(':');
var username = creds[0];
var password = creds[1];
if((username == 'hack') && (password == 'thegibson')) {
console.log(" Login successful !!!");
}
else {
console.log("Login failed !!");
}
}
var connection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
//send message
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
});
Client code -
import React from 'react'
var client = null;
export default React.createClass({
getInitialState: function() {
return { val : [],
username : 'hacker',
password : 'thegibson' };
},
componentWillMount: function() {
//client = new WebSocket('ws://localhost:8000/','echo-protocol');
client = new WebSocket('ws://'+this.state.username+':'+this.state.password+'#localhost:5005/','echo-protocol');
client.onerror = function() {
console.log('Connection Error');
};
client.onopen = function() {
function sendData(){
var details=[{"name" : "Ravi", "age" : 15, "occupation": "Student" }];
if (client.readyState === client.OPEN) {
client.send(details.toString());
console.log(details);
setTimeout(sendData,2000);
}
}
sendData();
};
client.onmessage = function(e) {
this.setState({
val: e.data
});
}.bind(this);
},
componentWillUnmount: function(){
client.close();
},
render: function() {
return (React.createElement("div",null,
React.createElement("ul",null,
React.createElement("li",null,this.state.val.name," ( ", this.state.val.age," ) - "," Occupation :", this.state.val.occupation)
)
))
}
});
Maybe you can use jwt or jwe if you want to encrypt the data you send. There are many libraries you can use and full documentation here: https://jwt.io/
So you cand send via post or a header all information and check it in every HTTP or websocket call

Categories