HTTPS Redirect in next js - javascript

I'm trying to do a http to https redirect using next,
so if the user enters the site at http://www.example.com redirect to https://www.example.com
I'm using GraphQL Yoga on the server side, so not sure how I could accomplish this in my index file on the server side.
I've tried using the meta tag and changing the protocol in the window object but no luck with doing so in server-side rendering.
Is there any way I can accomplish this redirect on the client side using next js or on the server side?
const cookieParser = require('cookie-parser')
const jwt = require('jsonwebtoken')
require('dotenv').config({path: '.env'})
const createServer = require('./createServer')
const db = require('./db')
const sslRedirect = require('heroku-ssl-redirect');
const server = createServer()
//Express middleware to handle cookies
server.express.use(cookieParser())
//decode JWT
server.express.use((req, res, next) => {
const { token } = req.cookies;
if (token) {
const { userId } = jwt.verify(token, process.env.APP_SECRET);
req.userId = userId;
}
next()
})
//Populates user on request
server.express.use(async (req, res, next) => {
if(!req.userId) return next()
const user = await db.query.user({
where: {id: req.userId}
}, `{id, permissions, email, name}`)
req.user = user
next()
})
//start
server.start({
cors: {
credentials: true,
origin: process.env.FRONTEND_URL
},
}, starting => {
console.log(`server is running on port ${starting.port}`)
})

What I have done in the past is started both a HTTP and a HTTPS server with express.
The HTTPS is the server with all the routes\API's configured.
The HTTP server simply to redirects all GET requests to HTTPS. See the following code which could be used setup the HTTP server to do the redirect.
let httpRedirectServer = express();
// set up a route to redirect http to https
httpRedirectServer.get('*', (request, response) => {
response.redirect('https://' + request.headers.host + request.url);
});
httpRedirectServer.listen(80);
httpRedirectServer.on('listening', () => {
console.log("Listening to redirect http to https");
});
Alternatively on the client side a quick fix is to redirect in javascript by running something like.
// Check the URL starts with 'http://xxxxx' protocol, if it does then redirect to 'https://xxxxx' url of same resource
var httpTokens = /^http:\/\/(.*)$/.exec(window.location.href);
if(httpTokens) {
window.location.replace('https://' + httpTokens[1]);
}

Related

Express doesn't set cookies with httpOnly flag

I have my back-end Express.js server that has sign in function. After user sign in, he gets 2 tokens - access token and refresh token. What I want to do, is to make return from server refresh token as httpOnly cookie.
Here is a peace of code of this function:
const { refreshToken, accessToken } = await jwtService.updateTokens({
userId: client.id, username: client.username
}, { transaction })
logger.info(`Client ${client.email} has been successfully signed in!`)
await transaction.commit()
return res
.status(200)
.cookie("refreshToken", JSON.stringify(refreshToken), { httpOnly: true, secure: false })
.json({ accessToken, reopening: reopening ? client.username : null })
Basically, browser just doesn't set this cookie as httpOnly and doesn't set it at all, actually. So, I was trying to ping this endpoint with postman, and it works:
In reponse body I have access token and in httpOnly cookie I have this refresh token.
So, the problem is, why browser doesn't save it? I have found a couple of solutions and all of them were about cors and axios credentials. I use 2 express servers - 1 is for normal back-end and 1 is for front-end.
Here is how "path" from front-end to back-end looks like:
Sign in function that send request to front-end express server:
const api = axios.create({
baseURL: apiUrl,
headers: {
'Content-Type': 'application/json'
}
})
export const signIn = async payload => {
try {
const { data } = await api.post('s-i', payload)
return data
} catch (e) {
return e.response.data
}
}
Front-end express server sends request to actual back-end:
const api = axios.create({
baseURL: process.env.NODE_ENV === "development" ? process.env.PNB_API_DEV : process.env.PNB_API_PROD,
})
const router = Router()
router.post('/s-i', async (req, res) => {
try {
const { data } = await api.post('/sign-in', req.body)
res.json(data)
} catch (e) {
return res.status(e.response.status).json(e.response.data)
}
});
And then that function that was at the very begging.
So - the question is - how to make browser save those httpOnly cookies? If it's really about credentials or cors where should I put those settings?
PS
Back-end port - 3001 and front-end port - 8010.

