Koa HTTPS connection with koa-sslify module Without Reverse Proxy - ssl

I try to make HTTPS connection for Koa server with that module https://www.npmjs.com/package/koa-sslify but I get error "AssertionError: app.use() requires a generator function"
'use strict';
var app = require('application'),
enforceHttps = require('koa-sslify'),
config = require('config'),
fs = require('fs'),
path = require('path'),
routes = fs.readdirSync(path.join(__dirname, '../routing')).sort();
routes.forEach(function (route) {
require('../routing/' + route);
});
// Force HTTPS on all page
app.use(enforceHttps({
trustProtoHeader: true
}));
app.listen(config.server.port,config.server.host);
UPD:
I used NGINX instead, because probably it does that work better and use less resources

try in this way, but better use NGINX as a reverse proxy server
const Koa = require('koa');
const https = require('https');
const fs = require('fs');
const { default: enforceHttps } = require('koa-sslify');
const app = new Koa();
// Force HTTPS using default resolver
app.use(enforceHttps({
port: 443
}));
// index page
app.use(ctx => {
ctx.body = `hello world from ${ctx.request.url}`;
});
// SSL options
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
}
// start the server
https.createServer(options, app.callback()).listen(443);

Related

StackBlitz - ECONNREFUSED when connecting to local machine

I'm running a simple express server on my machine and attempting to ping it from a StackBlitz web container, but am getting the following error when trying to connect:
FetchError: request to https://192.168.1.23:8443/ failed, reason: connect ECONNREFUSED 192.168.1.23:8443
I've tried:
using https
allowing cors
setting up host: 0.0.0.0
Here's the code for the server, its a vanilla node project, just with express and cors.
var fs = require('fs');
var http = require('http');
var https = require('https');
var cors = require('cors')
var privateKey = fs.readFileSync('key.pem', 'utf8');
var certificate = fs.readFileSync('cert.pem', 'utf8');
var credentials = { key: privateKey, cert: certificate };
var express = require('express');
var app = express();
app.use(cors())
app.get('/', (_, res) => res.send(`hello`));
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
httpServer.listen(8080, '0.0.0.0');
httpsServer.listen(8443, '0.0.0.0');
Here is the code for the stackblitz container, it is a vanilla node project with node-fetch:
import fetch from 'node-fetch';
const url = 'https://192.168.1.23:8443/';
const response = await fetch(url)
.catch((err) => console.error(err));
console.log(response?.status || 'failed');
Try use a html page to connect to your server. If still error then try embed an iframe in your html.

Express JS Websocket Connection to wss failed without error but still able to communicate

I am using an Express JS to initiate websocket connection. Below is the following configuration that I used.
socket.js
const ip_address = `${process.env.MIX_HTTPS_APP_URL}`;
const socket_port = `${process.env.MIX_EXPRESS_PORT}`;
const URL = ip_address + ":" + socket_port;
export const socket = io(URL, { autoConnect: true });
socket.onAny((event, ...args) => {
// console.log(event, args);
});
index.js
const app = express();
// app settings
/** Create HTTP server. */
const privateKey = fs.readFileSync(env.privateKey, "utf8");
const certificate = fs.readFileSync(env.certificate, "utf8");
const options = {
key: privateKey,
cert: certificate,
};
const server = https.createServer(options, app).listen(port);
/** Create socket connection */
const socketio = new Server(server);
global.io = socketio.listen(server, {
cors: {
origin: env.url,
},
});
global.io.on("connection", WebSockets.connection);
/** Listen on provided port, on all network interfaces. */
/** Event listener for HTTP server "listening" event. */
server.on("listening", () => {
console.log(`Listening on port:: ${env.url}:${port}/`);
});
Though I can emit and listen to socket, I am still getting this error message. How should I solve this so that users wont see this error message when they view the console?
With reference to your example, the listening on port should be on http server, & socket.io should just attach to on new conn.
see doc https://socket.io/docs/v4/server-initialization/#with-an-https-server
Hope this helps.

