HttpOnly cookie can be accessed in a node client? - node.js

I'm new to node and going through some tutorials. I've got a simple node server running this code:
// SERVER CODE
const http = require('http');
const Cookies = require('cookies');
const port = 3000;
const requestHandler = (request, response) => {
cookies = new Cookies(request, response);
cookies.set("foo", "bar", { httpOnly: true });
response.end('Hello Node.js Server!');
}
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err);
}
console.log(`server is listening on ${port}`);
})
And I have another .js file that tries to access this server:
//CLIENT CODE
const http = require('http')
http.get('http://machine_name:3000', (
console.log(res.headers['set-cookie']);
});
From my understanding, httponly cookies should be unable to be available by client Javascript. When I run the client code though, I get:
[ 'foo=bar; path=/; httponly' ]
Is this right? Am I not setting it up correctly? I feel like this is an error since the httponly property means I shouldn't be able to access it via Javascript.

What you are doing is doing it in the right way and this you can try with your browser.
Si tienes un archivo index con el siguiente contenido:
// index.js file
const http = require('http');
const Cookies = require('cookies');
const port = 3000;
const requestHandler = (request, response) => {
cookies = new Cookies(request, response);
cookies.set("foo", "bar", { httpOnly: true });
response.end('Hello Node.js Server!');
}
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err);
}
console.log(`server is listening on ${port}`);
})
When you execute the command
node index.js
And you open your browser, open the console and execute the following
console.log( document.cookie ) // this not return your cookies
But if you have { httpOnly: false } you can get the following:
"other-cookies; foo=bar"
This is because JavaScript uses cookies more in the browser itself than in the console, if you have the httpOnly flag activated you can be 100% sure that no JS script can use it.
Read more about cookies

Related

Express and Websocket to run on the same port on the same file

I'm running two apps that sends real-time messages to each other using websocket and also generate a random link using express.js, now i hosted the server with both react apps to my vps host and want to make the websocket connection secure (wss://) but i realize i'll have to get the express server on the same port too, so the ssl/tsl works for both - so how do i do that?
Here is my full code, all on the same file:
const webSocketServerPort = 8000;
const webSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer(); server.listen(webSocketServerPort); console.log('Listening on port 8000');
const wsServer = new webSocketServer({ httpServer: server })
//GEERTOOOO
const express = require('express'); const cors = require('cors'); const fs = require('fs'); const app = express();
app.use(cors({ origin: '*' }));
app.get('/', (req, res) => { // Generate a random 6-character string const linkId = Math.random().toString(36).substr(2, 6);
// Save the link in the lex.json file fs.readFile('lex.json', (err, data) => { if (err) { console.error(err); res.status(500).send('Error generating link'); return; }
const links = JSON.parse(data);
links[linkId] = {
destination: 'http://localhost:4000/',
expires: Date.now() + 1000 * 60 * 5 // expires in 5 minutes
};
fs.writeFile('lex.json', JSON.stringify(links), (err) => {
if (err) {
console.error(err);
res.status(500).send('Error generating link');
return;
}
// Send the link back to the client
res.send(`http://localhost:3000/${linkId}`);
});
}); });
app.get('/:linkId', (req, res) => {
fs.readFile('lex.json', (err, data) => {
if (err) { console.error(err); res.status(500).send('Error retrieving link');
return;
}
const links = JSON.parse(data);
const link = links[req.params.linkId];
if (!link) {
res.status(404).send('Link not found');
return;
}
// Check if the link has expired
if (link.expires < Date.now()) {
res.status(410).send('Link has expired');
return;
}
// Redirect to the destination
res.redirect(link.destination);
}); });
app.listen(3000, () => { console.log('Server listening on port 3000'); });
//GEERTOOOO
const clients = {};
const getUniqueID = () => { const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return s4() + s4() + '-' + s4(); }
wsServer.on('request', (request) => { var userID = getUniqueID();
const connection = request.accept(null, request.origin); clients[userID] = connection;
connection.on('message', (message) => {
if (message.type === 'utf8') {
for(var key in clients) {
if (clients[key] !== clients[userID]) {
clients[key].sendUTF(message.utf8Data);
console.log(`Sent Message to: ${clients[key]}`);
}
}
}
}) })
Note: the express server is on port 3000 and the websocket server runs on port 8000.
I,ve tried just changing the port to same thing but i get an error when trying to use the websocket server for messages.
THE PURPOSE OF ALL THIS IS JUST TO MAKE THE WEBSOCKET CONNECTION AND EXPRESS CONNECCTION SECURE SO MY APPS (with letsencrypt ssl) can connect to the servers
It is not possible to create two separate server instances, both listening on the same port. But, specifically for a webSocket, you can share one server instance between Express and the webSocket server code. This is possible because a webSocket connection always starts with an http request (thus it can be listened for using your Express http server. And, because these http requests that initiate a webSocket all contain identifying headers they can be separated out from the regular http requests for Express by looking at the headers. The webSocket server code already knows how to do that for you.
To do that, first capture the Express server instance:
const server = app.listen(3000, () => { console.log('Server listening on port 3000'); });
Then, use that server instance when you create your webSocket server.
const wsServer = new webSocketServer({ httpServer: server });
Then, remove this code because you don't want to create yet another http server instance for the webSocket server:
const server = http.createServer();
server.listen(webSocketServerPort);
console.log('Listening on port 8000');

node js http createServer socket

The doubt with with code is two things:
When i send request through a browser, i dont get a console log message as "connected" but if i use http.get() or http.request() , it works fine
2)The "connect" event receives a callback with req,clientSocke,head ! now where can i see the server socket ?
const http=require("http")
const server=http.createServer()
server.on("connect",(req,c_socket,head)=>{
console.log("connected")
})
server.listen(5000,()=>{console.log("server up)})
when you access the server via browser, the method is using GET not CONNECT. That's why console.log does not show.
if you want console.log to show when accessing from the browser, you can use request event.
this is an explanation from node.js docs.
'connect' event is emitted each time a server responds to a request
with a CONNECT method. If this event is not being listened for,
clients receiving a CONNECT method will have their connections closed.
node.js docs
you can make a socket server with a net package with createSever method.
this is an example of how to make a simple request to the socket server.
const http = require('http');
const net = require('net');
const { URL } = require('url');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('hello world');
});
server.on('connect', (req, clientSocket, head) => {
console.log('connected');
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write(
'HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n'
);
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
server.listen(5000, () => {
console.log('server up');
});
// Make a request to a tunneling server
const req = http
.request({
port: 5000,
host: 'localhost',
method: 'CONNECT',
path: 'www.google.com:80',
})
.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
);
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
console.log('end');
});
});

