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
Related
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.');
});
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
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);
});
});
I have a node.js Server:-
// *********** Server that receives orders ************ //
// to use features of the http protocol. //
var http = require('http');
// initialize to empty string. //
var req = "";
// create the server that will receive an order Request. //
var server = http.createServer(function(req,res) {
res.writeHead(200, {'content-type': 'text/plain'});
// when data is successfully received, a success message is displayed. //
res.on('data', function(data){
req += data; // received data is appended. //
console.log("We have received your request successfully.");
});
});
// An error message is displayed - error event. //
server.on('error', function(e){
console.log("There is a problem with the request:\n" + e.message);
});
// server listens at the following port and localhost (IP). //
server.listen(8000, '127.0.0.1');
and then I have a node.js Client:-
var http = require("http");
var querystring = require("querystring");
var postOrder = querystring.stringify({
'msg': 'Hello World!'
});
var options = {
hostname: '127.0.0.1',
port: 8000,
path:'/order',
method:'POST',
headers:{
'Content-Type' :'application/x-www-form-urlencoded',
'Content-Length' : postOrder.length
}
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postOrder);
req.end();
I am trying to figure out how I can make the client post its order to the server and get a response back from the server...either a success message or an error message...using command line.
currently I run the server on cmd line $ node server.js
and then a run the client $ node client.js
but i get no responses.
I think that have problems from the server:
The Server must be:
http.createServer(function(req, res) {
if (req.method == 'GET') {
} else if (req.method == 'POST') {
var body = '';
req.on('data', function(data) {
body += data;
});
req.on('end', function() {
console.log("We have received your request successfully.");
});
}
res.end("ok");
})
I'm using Nodejs, Socket.io, and Angular to build a web app taking advantage of the Instagram Real-Time API. I'm running into an issue when I fire off GET requests to the Instagram API.
I get this error every time I send a GET request:
"Failed to load resource: the server responded with a status of 404 (NOT FOUND)"
The error details reveal:
https://api.instagram.com/v1/geographies/[object%20Object]/media/recent?client_id=MY_CLIENT_ID
Obviously that [object%20Object] is where the error lies. As my code below shows, that should be the 'geo_id' which I'm passing in as an argument. Geo_id is actually the 'object_id' of the Instagram real-time subscription.
Below is my code. Any idea where I'm going wrong?
Socket.io server side code:
io.sockets.on('connection', function(socket) {
// log user connections
console.log("user connected");
// receive the Instagram handshake for real-time subscriptions
app.get('/callback', function(req, res){
var handshake = Instagram.subscriptions.handshake(req, res);
});
// for each new post Instagram sends us the data
app.post('/callback', function(req, res) {
var data = req.body;
// grab the object_id (as geo_id) of the subscription and send as an argument to the client side
data.forEach(function(data) {
var geo_id = data.object_id;
sendUpdate(geo_id);
});
res.end();
});
// send the url with the geo_id to the client side
// to do the ajax call
function sendUpdate(geo_id) {
io.sockets.emit('newImage', { geo_id: geo_id });
}
// log user disconnections
socket.on('disconnect', function () {
console.log('user disconnected');
});
});
relevant angular controller code:
socket.on('newImage', function(geo_id) {
// pass geo_id into Instagram API call
Instagram.get(geo_id).success(function(response) {
instagramSuccess(response.geo_id, response);
});
// Instagram API callback
var instagramSuccess = function(scope,res) {
if (res.meta.code !== 200) {
scope.error = res.meta.error_type + ' | ' + res.meta.error_message;
return;
}
if (res.data.length > 0) {
$scope.items = res.data;
} else {
scope.error = "This location has returned no results";
}
};
});
Instagram angular factory code:
angular.module('InstaFactory', []).factory('Instagram', function($http) {
var base = "https://api.instagram.com/v1";
var client_id = 'MY_CLIENT_ID';
return {
'get': function(geo_id) {
var request = '/geographies/' + geo_id + '/media/recent?client_id=' + client_id;
var url = base + request;
var config = {
'params': {
'callback': 'JSON_CALLBACK'
}
};
return $http.jsonp(url, config);
}
};
});