https settings for ionic app server settings

The application is build in MEAN stack and we are able to run the port successfully in 3001 port and our web application is running perfectly in HTTPS ... Now we have build the ionic app for the same application where we are using the same back up..
The ionic app is not logging in or form is not getting submitted..
Do we need to use a seperate port for the same application to use for ionic like
ionic in 8001
and web application (Angular) in 3001
What is the procedure to run the ionic app in SSL (https)
Any suggestion will be great helpful and thank you in advance
My code is as follows which worked perfectly:
var express = require('express');
var DataController = require('./user/DataController');
var UserController = require('./user/UserController');
var db = require('./database/database-db');
var cors = require('cors');
var app = express();
app.use(cors());
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
// res.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
// res.setHeader("Access-Control-Allow-Origin", "http://localhost:8100");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use('/user', UserController);
app.use('/data', DataController);
app.get('/', function(req, res){
res.send("Welcome to the secure mobile and web development world");
});
// This settings are for HTTPS, SSL web applications.
// var https = require("https");
// var fs = require("fs");
// var options = {
// key: fs.readFileSync("/home/path/ssl/keys/key.key"),
// cert: fs.readFileSync("/home/path/ssl/certs/crt.crt")
// };
// https.createServer(options,app).listen(3001);
// console.log('Welcome to the security world')
// This settings are only for HTTP sites
// var http = require("http");
// var fs = require("fs");
// http.createServer(app).listen(3001);
// console.log('Welcome to the security')
//This settings are for both HTTPS,HTTP SSL web applications.
var https = require("https");
var http = require("http");
var fs = require("fs");
var options = {
key: fs.readFileSync("/home/path/ssl/keys/key.key"),
cert: fs.readFileSync("/home/path/ssl/keys/crt.crt")
};
https.createServer(options,app).listen(3001);
console.log('Welcome to the security world')
http.createServer(app).listen(3002);
console.log('Welcome to the proxy world')

compoundjs support both ssl and normal http