socket.io, vTiger, and csrf-magic.js. CORS issues

I'm attempting to create and add a socket.io module to my vTiger 7.0 so that I can update fields in real-time to multiple users.
We are have issues with users changing fields that should be locked while our quality control is attempting to check the record. This is causes things to get approved that should not. Node.js with vTiger will be awesome add-on.
The only problem is that vTiger uses csrf-magic.js to create a token that need to be included in the header to allow CORS
I have the middleware setup in my node project to allow my vtiger to make a request
vTiger is on vtiger.example.com
The node server is on node.example.com:3010
//server code node.example.com:3010
const fs = require("fs");
const config = require("./core/config").config();
var options = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert),
ca: fs.readFileSync(config.ca),
requestCert: true,
rejectUnauthorized: false,
};
const app = require("express")();
const server = require("https").Server(options, app);
const io = require("socket.io")(server);
// Need to send io to socket module
module.exports = io;
app.use(function (req, res, next) {
var allowedOrigins = [
"https://node.example.com",
"https://vtiger.example.com"
];
var origin = req.headers.origin;
if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
res.header("Access-Control-Allow-Methods", "GET, OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Credentials", true);
return next();
});
io.sockets.on("connection", require("./sockets/socket.js"));
const qc = require('./models/qc_model');
app.get('/', (req,res) => {
res.json({message: 'No Access'});
})
qc.pullLeadInfo(13622196, 10730, (data) => {
console.log(data.lead.lsloa_ver_by);
});
//Start the server
server.listen(config.port, () => {
console.log("server listening on port: " + config.port);
});
\\client side vtiger.example.com
var socket = io.connect('https://node.example.com:3010');
I get this error
Access to XMLHttpRequest at 'https://node.example.com:3010/socket.io/?EIO=4&transport=polling&t=NmEEc_r' from origin 'https://vtiger.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
csrf-magic.js:41 GET https://node.example.com:3010/socket.io/?EIO=4&transport=polling&t=NmEEc_r net::ERR_FAILED
I cannot find any good documentation dealing with this issue. Any help would be great!
Found the information here
https://github.com/socketio/socket.io/issues/3929
// Server
io.engine.on("headers", (headers) => {
headers["Access-Control-Allow-Private-Network"] = true;
});
// Client
const socket = io({
extraHeaders: {
"Access-Control-Request-Private-Network": true
}
});

Express.js: How to refresh on DB change in backend?

