I am planning a security system based on tcp. I want to secure it with TLS/SSL. I want to make a Client make a message to the server, the server has to check it and send to all the other clients a message back.
I think it is unclear how to handle that, because the documentation of node.js tls only shows how you connect to the server and get a message back.
This is the code of the documentation:
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
rejectUnauthorized: true,
};
const server = tls.createServer(options, (socket) => {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.write('welcome!\n');
socket.setEncoding('utf8');
socket.pipe(socket);
});
server.listen(8000, () => {
console.log('server bound');
});
Maybe you could make an example, because its totally unclear to me. Thanks for your help. If my question is unclear to you, please let me know.
'use strict';
var tls = require('tls');
var fs = require('fs');
const PORT = 1337;
const HOST = '127.0.0.1'
var options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('public-cert.pem')
};
var users= [];
var server = tls.createServer(options, function(socket) {
users.push(socket)
socket.on('data', function(data) {
for(var i = 0; i < users.length; i++){
if(users[i]!=socket){
users[i].write("I am the server sending you a message.");
}
}
console.log('Received: %s [it is %d bytes long]',
data.toString().replace(/(\n)/gm,""),
data.length); });
});
server.listen(PORT, HOST, function() {
console.log("I'm listening at %s, on port %s", HOST, PORT);
});
server.on('error', function(error) {
console.error(error);
server.destroy();
});
Related
i am working on a chatapp project that needs a real time chatting so i have used socketio in my server side which is written in nodejs and than used socketio-client in my main chatapp react-native project.
But now a problem is coming my socket is not initializing. I'm not able to connect my server with my main app. I am using socketio and socketio client my both the socket version are same 4.5.1 but it's not even connecting. I have tried to use old version of socket but its also not working and I have also tried to change my localhost port to 4000 but it's also not working.
My server code:
const express = require('express');
var bodyParser = require('body-parser');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const port = process.env.PORT || 3000;
require('./src/config/database')
const user_routes = require('./src/user/users.routes');
app.use(bodyParser.urlencoded({extended: true}))
app.use(express.json())
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.use('/User', user_routes)
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('send_message',(data)=>{
console.log("received message in server side",data)
io.emit('received_message',data)
})
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
server.listen(port, () => {
console.log( `Server running at http://localhost:${port}/`);
});
My app socketservice file code:
import io from 'socket.io-client';
const SOCKET_URL = 'http://localhost:3000'
class WSService {
initializeSocket = async () => {
try {
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}
const socketServcies = new WSService()
export default socketServcies
Where I have marked it should be connected = true but it's false in the dev console I have done console log so check that it's connecting or not and I can see that it's not connecting. How to make it connect?
There is no error in my app or server I have checked many times and my server is also running when I am running my app.
Answering my own question
The problem was i was using android emulator and android in an emulator can't connect to localhost you need to use the proxy ip so when i add http://10.0.2.2:3000 in const SOCKET_URL = 'http://10.0.2.2:3000' than its working fine
credit goes to gorbypark who told me this in discord
I'm assuming that your front and back runs in localhost. The documentation says that if the front-end is in the same domain as the back-end, you don't need to use the URL. Since you have the options parameter declared, you can use the default argument window.location in first place:
class WSService {
initializeSocket = async () => {
try {
this.socket = io(window.location, {
transports: ['websocket']
})
console.log("initializing socket", this.socket)
this.socket.on('connect', (data) => {
console.log("=== socket connected ====")
})
this.socket.on('disconnect', (data) => {
console.log("=== socket disconnected ====")
})
this.socket.on('error', (data) => {
console.log("socekt error", data)
})
} catch (error) {
console.log("scoket is not inialized", error)
}
}
emit(event, data = {}) {
this.socket.emit(event, data)
}
on(event, cb) {
this.socket.on(event, cb)
}
removeListener(listenerName) {
this.socket.removeListener(listenerName)
}
}
Don't specify the host/port for socket-io to connect to. It can figure it out on its own.
Per documentation, it tries to connect to window.location if no URL is specified as an argument.
So instead of
this.socket = io(SOCKET_URL, {
transports: ['websocket']
})
Just do
this.socket = io()
I am not sure it works with other arguments. You could try like this
this.socket = io(undefined, {
transports: ['websocket']
})
For testing a JavaScript / html5 application, I created a local WebSocketServer with node.js and ws package. I want to use secure websockets (wss) with SSL/TLS.
Key and certificate were create for testing purposes by OpenSSL locally (self signed certificate).
The client just tries to use the native WebSocket object to connect to the (local) https Server:
var ws = new Websocket('wss://localhost:8080');
The Problem is, no browser (Firefox, Chrome, Edge) can connect to the server and they all give me different error messages.
Firefox:
Firefox can not connect to the server at wss: // localhost: 8080 /.
Chrome:
ws_client.js:7 WebSocket connection to 'wss://localhost:8080/' failed:
Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
Edge:
SCRIPT12017: SCRIPT12017: WebSocket Error: SECURITY_ERR, Cross zone
connection not allowed
I created the certificate and key in OpenSSL (light, newest version) like this:
openssl req -new -x509 -nodes -out server.crt -keyout server.key
(source)
I checked almost every question about this (and similar) topics, e.g. this question, but none of them could provide a solution.
Please do not mark this question as a duplicate, because all similar questions contain slightly different problems!
Server Code:
var fs = require('file-system');
var pkey = fs.readFileSync('server.key', 'utf8');
var crt = fs.readFileSync('server.crt', 'utf8');
var credentials = { key: pkey, cert: crt };
var https = require('https');
var httpsServer = https.createServer(credentials);
httpsServer.listen(8080);
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
server: httpsServer
});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('reply from server : ' + message)
});
});
I tried another code as server, but same errors occur:
const WebSocketServer = require('ws').Server;
var fs = require('file-system');
var ws_cfg = {
ssl: true,
port: 8080,
ssl_key: 'server.key',
ssl_cert: 'server.crt'
};
var processRequest = function(req, res) {
console.log('Request received');
};
var httpServ = require('https');
var app = httpServ.createServer({
key: fs.readFileSync(ws_cfg.ssl_key, 'utf8', (error) => {
console.log('Error reading file');
}),
cert: fs.readFileSync(ws_cfg.ssl_cert, 'utf8', (error) => {
console.log('Error reading file');
})
}, processRequest).listen(ws_cfg.port, function(){
console.log('Server running');
});
var wss = new WebSocketServer( {server: app, port: 8080, host: 'localhost', domain: 'localhost'} );
wss.on('connection', function (ws) {
console.log('Connected to a client');
ws.on('message', function (message) {
console.log('MSG received: ' + message);
});
});
There's one more thing. Always, if I add a console.log(wss); to the server Code, the output looks something like this:
WebSocketServer {
domain: null,
...some more stuff...
...cert key etc....
host: null,
path: null,
port: null } }
host, domain and port is set to null. I tried everything to set it to localhost:8080, but nothing worked out. I think this could be the source of all Problems, but can't find a way. If anyone knows an answer to this question, I would highly appreciate it.
(Using the insecure 'ws' protocol ('ws://localhost:8080') in order to connect to local node.js http server works, but I want to test the app as realistic as possible and use a secure Connection.)
-- This is not an answer, just my workaround --
For anyone having the same problems, here is what I did:
Server Code should be:
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const server = new https.createServer({
cert: fs.readFileSync('localcert.cert'), //what ever you're files are called
key: fs.readFileSync('localkey.key')
});
const wss = new WebSocket.Server({ server }); // !
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('MSG received: %s', message);
});
ws.send('Hi to client');
});
server.listen(8080);
Only working in Google Chrome for now, can still not connect in Firefox.
enter chrome://flags/#allow-insecure-localhost in Google Chrome and enable.
Try to add the self-signed certificate or the generated CA to be trusted on the system that you are using.
I'm a newbie working with an application with MEAN stack. It is an IoT based application and using nodejs as a backend.
I have a scenario in which I have to send a broadcast to each connected clients which can only open the Socket and can wait for any incoming data. unless like a web-browser they can not perform any event and till now I have already gone through the Socket.IO and Express.IO but couldn't find anything which can be helpful to achieve what I want send raw data to open socket connections'
Is there any other Node module to achieve this. ?
Here is the code using WebSocketServer,
const express = require('express');
const http = require('http');
const url = require('url');
const WebSocket = require('ws');
const app = express();
app.use(function (req, res) {
res.send({ msg: "hello" });
});
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
server.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
Now, my query is when this code will be executed,
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
wss.on('connection', function connection(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
}
}
wss.broadcast = function broadcast(msg) {
console.log(msg);
wss.clients.forEach(function each(client) {
client.send(msg);
});
};
Try the following code to broadcast message from server to every client.
wss.clients.forEach(function(client) {
client.send(data.toString());
});
Demo server code,
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 2055 },()=>{
console.log('server started')
})
wss.on('connection', (ws) => {
ws.on('message', (data) => {
console.log('data received \n '+ data)
wss.clients.forEach(function(client) {
client.send(data.toString());
});
})
})
wss.on('listening',()=>{
console.log('listening on 2055')
})
I want create a simple secure client/server using TLS. I've follow instruction on the official doc. But I don't know how to create self-signed certificate with openssl (does not work with me).
Here code :
server.js
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
// This is necessary only if the client uses the self-signed certificate.
ca: [ fs.readFileSync('client-cert.pem') ]
};
const server = tls.createServer(options, (socket) => {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.write('welcome!\n');
socket.setEncoding('utf8');
socket.pipe(socket);
});
server.listen(8000, () => {
console.log('server bound');
});
client.js :
const tls = require('tls');
const fs = require('fs');
const options = {
// Necessary only if using the client certificate authentication
key: fs.readFileSync('client-key.pem'),
cert: fs.readFileSync('client-cert.pem'),
// Necessary only if the server uses the self-signed certificate
ca: [ fs.readFileSync('server-cert.pem') ]
};
const socket = tls.connect(8000, options, () => {
console.log('client connected',
socket.authorized ? 'authorized' : 'unauthorized');
process.stdin.pipe(socket);
process.stdin.resume();
});
socket.setEncoding('utf8');
socket.on('data', (data) => {
console.log(data);
});
socket.on('end', () => {
server.close();
});
I don't know why use two different key-pair :
client-key.pem
client-cert.pem
and :
server-key.pem
server-cert.pem
Anyone can exmplain me ? For work in self-signed.
Sincerely,
Yoratheon
I solve my problem.
Solution here
I've looked around and it seems as if all the ways to implement SSEs in Node.js are through more complex code, but it seems like there should be an easier way to send and receive SSEs. Are there any APIs or modules that make this simpler?
Here is an express server that sends one Server-Sent Event (SSE) per second, counting down from 10 to 0:
const express = require('express')
const app = express()
app.use(express.static('public'))
app.get('/countdown', function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
})
countdown(res, 10)
})
function countdown(res, count) {
res.write("data: " + count + "\n\n")
if (count)
setTimeout(() => countdown(res, count-1), 1000)
else
res.end()
}
app.listen(3000, () => console.log('SSE app listening on port 3000!'))
Put the above code into a file (index.js) and run it: node index
Next, put the following HTML into a file (public/index.html):
<html>
<head>
<script>
if (!!window.EventSource) {
var source = new EventSource('/countdown')
source.addEventListener('message', function(e) {
document.getElementById('data').innerHTML = e.data
}, false)
source.addEventListener('open', function(e) {
document.getElementById('state').innerHTML = "Connected"
}, false)
source.addEventListener('error', function(e) {
const id_state = document.getElementById('state')
if (e.eventPhase == EventSource.CLOSED)
source.close()
if (e.target.readyState == EventSource.CLOSED) {
id_state.innerHTML = "Disconnected"
}
else if (e.target.readyState == EventSource.CONNECTING) {
id_state.innerHTML = "Connecting..."
}
}, false)
} else {
console.log("Your browser doesn't support SSE")
}
</script>
</head>
<body>
<h1>SSE: <span id="state"></span></h1>
<h3>Data: <span id="data"></span></h3>
</body>
</html>
In your browser, open localhost:3000 and watch the SSE countdown.
I'm adding a simple implementation of SSE here. It's just one Node.js file.
You can have a look at the result here: https://glossy-ox.glitch.me/
const http = require('http');
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
// Server-sent events endpoint
if (req.url === '/events') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
...(req.httpVersionMajor === 1 && { 'Connection': 'keep-alive' })
});
const refreshRate = 1000; // in milliseconds
return setInterval(() => {
const id = Date.now();
const data = `Hello World ${id}`;
const message =
`retry: ${refreshRate}\nid:${id}\ndata: ${data}\n\n`;
res.write(message);
}, refreshRate);
}
// Client side
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>SSE</title>
</head>
<body>
<pre id="log"></pre>
</body>
<script>
var eventSource = new EventSource('/events');
eventSource.onmessage = function(event) {
document.getElementById('log').innerHTML += event.data + '<br>';
};
</script>
</html>
`);
});
server.listen(port);
server.on('error', (err) => {
console.log(err);
process.exit(1);
});
server.on('listening', () => {
console.log(`Listening on port ${port}`);
});
If you're using express this is the easiest way https://www.npmjs.com/package/express-sse
on BE:
const SSE = require('express-sse');
const sse = new SSE();
...
app.get('/sse', sse.init);
...
sse.send('message', 'event-name');
on FE:
const EventSource = require('eventsource');
const es = new EventSource('http://localhost:3000/sse');
es.addEventListener('event-name', function (message) {
console.log('message:', message)
});
I found SSE implementation in node.js.
Github link: https://github.com/einaros/sse.js
NPM module:https://www.npmjs.com/package/sse
Will above link helps you ?
**client.js**
var eventSource = new EventSource("/route/events");
eventSource.addEventListner("ping", function(e){log(e.data)});
//if no events specified
eventSource.addEventListner("message", function(e){log(e.data)});
**server.js**
http.createServer((req, res)=>{
if(req.url.indexOf("/route/events")>=){
res.setHeader('Connection', 'keep-alive');
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Content-Type", "text/event-stream");
let event = "event: ping";
let id = `id: ${Date.now()}`;
let data = {
message:`hello #${new Date().toString()}`
}
data = "data: "+JSON.stringify(data);
res.end(`${event}\n${id}\n${data}\n\n`);
}
}).listen(PORT)
After looking at the other answers I finally got this working, but what I ended up having to do was a little different.
[package.json] Use express-sse:
The exact version of express-sse is very important. The latest tries to use res.flush(), but fails and crashes the http server.
"express-sse": "0.5.1",
[Terminal] Install express-sse:
npm install
[app.js] Use the router:
app.use(app.baseUri, require('./lib/server-sent-events').router);
[server-sent-events.js] Create sse library:
The call to pause() is the equivalent of flush(), which was removed from express. It ensures you'll keep getting messages as they are sent.
var express = require('express');
const SSE = require('express-sse');
const sse = new SSE();
var router = express.Router();
router.get('/sse', sse.init)
module.exports = {
send,
router
};
async function send(message) {
sse.send(message.toProperCase(), 'message');
await pause();
}
function pause() {
return new Promise((resolve, reject) => {
setImmediate(resolve)
})
}
[your-router.js] Use the sse library and call send:
var express = require('express');
var serverSentEvents = require('../lib/server-sent-events');
var router = express.Router();
router.get('/somepath', yourhandler);
module.exports = router;
async function yourhandler (req, res, next) {
await serverSentEvents.send('hello sse!'); // <<<<<
}
[your-client-side.js] Receive the sse updates:
I recommend you keep the event.data.replace(/"/g,'') because express-sse tacks on enclosing quotes and we don't want those.
const eventSource = new EventSource('http://yourserver/sse');
eventSource.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data.replace(/"/g,'') + '...';
};
You should be able to do such a thing using Socket.io. First, you will need to install it with npm install socket.io. From there, in your code you will want to have var io = require(socket.io);
You can see more in-depth examples given by Socket.IO
You could use something like this on the server:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port ' + port);
});
app.use(express.static(__dirname + '/public'));
io.on('connection', function (socket) {
socket.emit('EVENT_NAME', {data});
});
And something like this on the client:
<script src="socket_src_file_path_here"></script>
<script>
var socket = io('http://localhost');
socket.on('EVENT_NAME', function (data) {
console.log(data);
//Do whatever you want with the data on the client
});
</script>