2

I'm trying to work with socket.io, but when I run it on server , with https, my socket.io does't work.

My app.js

let express = require('express');
let path = require('path');
let favicon = require('serve-favicon');
let logger = require('morgan');
let cookieParser = require('cookie-parser');
let bodyParser = require('body-parser');

let index = require('./routes/index');
let users = require('./routes/users');
let dashboard = require('./routes/dashboard');



let app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'public/images', 'chatbotico.png')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(methodOverride('X-HTTP-Method-Override'));
app.use(session({secret: 'supernova', saveUninitialized: true, resave: true}));
app.use(passport.initialize());
app.use(passport.session());

// Session-persisted message middleware
app.use(function(req, res, next){
    let err = req.session.error,
        msg = req.session.notice,
        success = req.session.success;

    delete req.session.error;
    delete req.session.success;
    delete req.session.notice;

    if (err) res.locals.error = err;
    if (msg) res.locals.notice = msg;
    if (success) res.locals.success = success;

    next();
});


app.use('/', index);
app.use('/users', users);
app.use('/users/dashboard', dashboard);

// realtime chatbot
    let socket = require('./config/sock');
    // Socket connection
    socket.conn();
socket.fromClient();


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  let err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

So Instead of using the socket.io on app.js, I've created a function that it's being called from app and hold all socket configuration

./config/sock

let app = require('express')();
let https = require('https');
let fs = require('fs');

let options = {
    key: fs.readFileSync('./server.key'),
    cert: fs.readFileSync('./server.crt'),
    requestCert: false,
    rejectUnauthorized: false
};


let server = https.createServer(options, app);


let io = require('socket.io')(server);
io.set("transports", ["xhr-polling","websocket","polling", "htmlfile"]);

let conn = function() {
    server.listen(8080, function(){

    });

    app.get('/', function (req, res) {
        res.set('Content-Type', 'text/xml; charset=utf-8');
        res.sendfile(__dirname + '/index.html');
    });
};

let fromClient = function() {
    io.on('connection', function (socket) {
        socket.on('fromClient', function (data) {
            console.log(data);
            });
        });
    });
};
module.exports = {conn,fromClient};

So from my client side, i've import socket.io js on handlebars, routered on ./routes/dashboard

./views/dashboard/dashboard.hbs

<html>
[...]
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script src="../javascripts/convo.js"></script>
[...]
<html>

with this import I try to connect with the server side on convo.js

./public/convo.js

let socket = io.connect('https://localhost:8080', { secure: true, reconnect: true, requestCert: false, rejectUnauthorized: false });

socket.emit('fromClient', { 'client' : 'some value'});

My problem is, I've tried everything to make my browser allow these https connection with self-signed certificate. And I don't know how to make it pass through.

  localhost:8080 uses an invalid security certificate. 
The certificate is not trusted because it is self-signed. 
The certificate is not valid for the name localhost. Error code: 
SEC_ERROR_UNKNOWN_ISSUER 

Could someone give me a light. This is not a product, it's a college project and I don't want to buy a certificate

Lucas Oliveira
  • 668
  • 6
  • 22

2 Answers2

1

I've lived through this problem. (Browsers really will not cooperate any more. Thanks, all you stupid cybercriminals in the world for ruining it for the rest of us.)

First, edit your machine's hosts file to contain an entry like

lucas.example.com   127.0.0.1

so you can hit http://lucas.example.com:8080 instead of http://localhost:8080 from your own machine. Get that to work. (Use your favorite search engine to figure out how to edit your hosts file.)

Second, make yourself a self-signed certificate with the common name of lucas.example.com. Install that certificate in your local machine's web server. Hit https://lucas.example.com:8080. You'll get a certificate error in your browser. Override it and convince yourself you can see the localhost via https.

Then figure out how to import your self-signed certificate into your browser and tell your browser to trust it. This may help. Getting Chrome to accept self-signed localhost certificate

Then you should be able to do wss access from a browser.

Finally, you need to get node.js on your machine to trust your self-signed cert. This may help. How do I use a self signed certificate for a HTTPS Node.js server?

If the worst comes to the worst, you can buy a one-year cert from namecheap.com (reseller for Comodo) for less than US$10. You'll have to prove you own the domain though.

Or, maybe pester the IT department at your university, or get your professor to do that. Proper TLS certificates should be part of any properly configured university development laboratory. They should get a wildcard certificate for something like *.studentlab.cs.uni.edu and let you make your own lucas.studentlab.cs.uni.edu for this kind of work.

O. Jones
  • 103,626
  • 17
  • 118
  • 172
1

The O. Jones answer helped me a lot. But I've changed my approach to using socket.io

I hook the socket with the same server as express.

So on app.js , I've changed the socket connection:

// Socket connection
let server = require('http').Server(app);
socket.fromClient(server);

And exports to bin/www, the server variable too

module.exports = {app: app, server: server};

on bin/www i've imported the app and server, and run it:

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

    var app = require('../app').app;

var server = require('../app').server;
/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);

So this allowed me to use my socket.io(on server side) within the up running express server.

let api = require('./api');
let ipfs = require('./handlefiles');
let funct = require('./function');
let io;


let fromClient = function(server) {

    io = require('socket.io')(server);

    io.on('connection', function (socket) {
        socket.on('fromClient', function (data) {
            api.getRes(data.client).then(function(res){
                socket.emit('fromServer', { server: res.message, treat: res.action });
            });
        });
    });
};

module.exports = {fromClient};

On the client side, I've just call localhost(or the host desired)

let socket = io('//localhost:3000');

This hook up the client withing the server-side and allowed me to run my application without need a certificate for that, both on development and production like server.

Lucas Oliveira
  • 668
  • 6
  • 22