I decided to make a janky chat site type thing to get me started working with requests and such.
My approach was to create an express.js server that takes in requests when the '/messageReciever' is posted to.
app.post("/messageReciever", (req, res) => {
logMessage(req.body.message);
});
The next step was to make a 'client' that could send information to this end point:
var XMLHttpRequest = require("XMLHttpRequest").XMLHttpRequest;
function makePostRequest(url, json)
{
let http = new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-Type", "application/json");
http.send(JSON.stringify(json));
}
function sendMessage(url, message)
{
makePostRequest(url, {message: message});
logMessage(message);
}
Both of these are fine. The issue I'm running into is, once I receive the post request I want to refresh the main page of my site (to show the messages)
app.get('/', (req, res) => {
res.render('index', data = retrieveMessages());
});
I've tried basically everything I've found online:
res.redirect('back');
res.redirect(req.get('referer'));
res.redirect(req.originalUrl)
I used res.redirect('back') previously in my code, and it works. The issue is that I'm trying to refresh someone's connection to a site based on someone else's connection; meaning I can't use the response information like I normally could.
I've tried looking for ways to refresh pages from outside functions but I can't find anything.
(I realize that there are easier ways to make a chat site that don't include weirdly sending data back and forth between two server's)
You can use a package called socket.io. Socket.io allows you to send requests to a client once the server has some data.
Example:
Server:
// Define express
const express = require('express');
const app = express();
// Create the server
const http = require('http');
const server = http.createServer(app);
// Define socket.io
const io = require('socket.io')(server);
// Define the port for the server to listen on
let port = 3000;
function logMessage(message, id) {
...
io.emit('message_sent_' + id, { message }); // Emit that a message was sent to the clients
}
function recieveMessages(id) {
// Get the messages somehow
}
app.post('/messageReciever', (req, res) => {
// req.body.message is your message and req.cookies.id is the clients random ID
logMessage(req.body.message, req.cookies.id);
});
app.get('/', (req, res) => {
res.cookie('id', 'some-generated-id'); // Set a cookie for the unique ID to fetch user messages
res.render('index', { data: retrieveMessages() });
});
// Get the server listening to incoming requests
server.listen(port, () => console.log('my app is online');
Client:
<!doctype html>
<html>
<body>
...
</body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect();
socket.on('message_sent_' + 'some-id', function(data) {
// Do something with the data
});
</script>
</html>
References:
https://socket.io/docs/v4/
http://expressjs.com/
https://marques-robinson-project.medium.com/chat-app-with-socket-io-and-express-using-node-js-2293b87f47c3

Aibo API not redirecting to my redirect uri after authentication

I'm trying to create an aibo linkable app. I have a node.js/express app running and when I receive a request for '/' I redirect to the aibo authentication endpoint with appropriate parameters. When I go to my site it correctly displays the SONY sign in page and I can log in with my email and password but it takes me to the myaibo.aibo.com site instead of redirecting to my '/auth' endpoint.
Here is a short snippet of what I'm doing:
const CLIENT_ID = process.env.AIBO_CLIENT_ID;
const CLIENT_SECRET = process.env.AIBO_CLIENT_SECRET;
const REDIRECT_URI= 'https://aibo.jonfleming.net/auth';
app.get('/', (req, res, next) => {
if(!req.session.authenticated) {
req.session.state = randomGenerate(12);
const url = `https://myaibo.aibo.com/account_link.html?state=${req.session.state}&` +
`client_id=${CLIENT_ID}&scope=pub&redirect_uri=${REDIRECT_URI}&response_type=code`;
res.redirect(url);
} else {
next();
}
});
app.get('/auth', (req, res) => {
const code = req.query.code;
const state = req.query.state;
if (state === req.session.state) {
// request access token
// get deviceId
// update header
req.session.authenticated = true;
res.send('Connected');
}
});
The '/auth' endpoint never gets hit.
I've also tried displaying a clickable link in place of the res.redirect(url).
res.send(`<html><body>Sign In</body></html>`);
Clicking the link has the same result. It takes me to the sign in page but never redirects back to my app.

express + cors() is not working properly

I'm building a React application and I'm trying to make a call to https://itunes.apple.com/search?term=jack+johnson
I have a helper called requestHelper.js which looks like :
import 'whatwg-fetch';
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
So I get:
XMLHttpRequest cannot load
https://itunes.apple.com/search?term=jack%20johnson. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
My express server looks like this:
const ip = require('ip');
const cors = require('cors');
const path = require('path');
const express = require('express');
const port = process.env.PORT || 3000;
const resolve = require('path').resolve;
const app = express();
app.use(cors());
app.use('/', express.static(resolve(process.cwd(), 'dist')));
app.get('*', function(req, res) {
res.sendFile(path.resolve(resolve(process.cwd(), 'dist'), 'index.html'))
});
// Start app
app.listen(port, (err) => {
if (err) {
console.error(err.message);
return false;
}
const divider = '\n-----------------------------------';
console.log('Server started ✓');
console.log(`Access URLs:${divider}\n
Localhost: http://localhost:${port}
LAN: http://${ip.address()}:${port}
${divider}
`);
});
I have tried using mode: 'no-cors' but is not actually what I need since the response is empty.
Am I doing something wrong with this configuration?
The same origin policy kicks in when code hosted on A makes a request to B.
In this case A is your Express app and B is iTunes.
CORS is used to allow B to grant permission to the code on A to read the response.
You are setting up CORS on A. This does nothing useful since your site cannot grant your client side code permission to read data from a different site.
You need to set it up on B. Since you (presumably) do not work for Apple, you can't do this. Only Apple can grant your client side code permission to read data from its servers.
Read the data with server side code instead.

Categories

Resources