I needed to use SSL on my site in certain situations,
I have followed the example in the readme
require('compound').createServer({
key: fs.readFileSync('/tmp/tls.key').toString(),
cert: fs.readFileSync('/tmp/tls.cert').toString()
});
My server.js is
#!/usr/bin/env node
var fs = require('fs');
/**
* Server module exports method returning new instance of app.
*
* #param {Object} params - compound/express webserver initialization params.
* #returns CompoundJS powered express webserver
*/
var app = module.exports = function getServerInstance(params) {
params = params || {};
// specify current dir as default root of server
params.root = params.root || __dirname;
params["key"] = fs.readFileSync('/tmp/tls.key').toString();
params["cert"] = fs.readFileSync('/tmp/tls.cert').toString();
return require('compound').createServer(params);
};
if (!module.parent) {
var port = process.env.PORT || 3000;
var host = process.env.HOST || '0.0.0.0';
var server = app();
server.listen(port, host, function () {
console.log(
'Compound server listening on %s:%d within %s environment',
host, port, server.set('env')
);
});
}
Now the problem is I can't get http, only https.
If I just put my cert and key inside of the config folder and have
**var app = module.exports = function getServerInstance(params) {
params = params || {};
// specify current dir as default root of server
params.root = params.root || __dirname;
return require('compound').createServer(params);
};**
Then I get some error that
config/tls.cert:1
tion (exports, require, module, __filename, __dirname) { -----BEGIN CERTIFICAT
^^^^^^^^^^^
SyntaxError: Unexpected identifier
at Module._compile (module.js:439:25)
What is the quickest and easiest way to get compoundjs to support both https and http routes, do I need to have two servers (like you would often with straight express)?
YES - need to have two servers like you do with express. So
var app = module.exports = function getServerInstance(params) {
params = params || {};
// specify current dir as default root of server
params.root = params.root || __dirname;
return require('compound').createServer(params);
};
var port = process.env.PORT || 80;
var host = process.env.HOST || '0.0.0.0';
var port_https = 443;
var server = app();
server.listen(port, host, function () {
server.set("confvar", process.env.SERVER_NAME);
console.log(
'Compound server listening on %s:%d within %s environment',
host, port, server.set('env')
);
});
if(fs.existsSync(PATH TO KEY GOES HERE)){
var apphttps = module.exports = function getServerInstance(params) {
params = params || {};
// specify current dir as default root of server
params.root = params.root || __dirname;
params.key = fs.readFileSync(PATH TO KEY GOES HERE).toString();
params.cert = fs.readFileSync(PATH TO CERT GOES HERE).toString();
return require('compound').createServer(params);
};
var serverhttps = apphttps();
serverhttps.listen(port_https, host, function () {
serverhttps.set("confvar", process.env.SERVER_NAME);
console.log(
'Compound https server listening on %s:%d within %s environment',
host, port_https, serverhttps.set('env')
);
});
}

node.js, socket.io with SSL

I'm trying to get socket.io running with my SSL certificate however, it will not connect.
I based my code off the chat example:
var https = require('https');
var fs = require('fs');
/**
* Bootstrap app.
*/
var sys = require('sys')
require.paths.unshift(__dirname + '/../../lib/');
/**
* Module dependencies.
*/
var express = require('express')
, stylus = require('stylus')
, nib = require('nib')
, sio = require('socket.io');
/**
* App.
*/
var privateKey = fs.readFileSync('../key').toString();
var certificate = fs.readFileSync('../crt').toString();
var ca = fs.readFileSync('../intermediate.crt').toString();
var app = express.createServer({key:privateKey,cert:certificate,ca:ca });
/**
* App configuration.
*/
...
/**
* App routes.
*/
app.get('/', function (req, res) {
res.render('index', { layout: false });
});
/**
* App listen.
*/
app.listen(443, function () {
var addr = app.address();
console.log(' app listening on http://' + addr.address + ':' + addr.port);
});
/**
* Socket.IO server (single process only)
*/
var io = sio.listen(app,{key:privateKey,cert:certificate,ca:ca});
...
If I remove the SSL code it runs fine, however with it I get a request to http://domain.example/socket.io/1/?t=1309967919512
Note it's not trying HTTPS, which causes it to fail.
I'm testing on chrome, since it is the target browser for this application.
I apologize if this is a simple question, I'm a node/socket.io newbie.
Use a secure URL for your initial connection, i.e. instead of "http://" use "https://". If the WebSocket transport is chosen, then Socket.IO should automatically use "wss://" (SSL) for the WebSocket connection too.
Update:
You can also try creating the connection using the 'secure' option:
var socket = io.connect('https://localhost', {secure: true});
The following is how I set up to set it up with express:
var app = require('express')();
var https = require('https');
var fs = require( 'fs' );
var io = require('socket.io')(server);
var options = {
key: fs.readFileSync('./test_key.key'),
cert: fs.readFileSync('./test_cert.crt'),
ca: fs.readFileSync('./test_ca.crt'),
requestCert: false,
rejectUnauthorized: false
}
var server = https.createServer(options, app);
server.listen(8080);
io.sockets.on('connection', function (socket) {
// code goes here...
});
app.get("/", function(request, response){
// code goes here...
})
Update : for those using lets encrypt use this
var server = https.createServer({
key: fs.readFileSync('privkey.pem'),
cert: fs.readFileSync('fullchain.pem')
}, app);
On the same note, if your server supports both http and https you can connect using:
var socket = io.connect('//localhost');
to auto detect the browser scheme and connect using http/https accordingly. when in https, the transport will be secured by default, as connecting using
var socket = io.connect('https://localhost');
will use secure web sockets - wss:// (the {secure: true} is redundant).
for more information on how to serve both http and https easily using the same node server check out this answer.
If your server certificated file is not trusted, (for example, you may generate the keystore by yourself with keytool command in java), you should add the extra option rejectUnauthorized
var socket = io.connect('https://localhost', {rejectUnauthorized: false});
Depending on your needs, you could allow both secure and unsecure connections and still only use one Socket.io instance.
You simply have to instanciate two servers, one for HTTP and one for HTTPS, then attach those servers to the Socket.io instance.
Server side :
// needed to read certificates from disk
const fs = require( "fs" );
// Servers with and without SSL
const http = require( "http" )
const https = require( "https" );
const httpPort = 3333;
const httpsPort = 3334;
const httpServer = http.createServer();
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
});
httpServer.listen( httpPort, function() {
console.log( `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
console.log( `Listening HTTPS on ${httpsPort}` );
});
// Socket.io
const ioServer = require( "socket.io" );
const io = new ioServer();
io.attach( httpServer );
io.attach( httpsServer );
io.on( "connection", function( socket ) {
console.log( "user connected" );
// ... your code
});
Client side :
var url = "//example.com:" + ( window.location.protocol == "https:" ? "3334" : "3333" );
var socket = io( url, {
// set to false only if you use self-signed certificate !
"rejectUnauthorized": true
});
socket.on( "connect", function( e ) {
console.log( "connect", e );
});
If your NodeJS server is different from your Web server, you will maybe need to set some CORS headers. So in the server side, replace:
const httpServer = http.createServer();
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
});
With:
const CORS_fn = (req, res) => {
res.setHeader( "Access-Control-Allow-Origin" , "*" );
res.setHeader( "Access-Control-Allow-Credentials", "true" );
res.setHeader( "Access-Control-Allow-Methods" , "*" );
res.setHeader( "Access-Control-Allow-Headers" , "*" );
if ( req.method === "OPTIONS" ) {
res.writeHead(200);
res.end();
return;
}
};
const httpServer = http.createServer( CORS_fn );
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
}, CORS_fn );
And of course add/remove headers and set the values of the headers according to your needs.
check this.configuration..
app = module.exports = express();
var httpsOptions = { key: fs.readFileSync('certificates/server.key'), cert: fs.readFileSync('certificates/final.crt') };
var secureServer = require('https').createServer(httpsOptions, app);
io = module.exports = require('socket.io').listen(secureServer,{pingTimeout: 7000, pingInterval: 10000});
io.set("transports", ["xhr-polling","websocket","polling", "htmlfile"]);
secureServer.listen(3000);
Server-side:
import http from 'http';
import https from 'https';
import SocketIO, { Socket } from 'socket.io';
import fs from 'fs';
import path from 'path';
import { logger } from '../../utils';
const port: number = 3001;
const server: https.Server = https.createServer(
{
cert: fs.readFileSync(path.resolve(__dirname, '../../../ssl/cert.pem')),
key: fs.readFileSync(path.resolve(__dirname, '../../../ssl/key.pem'))
},
(req: http.IncomingMessage, res: http.ServerResponse) => {
logger.info(`request.url: ${req.url}`);
let filePath = '.' + req.url;
if (filePath === './') {
filePath = path.resolve(__dirname, './index.html');
}
const extname = String(path.extname(filePath)).toLowerCase();
const mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json'
};
const contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, (error: NodeJS.ErrnoException, content: Buffer) => {
if (error) {
res.writeHead(500);
return res.end(error.message);
}
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
});
}
);
const io: SocketIO.Server = SocketIO(server);
io.on('connection', (socket: Socket) => {
socket.emit('news', { hello: 'world' });
socket.on('updateTemplate', data => {
logger.info(data);
socket.emit('updateTemplate', { random: data });
});
});
server.listen(port, () => {
logger.info(`Https server is listening on https://localhost:${port}`);
});
Client-side:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Websocket Secure Connection</title>
</head>
<body>
<div>
<button id='btn'>Send Message</button>
<ul id='messages'></ul>
</div>
<script src='../../../node_modules/socket.io-client/dist/socket.io.js'></script>
<script>
window.onload = function onload() {
const socket = io('https://localhost:3001');
socket.on('news', function (data) {
console.log(data);
});
socket.on('updateTemplate', function onUpdateTemplate(data) {
console.log(data)
createMessage(JSON.stringify(data));
});
const $btn = document.getElementById('btn');
const $messages = document.getElementById('messages');
function sendMessage() {
socket.emit('updateTemplate', Math.random());
}
function createMessage(msg) {
const $li = document.createElement('li');
$li.textContent = msg;
$messages.appendChild($li);
}
$btn.addEventListener('click', sendMessage);
}
</script>
</body>
</html>
For enterprise applications it should be noted that you should not be handling https in your code. It should be auto upgraded via IIS or nginx. The app shouldn't know about what protocols are used.
In case someone need a shorter form
var fs = require('fs');
var https = require('https');
var express = require('express');
var app = express();
var options = {
key: fs.readFileSync('/path-to/ssl.key'),
cert: fs.readFileSync('/path-to/ssl.cert')
};
var server = https.createServer(options, app);
var io = require('socket.io')(server);
This is my nginx config file and iosocket code. Server(express) is listening on port 9191. It works well:
nginx config file:
server {
listen 443 ssl;
server_name localhost;
root /usr/share/nginx/html/rdist;
location /user/ {
proxy_pass http://localhost:9191;
}
location /api/ {
proxy_pass http://localhost:9191;
}
location /auth/ {
proxy_pass http://localhost:9191;
}
location / {
index index.html index.htm;
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
location /socket.io/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:9191/socket.io/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
ssl_certificate /etc/nginx/conf.d/sslcert/xxx.pem;
ssl_certificate_key /etc/nginx/conf.d/sslcert/xxx.key;
}
Server:
const server = require('http').Server(app)
const io = require('socket.io')(server)
io.on('connection', (socket) => {
handleUserConnect(socket)
socket.on("disconnect", () => {
handleUserDisConnect(socket)
});
})
server.listen(9191, function () {
console.log('Server listening on port 9191')
})
Client(react):
const socket = io.connect('', { secure: true, query: `userId=${this.props.user._id}` })
socket.on('notifications', data => {
console.log('Get messages from back end:', data)
this.props.mergeNotifications(data)
})
I needed to get this to work with Debian 10, ISPConfig 3 and Let's Encrypt. Took me a while to work out the specifics. Maybe this saves someone else some timeā€¦
Server-side:
const fs = require('fs');
const https = require('https');
const express = require('express');
const socketio = require('socket.io');
const app = express();
const https_options = {
key: fs.readFileSync('/var/www/clients/client1/web1/ssl/your-domain.com-le.key'),
cert: fs.readFileSync('/var/www/clients/client1/web1/ssl/your-domain.com-le.crt'),
ca: fs.readFileSync('/root/.acme.sh/your-domain.example/fullchain.cer'),
requestCert: false,
rejectUnauthorized: false
}
const server = https.createServer(https_options, app);
server.listen(3000, () => {
console.log('server started ok');
});
const io = socketio(server, {
cors: {
origin: "https://your-domain.example",
},
secure: true
});
io.on('connection', (sock) => {
console.log('someone connected');
}
Client-side:
const sock = io('https://your-domain.example:3000/');
sock.on('status', (text) => {
add_text($('#status'), text);
});
Server side:
var ssl_options = {
ca: [fs.readFileSync('../ssl/cert1.crt'), fs.readFileSync('../ssl/cert2.crt'), fs.readFileSync('../ssl/cert3.crt')],
key: fs.readFileSync('../ssl/xxx.key'),
cert: fs.readFileSync('../ssl/xxx.example.crt'),
};
var wssServer = https.createServer(ssl_options,app); // Express app
wssServer.listen(4433, '0.0.0.0');
global.io = require("socket.io")();
io.listen(wssServer);
io.on( "connection", function( socket ) {
console.log( "user connected" );
});
Client-side (no luck with the built-in WebSocket API):
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js"></script>
<script>
const socket = io("https://xxx.example:4433",{ transports: ['websocket', 'polling', 'flashsocket'] });
</script>