Automatic exit - NodeJS https webserver

To elaborate on the question in the title,
I have made a simple app with js that runs on a node server. I have a thumbdrive that contains a folder and a start.bat file. Start.bat, as the name implies, switches the directory to my server folder and starts the server. Start.bat also starts another process that opens the edge browser to localhost in kiosk mode. When a user starts start.bat, the app will appear on the screen with the server running in the background. When the user exits the edge browser, they are then required to CTRL + C out of the server cmd prompt to properly shut down the server.
I need a system which effectively automatically shuts down the server after the Edge browser has been closed. I am not sure if it is possible to tie together the closing of the browser and the node server and am yet to find a solution online. If anyone has any ideas regarding possible fixes to my problem I would love to hear it!
https-server.js
const https = require("https");
const path = require("path");
const fs = require("fs");
const ip = require("ip");
const process = require("process");
const app = express();
const port = 443;
process.chdir("..");
console.log("Current working dir: " + process.cwd());
var rootDir = process.cwd();
//determines what folder houses js, css, html, etc files
app.use(express.static(rootDir + "/public/"), function (req, res, next) {
const ip = req.ip;
console.log("Now serving ip:", "\x1b[33m", ip, "\x1b[37m");
next();
});
//determines which file is the index
app.get("/", function (req, res) {
res.sendFile(path.join(rootDir + "/public/index.html"));
});
var sslServer = https.createServer(
{
key: fs.readFileSync(path.join(rootDir, "certificate", "key.pem")),
cert: fs.readFileSync(path.join(rootDir, "certificate", "certificate.pem")),
},
app
);
//determines which port app (http server) should listen on
sslServer.listen(port, function () {
console.log(
"Server has successfully started, available on:",
"\x1b[33m",
ip.address(),
"\x1b[37m",
"listening on port:",
"\x1b[33m",
+port,
"\x1b[37m"
);
console.log("CTRL + C to exit server");
sslServer.close();
});
Will provide any needed information.
Have an endpoint registered to exit the process
app.get('/shutdown', (req, res, next) => {
res.json({"message": "Received"});
next();
}, () => {
process.exit();
});
Then register a listener for onbeforeunload to do a request to this endpoint.
let terminateCmdReceived = false;
async function shutdown(e) {
let response;
if (!terminateCmdReceived) {
e.preventDefault();
try {
response = await fetch('http://localhost:3000/shutdown');
const json = await response.json();
if(json.message === "Received") {
terminateCmdReceived = true;
window.close();
}
} catch (e) {
console.error("Terminate Command was not received");
}
}
}
window.onbeforeunload = shutdown

