Can't figure out SSL with node and express (https) - node.js

I've been working at making a website, but after getting my website to work I set out to try and get SSL so the annoying "warning" symbol would go away. Unfortunately I've come to a real impasse and all the resources I've found to help me work through this seem to be outdated or at least not compatible with what I'm doing.
My original working server.js file:
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '/index.html'));
});
app.listen(port);
What I tried but ends up not working:
const fs = require('fs');
const options = {
cert: fs.readFileSync('cert/certificate.crt'),
ca: fs.readFileSync('cert/ca_bundle.crt'),
key: fs.readFileSync('cert/private.key')
};
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 3000;
const httpsPort = process.env.PORT || 3030;
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '/index.html'));
});
app.listen(port);
httpsPort.createServer(options, app).listen(httpsPort);
I am struggling to wrap my head around the entire venture since I've started on this https issue.
Help would be greatly appreciated!

Uhm, there are a few issues here. First you try to listen on two different things. app.listen is a short version of http.createServer({ ...options }, app).
Second - your code is httpsPort.createServer(options, app).listen(httpsPort);, which basically translates to 3030.createServer(options, app).listen(3030). Here's what I usually do:
const https = require('https');
const server = https.createServer(options, app).listen(port)
If you would like to support both, then you need to include both http and https packages, and have an if-else (or something similar) so that you use the proper package to create the server.
You should not listen on the app in this scenario!

Related

Device login detection with node.js and react.js

I need to restrict users to login from multiple devices. I'm using react.js at the frontend and node.js as the backend. Which is the most reasonable way to handle this task?
I can not imagine how you can identify user browser 100 %. Cookies are browser based,so that could not solve the problem. Try Matteo Collina's pino logger, I think that it has many options.so you can choose most suitable for your task.
For example,this simple code
const express = require('express');
const pino = require('pino');
const expressPino = require('express-pino-logger');
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
const expressLogger = expressPino({ logger });
const PORT = process.env.PORT || 3000;
const app = express();
app.use(expressLogger);
app.get('/', (req, res) => {
logger.debug('Calling res.send');
res.send('Hello World');
});
app.listen(PORT, () => {
logger.info('Server running on port %d', PORT);
});
would show
"level":30,"time":1613817528986,"pid":17345,"hostname":"jholmes","msg":"Server running on port 3000"
You can pick IP,but would dynamic Id's you can not point pot to single user.
React also has plenty libraries for auth(ajv).

localhost:3000 not responding

I've just started learning node.js but when I try to launch the hello world code by writing on the terminal node server.js, localhost:3000 gives me the following error:
This page isn’t working;
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
I've been searching for 2h now and I've found nothing. I've checked the port 3000 in cmd with netstat -a -n -o and it says that the port is listening (so I guess it is working). So what is preventing me from accesing to that port.
Here it my JS files:
server.js:
const http = require('http');
const app = require('./app');
const port = process.env.PORT || 3000;
const server = http.createServer();
server.listen(port);
app.js:
const { request } = require('express');
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.status(200).json({
message: 'It works'
});
})
module.exports = app;
Add the required app to the createServer call:
const server = http.createServer(app);
In this way the http server can route your http requests to it.
Could process.env.PORT be set somewhere, causing your app to be hosted on that port instead?
An easy way to check would be to console.log the PORT variable in your script, and see if it has any value.
If it does have a value, trying going to localhost:PORT

Express Static Directory over HTTPS

I would like to implement Node.js with Express for static content over HTTPS. Scouring the Web reveals tons of examples of Express with HTTPS and tons of examples of Express serving a static directory, but I cannot find an example using all three Express, HTTPS and static.
Moreover, looking at the examples I can find, I cannot piece together how to accomplish this.
Here is what I have found:
Express Static Directory over HTTP
var fs = require('fs')
var app = require("express");
var server = app();
server.use(app.static(staticDir))
server.listen(webPort)
Express over HTTPS (without Static Directory)
const app = require('express')();
const https = require('https');
const server = https.createServer(
{
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
},
app
);
server.listen(APIPort);
When I try combining the two approaches, I get stuck because the static example bypasses createServer, and yet createServer is the crux of getting to HTTPS in the examples.
I'm sure the answer is simple, but I cannot arrive at or locate the solution.
Could you try the below code-snippet and see if it works for you?
const fs = require('fs');
const https = require('https');
const express = require('express');
const app = express();
app.use(express.static(process.env.SERVE_DIRECTORY));
app.get('/', function(req, res) {
return res.end('Serving static files!');
});
const key = fs.readFileSync(__dirname + '/selfsigned.key');
const cert = fs.readFileSync(__dirname + '/selfsigned.crt');
const options = {
key: key,
cert: cert
};
const server = https.createServer(options, app);
server.listen(PORT, () => {
console.log(`Serving on port ${PORT}`);
});
Please make sure to do the suitable changes before running the above code.

How can I adjust my NodeJs server code to responf to HTTPS requests?

