3

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!

Andre Carneiro
  • 708
  • 1
  • 5
  • 27
  • If I am understanding correctly, you are attempting to communicate from a Node Client to a Browser Client through WebSockets? This is not explicitly possible because WebSockets use a server for duplex communication between a Server and Client(s), not Client and Client. However, there seems to be some advancements in P2P communication with WebSockets that may help you: https://stackoverflow.com/questions/4118272/do-websockets-allow-for-p2p-browser-to-browser-communication – Josh Weston Aug 15 '17 at 14:49
  • Nope, is not like that! There is a server for the websocket and two clients. The nodejs client is the "producer" and writes into the websocket. The browser client is the "consumer" and it should be able to read from the websocket unless my concepts about it are wrong. – Andre Carneiro Aug 15 '17 at 15:46

2 Answers2

1

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 );
vox
  • 837
  • 8
  • 15
  • Thanks for your answer! But I don´t understand how can I use 'connection' object outside the 'request' event if this object exists only because the 'request' object(or I didn´t understand what you wrote)? Could you explain this, please? – Andre Carneiro Aug 16 '17 at 11:41
1

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);
  });
});
Andre Carneiro
  • 708
  • 1
  • 5
  • 27