Recently i created a node js and webrtc project that use http. But I notified that webrtc only works with https. So how can i transfer this http based node js file to https based one? Please help me.
Really i have no idea how to do this. So please help me to make it. What is need is to run this file over https. Not in http. As you can see, the below code use just http. As the webrtc need to run over https, i just need to make this file to run over https too
var hat = require('hat')
var http = require('http')
var nodeStatic = require('node-static')
var ws = require('ws')
var PORT = process.argv[2] || 4000
var httpServer = http.createServer()
var staticServer = new nodeStatic.Server('./public')
var wsServer = new ws.Server({ server: httpServer })
var peers = {}
var waitingId = null
var count = 0
httpServer.on('request', function (req, res) {
req.addListener('end', function () {
staticServer.serve(req, res)
}).resume()
})
wsServer.on('connection', onconnection)
function onconnection (peer) {
var send = peer.send
peer.send = function () {
try {
send.apply(peer, arguments)
} catch (err) {}
}
peer.id = hat()
peers[peer.id] = peer
peer.on('close', onclose.bind(peer))
peer.on('error', onclose.bind(peer))
peer.on('message', onmessage.bind(peer))
count += 1
broadcast(JSON.stringify({ type: 'count', data: count }))
}
function onclose () {
peers[this.id] = null
if (this.id === waitingId) {
waitingId = null
}
if (this.peerId) {
var peer = peers[this.peerId]
peer.peerId = null
peer.send(JSON.stringify({ type: 'end' }), onsend)
}
count -= 1
broadcast(JSON.stringify({ type: 'count', data: count }))
}
function onmessage (data) {
console.log('[' + this.id + ' receive] ' + data + '\n')
try {
var message = JSON.parse(data)
} catch (err) {
console.error('Discarding non-JSON message: ' + err)
return
}
if (message.type === 'peer') {
if (waitingId && waitingId !== this.id) {
var peer = peers[waitingId]
this.peerId = peer.id
peer.peerId = this.id
this.send(JSON.stringify({
type: 'peer',
data: {
initiator: true
}
}), onsend)
peer.send(JSON.stringify({
type: 'peer'
}), onsend)
waitingId = null
} else {
waitingId = this.id
}
} else if (message.type === 'signal') {
if (!this.peerId) return console.error('unexpected `signal` message')
var peer = peers[this.peerId]
peer.send(JSON.stringify({ type: 'signal', data: message.data }))
} else if (message.type === 'end') {
if (!this.peerId) return console.error('unexpected `end` message')
var peer = peers[this.peerId]
peer.peerId = null
this.peerId = null
peer.send(JSON.stringify({ type: 'end' }), onsend)
} else {
console.error('unknown message `type` ' + message.type)
}
}
function onsend (err) {
if (err) console.error(err.stack || err.message || err)
}
function broadcast (message) {
for (var id in peers) {
var peer = peers[id]
if (peer) {
peer.send(message)
}
}
}
httpServer.listen(PORT, function () {
console.log('Listening on port ' + PORT)
})
HTTPS requires a security certificate which matches the domain name. Both domain name and certificate for production usage can be purchased online and will have an expiration date and will need renewals.
The certificate comprises of two files cert.pem and key.pem.
For local development a self-signed untrusted certificate can be generated for localhost domain (via openssl command-line tool).
openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'
The original code can be updated from 'http' to 'https' and those two files need to be loaded and passed as options to https.createServer()
I also had to update the call to 'node-static' as it was not serving local files.
var hat = require('hat')
var https = require('https') // updated
const fs = require('fs');
var nodeStatic = require('node-static')
var ws = require('ws')
var PORT = process.argv[2] || 4000
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
var httpServer = https.createServer(options) // updated
var staticServer = new nodeStatic.Server('./public')
var wsServer = new ws.Server({ server: httpServer })
var peers = {}
var waitingId = null
var count = 0
httpServer.on('request', function (req, res) { // updated
staticServer.serve(req, res)
})
// the rest of the original code
// httpServer variable is now an HTTPS server instance
httpServer.listen(PORT, function () {
console.log('Listening on port ' + PORT)
})
Starting the server and visiting https://localhost:4000 will be prompted with untrusted certificate warning which you have to acknowledge.
Register a site domain for under $15.00/year (for .com) including whois protection.
Create a free Cloudflare account and setup your new Domain Name, configure the DNS to proxy and handle your IPs you plan to host with under such domain.
Generate through cloudflare SSL Key, and utilize the certs in your projects. As long as the DNS routes to say your home IP or server IP it'll maintain that HTTPS.
For testing purposes you can use fake key/cert but this will always show insecure until you follow the above steps.
In NodeJS to engage the HTTPS:
const HTTPS = require('https');
const FILESYSTEM = require('fs');
// CREATE HTTP APP HERE THEN CREATE HTTPS SERVER FOR THE APP
HTTPS.createServer({ key: FILESYSTEM.readFileSync(__dirname + '/certs/key.pem'), cert: FILESYSTEM.readFileSync(__dirname + '/certs/cert.pem') }, app).listen(443);
Related
I have a two webservers both running https with the same certificates, I have a main shard that the user connects to example.com, they retrieve some data and try to connect to an ip address on the 2nd shard via websocket.
But no matter what I configure I get an Error 1006 on the client side when connecting to the 2nd shard. Firefox devtooling gives me multiple errors - ssl_error_bad_cert_domain, SSL_ERROR_RX_RECORD_TOO_LONG.
The certificates are issued and signed, I was wondering where I should go from here. Thanks :)
SHARD2
const options = {
key: './server.key',
cert: './server.cert'
};
var https = require('https').Server(options);
https.listen(443, function () {
// console.log('Https listening on *: 443');
});
let WebSocket = require('ws');
let socket = new WebSocket.Server({ server:https });
socket.on('connection', function (ws, req) {
ws.on('message', (msgRaw) =>{
});
ws.on('close', function(code, reason) {
});
ws.on('error', function(error) {
console.log(error);
ws.close();
});
});
CLIENT
function connect() {
"use strict";
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
alert('Your browser doesn\'t support WebSocket');
return;
}
wss = new WebSocket('wss://123.123.123.120/:443');
wss.onmessage = function(event) {
};
wss.onerror = function(event) {
console.log(`wss error: ${JSON.stringify(event)}`);
};
wss.onclose = function(event) {
};
}
Useful sys diagram?
I am using nodejs to run the server, there is no log file
This is my server.js
const https = require('https');
const fs = require('fs');
const ws = require('ws');
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
const wss = new ws.Server({noServer: true});
function accept(req, res) {
// all incoming requests must be websockets
if (!req.headers.upgrade || req.headers.upgrade.toLowerCase() != 'websocket') {
res.end();
return;
}
// can be Connection: keep-alive, Upgrade
if (!req.headers.connection.match(/\bupgrade\b/i)) {
res.end();
return;
}
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onConnect);
}
function onConnect(ws) {
ws.on('message', function (message) {
let name = message.match(/([\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]+)$/gu) || "Guest";
ws.send(`${name}!`);
//setTimeout(() => ws.close(1000, "Bye!"), 5000);
});
}
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
This is my code in react
componentDidMount() {
var connection = new WebSocket('wss://localhost:8000/');
connection.onopen = function(e) {
connection.send("add people");
};
connection.onmessage = function(event) {
// alert(`[message] Data received from server: ${event.data}`);
console.log("output ", event.data);
};
}
While I am trying to connect with web-socket with my jsx file its give me an error which is Firefox can’t establish a connection to the server at wss://localhost:8000/.
Your implementaion needs some changes. In the backend server, you forgot to call the onConnect function. So your ws.on method will never call.
Also, you imported the ws and create a WebSocket server wss, but you add some event listener on ws wrongly, you should add listener on your Websocket instance (wss):
// rest of the codes ...
const was = new ws.Server({noServer: true})
wss.on('connection`) {
// do something here ...
}
// rest of the codes ...
https.createServer(options, () => {
// do something here ...
})
There are some examples of how to create the WebSocket server along with the HTTP server on ws npm page.
I was trying to make a Polyfill.io server as a microservice on AWS Lambda, it was supposed to run a JavaScript file on a GET request.
When I run the service locally the call goes through but it returns an undefined object instead of JS file.
I'm running it locally using serverless, my code is based on polyfill.io's github repo
I've modified the service/index.js to be like so:
'use strict';
const express = require('express');
const path = require('path');
const Raven = require('raven');
const morgan = require('morgan');
const shrinkRay = require('./shrink-ray');
const app = express().enable("strict routing");
const one_day = 60 * 60 * 24;
const one_week = one_day * 7;
const one_year = one_day * 365;
app.use(shrinkRay({
brotli: {quality: 11}
}));
let ravenClient;
// Log requests
if (process.env.ENABLE_ACCESS_LOG) {
app.use(morgan('method=:method path=":url" request_id=:req[X-Request-ID] status=:status service=:response-time bytes=:res[content-length]'));
}
process.on('uncaughtException', (err) => {
console.log('Caught exception', err);
});
// Set up Sentry (getsentry.com) to collect JS errors.
if (process.env.SENTRY_DSN) {
const about = require(path.join(__dirname, '../about.json'));
ravenClient = new Raven.Client(process.env.SENTRY_DSN, {
release: about.appVersion || process.env.SENTRY_RELEASE || 'unknown'
});
ravenClient.patchGlobal();
app.use(Raven.middleware.express.requestHandler(ravenClient));
}
// Do not send the X-Powered-By header.
app.disable("x-powered-by");
// Default response headers
app.use((req, res, next) => {
// Ensure our site is only served over TLS and reduce the chances of someone performing a MITM attack.
res.set('Strict-Transport-Security', `max-age=${one_year}; includeSubdomains; preload`);
// Enables the cross-site scripting filter built into most modern web browsers.
res.set('X-XSS-Protection', `1; mode=block`);
// Prevents MIME-sniffing a response away from the declared content type.
res.set('X-Content-Type-Options', `nosniff`);
// Sets content-type
res.set('Content-Type', `application/javascript`);
// Prevents clickjacking by prohibiting our site from being included on other domains in an iframe.
res.set('X-Frame-Options', `sameorigin`);
res.set('Cache-Control', 'public, s-maxage=' + one_year + ', max-age=' + one_week + ', stale-while-revalidate=' + one_week + ', stale-if-error=' + one_week);
res.set('Surrogate-Key', process.env.SURROGATE_KEY || 'polyfill-service');
res.set('Timing-Allow-Origin', '*');
return next();
});
/* Routes */
app.use(require('./routes/api.js'));
app.use(require('./routes/meta.js'));
app.use('/test', require('./routes/test.js'));
if (process.env.RUM_MYSQL_DSN) {
app.use(require('./routes/rum.js'));
}
app.use(/^\/v[12]\/assets/, express.static(__dirname + '/../docs/assets'));
if (process.env.SENTRY_DSN) {
app.use(Raven.middleware.express.errorHandler(ravenClient));
}
module.exports.node = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(event, app);
};
This is my serverless.yml:
service: serverless-node
provider:
name: aws
region: us-east-1
stage: dev
runtime: nodejs6.10
functions:
node:
handler: service/index.node
events:
- http:
path: node
method: get
I think you need to pass back the response object in the callback in the handler e.g.
callback(null, response);
I took a game that my friend made and wanted to make it playable across browsers by sending keypress data between peers with WebRTC and websockets. However, I get this error in the console:
WebSocket connection to 'ws://localhost:3000/' failed: Connection closed before receiving a handshake response
My server file has the following few lines:
'use strict';
const express = require('express');
const SocketServer = require('ws').Server;
const path = require('path');
const PORT = process.env.PORT || 3000;
const INDEX = path.join(__dirname, 'index.html');
const server = express();
server.use(express.static(path.join(__dirname, 'lib')));
server.use('/assets', express.static(path.join(__dirname, 'assets')));
server.listen(PORT, () => console.log(`Listening on ${ PORT }`));
const wss = new SocketServer({ server });
var users = {};
let usernames = [];
wss.on('connection', function(connection) {
connection.on('message', function(message) {
var data;
try {
data = JSON.parse(message);
} catch (e) {
console.log("Invalid JSON");
data = {};
}
switch (data.type) {
case "login":
console.log("User logged", data.name);
if(users[data.name]) {
sendTo(connection, {
type: "login",
success: false
});
} else {
users[data.name] = connection;
connection.name = data.name;
usernames.push(data.name);
sendTo(connection, {
type: "login",
success: true,
users: usernames
});
}
break;
case "offer":
console.log("Sending offer to: ", data.name);
var conn = users[data.name];
if(conn != null) {
connection.otherName = data.name;
sendTo(conn, {
type: "offer",
offer: data.offer,
name: connection.name
});
}
break;
case "answer":
console.log("Sending answer to: ", data.name);
var conn = users[data.name];
if(conn != null) {
connection.otherName = data.name;
sendTo(conn, {
type: "answer",
answer: data.answer
});
}
break;
case "candidate":
console.log("Sending candidate to:",data.name);
var conn = users[data.name];
if(conn != null) {
sendTo(conn, {
type: "candidate",
candidate: data.candidate
});
}
break;
case "leave":
console.log("Disconnecting from", data.name);
var conn = users[data.name];
conn.otherName = null;
if(conn != null) {
sendTo(conn, {
type: "leave"
});
}
break;
default:
sendTo(connection, {
type: "error",
message: "Command not found: " + data.type
});
break;
}
});
And the client side of the connection looks as follows:
const Game = require("./game");
const GameView = require("./game_view");
var HOST = location.origin.replace(/^http/, 'ws');
console.log('host: ', HOST);
console.log(process.env.PORT);
document.addEventListener("DOMContentLoaded", function() {
const connection = new WebSocket(HOST);
.....
This is the point that the error occurs and this is the caught error that I get:
bubbles
:
false
cancelBubble
:
false
cancelable
:
false
composed
:
false
currentTarget
:
WebSocket
defaultPrevented
:
false
eventPhase
:
0
isTrusted
:
true
path
:
Array(0)
returnValue
:
true
srcElement
:
WebSocket
target
:
WebSocket
timeStamp
:
213.01500000000001
type
:
"error"
__proto__
:
Event
I am not too familiar with server side programming and was trying to understand. I tried looking up this issue, but it seems like a variety of different things can cause this. If you want to see the repository you can see and try it yourself (uses webpack): SlidingWarfare Repo
The confusion starts here:
const server = express();
The express function doesn't really return a server, it returns an application. Commonly, the variable used for this is app, but that's of course nothing more than convention (i.e. not a requirement).
However, it becomes an issue when you pass the app to the WS server:
const wss = new SocketServer({ server });
That's because SocketServer requires an HTTP server instance, which server is not.
Here's a fix, without renaming your variables:
let httpServer = server.listen(PORT, () => console.log(`Listening on ${ PORT }`));
...
const wss = new SocketServer({ server : httpServer });
(because when you call .listen() on the Express instance, it will return an HTTP server instance)
Using the variable naming convention it would be this:
const app = express();
app.use(express.static(path.join(__dirname, 'lib')));
app.use('/assets', express.static(path.join(__dirname, 'assets')));
let server = app.listen(PORT, () => console.log(`Listening on ${ PORT }`));
const wss = new SocketServer({ server });
Currently I am writing a NS app that will communicate with a WebSocket over SSL. Here is server's code (server.js):
var fs = require('fs');
var cfg = {
port: 8082,
ssl_key: fs.readFileSync('keys/server.key'),
ssl_cert: fs.readFileSync('keys/server.crt'),
ca: fs.readFileSync('keys/ca.crt')
};
var httpServ = require('https');
var WebSocketServer = require('ws').Server;
var app = null;
// dummy request processing
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
app = httpServ.createServer({
// providing server with SSL key/cert
key: cfg.ssl_key,
cert: cfg.ssl_cert,
ca: cfg.ssl.ca,
passphrase: '1234',
requestCert: true,
rejectUnauthorized: false,
}, processRequest ).listen( cfg.port );
var wss = new WebSocketServer( { server: app } );
wss.on('connection', function(ws) {
console.log("Connected!");
ws.on('message', function(message) {
console.log('received: %s', message);
});
ws.send('something');
});
Server is running well without problem. Below is the client code (wsclient.js):
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082');
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
When I ran the client by typing node wsclient.js, it throw the following error:
Error: unable to verify the first certificate
Obviously, the error was caused by not providing the certificate info to the request. But I have no idea how to get this done in my client code. Thanks a lot for any clues or suggestions.
Finally I found the answer:
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082',{
key: fs.readFileSync('./keys/client.key'),
cert: fs.readFileSync('./keys/client.crt'),
ca: fs.readFileSync('./keys/ca.crt')
});
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
Now it works!