I have a small nodejs server which is working without a problem. Now I am trying to make use of "HTTPS" for security reasons. I have the following code, but when I try to open the page in Firefox via link [http://192.168.2.22:8080/api/users], on the terminal I see DIRECTING >>> https://192.168.2.22:8080/api/users but in the browser, instead of the expected response, I encounter this error:
Secure Connection Failed An error occurred during a connection to
192.168.2.22:8080. SSL received a record that exceeded the maximum permissible length.
Error code: SSL_ERROR_RX_RECORD_TOO_LONG
// Modules /////////////////////////////////////////////////////////////////////
const db = require('./db.js');
// Packages ////////////////////////////////////////////////////////////////////
const colors = require('colors');
const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
const fs = require('fs');
// Constant Variables //////////////////////////////////////////////////////////
const PORT_SERVER = 8080;
const HOST = '192.168.2.22';
////////////////////////////////////////////////////////////////////////////////
app.use(express.json({limit: '50mb'}));
// app.use(express.urlencoded({limit: '50mb'}));
// set up a route to redirect http to https
app.get('*', function(req, res) {
console.log('DIRECTING >>> https ://' + req.headers.host + req.url);
res.redirect('https://' + req.headers.host + req.url);
});
app.get('/api/users/', async (req, res) => {
console.log('CHECK POINT !!!');
let users = await db.db.get_users();
console.log("USERS : " + users);
res.send(users);
});
// have it listen on 8080
app.listen(PORT_SERVER, () => console.log(`Listen at ${PORT_SERVER}...`));
How can I resolve this? I could not find a solution that I can easily apply to my code, I am kind of a newbie for NodeJs.
Thanks in advance
You have not configured your server for SSL. Configure SSL using the https module like below. In this example, I have created two express one for Http and one for https as we can not run both http and non https on same port.
const express = require('express');
const http = require('http'),
const https = require('https')
const fs = require('fs')
const httpApp = express()
const app = express()
const httpsOptions = {
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt")
};
httpApp.set('port',80);
httpApp.get("*", function (req, res, next) {
res.redirect("https://" + req.headers.host + "/" + req.path);
});
app.set('port', 443);
app.enable('trust proxy');
http.createServer(httpApp).listen(httpApp.get('port'), function() {
console.log('Express HTTP server listening on port ' + httpApp.get('port'));
});
https.createServer(httpsOptions, app).listen(app.get('port'), function() {
console.log('Express HTTPS server listening on port ' + app.get('port'));
});
The Best way to redirect from non-http to https is to use Nginx web server as a reverse proxy and define redirection rule in Nginx config file.
client--->nginx reverse proxy(with SSL and redirection rules)-->express server
try changing the port to 443, https runs on 443 by default!

Heroku socket.io server runs locally, but not anywhere else

Basically my socket.io server is only working for.. one computer only, I suppose. It works if I use Chrome, Chrome incognito, Edge. I tried using the app with my phone, while on the same Wifi, and that's where I encountered problems. It looked like socket.io just wouldn't work then. I feel like it's only working for one client (maybe ip, port issues?)
I use socket.io in pair with React js, and oh boy it was pain in the arse to make them work both locally and on Heroku.
Here's my server file /src/server/index.js
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4001; // Only this port works for some reason
const index = require("./routes/index");
const app = express();
const path = require('path');
const server = http.createServer(app);
const io = socketIo(server); // < Interesting!
io = socketIo.listen(app);
io.configure(function () {
io.set("transports", ["xhr-polling"]);
io.set("polling duration", 10); // Recommended from online guys
});
app.use(express.static(path.join(__dirname, '../../index')));
app.get('/', (req, res, next) =>
res.sendFile(index))
io.on("connection", socket => {
console.log("New client connected");
})
server.listen(port, () => console.log(`Listening on port ${port}`));
I use config file to dynamically change the server and I import it every time I need to connect to my socket via socket.io-client
let server = 'ws://XXXXXXXXXXXXX.herokuapp.com/socket.io/?EIO=4&transport=websocket';
const env = process.env.NODE_ENV;
if (env === 'development') {
server = 'http://127.0.0.1:4001';
}
module.exports = server;
What could be the problem? Why is only working on my root computer? Could be a dyno problem or something else?
I'm a complete beginner with both heroku and socket.io, so any information would be helpful.
**EDIT:
I am not sure, but I feel like a server running in my VS Code made it work in my heroku app. I have turned it off and the server just keeps sending net::ERR_CONNECTION_REFUSED error.
Solution:
Using mars/heroku-cra-node buildpack is a must. It seperates react-ui and server code. Port config: const port = process.env.PORT || 4001,
Client listens for: let server = window.location.hostname
Also good to have a seperate config file for clientside that has the following:
const env = process.env.NODE_ENV;
if (env === 'development') {
server = 'http://localhost:4001';
}
module.exports = server;
Then you won't have to change ports and servers in development (VSCode) or production (Heroku).

Resources