Setup Vue.js with nodejs server

Im trying to get nodejs http to serve a vuejs application.
Vue is configured as SPA with history mode enabled.
My nodejs server is set up like this:
http.createServer((req, res) => {
fs.readFile('dist/index.html', 'utf-8', (err, content) => {
if (err) {
console.log('We cannot open "index.html" file.')
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}).listen(port, () => {
console.log('Server listening on: http://localhost:%s', port)
})
Taken from here: https://router.vuejs.org/guide/essentials/history-mode.html#native-node-js
This does indeed start the server and i can navigate to localhost:3000 but see a blank page.
Problem is, that with this configuration the server always returns the index.html file. Which is not wanted for static files like .js files, which results in errors.
How do i have to configure my http server so Vue will work as expected?
You have to serve the whole dist folder, not just the index file so it can get the whole vuejs app.
You can make this easier for you by using modules like https://github.com/cloudhead/node-static
const static = require('node-static');
const http = require('http');
const distFolder = new static.Server('./dist');
http.createServer(function (req, res) {
distFolder.serve(req, res);
}).listen(port, () => {
console.log('Server listening on: http://localhost:%s', port)
})
With expressjs this would become
const express = require('express')
const app = express()
app.use(express.static('dist'))
app.listen(port, () => {
console.log('Server listening on: http://localhost:%s', port)
})
EDIT:
Fallback for history mode:
http.createServer(function (req, res) {
distFolder.serve(req, res, function (err, result) {
// Fallback for history mode
if (err !== null && err.status === 404) {
distFolder.serveFile('/index.html', 200, {}, req, res);
}
});
}).listen(port, () => {
console.log('Server listening on: http://localhost:%s', port)
})
You are right, the example is a bit misleading. They say "If the URL doesn't match any static assets, it should serve the same index.html page that your app lives in." on the page but example completely ignores other static files.
You can use express - see this SO answer

Node.js + React: How to POST

Follow on from this question: Axios can GET but not POST to the same URL
I've been trying to figure this out for too long now.
I want to POST from my React app to a .JSON file. Can anyone tell me what I'm doing wrong?
My AJAX POST function using axios always returns a 404. I'm listening for it on the node server but app.post never fires.
Thanks.
POST request from my React app:
postJson = (postJsonData) => {
axios.post('./postJson/', {
postJsonData
})
.then(function (response) {
console.log("success!");
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
app.js (node server):
/*========== Default Setup for node server copied from node website ==========*/
const http = require('http');
const hostname = '127.0.0.1';
const port = 3001;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
/*========== Listen for POST (Trying to get the data from my REACT app
- will then assign it to "obj" below) ==========*/
var express = require("express");
var myParser = require("body-parser");
var app = express();
app.post("./postJson/", function(request, response) {
console.log("MURRRR");
console.log(request.body); //This prints the JSON document received (if it is a JSON document)
/*=== JSON Stuff ===*/
var jsonfile = require('jsonfile')
var file = './scene-setup.json'
var obj = {name: 'JP'}
jsonfile.writeFile(file, obj, function (err) {
console.error(err)
})
});
//Start the server and make it listen for connections on port 3000
app.listen(3000, function(){
console.log("server is listening to 3000");
});
Two things I noticed:
Your post endpoint doesn't need a leading "." I would make it just "/postJson"
Make sure you are posting to "http://localhost:3000/postJson"
Make sure you have the network tab open to see the actual URL you are requesting to.
Cheers
Turns out both react and my node server were running on localhost:3000 simultaneously which is apparently not okay.
Running my node server on localhost:3001 from a new command line window allowed me to do both at the same time.
Not sure how this would work when making a production build though.

Resources