mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Redirection fixes (#8592)
* fix(redirects): logic update * test(middlewares): redirects tests * fix(nconf): IS_PROD is boolean * fix(test): treat IS_PROD as Boolean here too * fix(test): apiUrl test copypasta
This commit is contained in:
182
test/api/v3/unit/middlewares/redirects.js
Normal file
182
test/api/v3/unit/middlewares/redirects.js
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import {
|
||||||
|
generateRes,
|
||||||
|
generateReq,
|
||||||
|
generateNext,
|
||||||
|
} from '../../../../helpers/api-unit.helper';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
import requireAgain from 'require-again';
|
||||||
|
|
||||||
|
describe('redirects middleware', () => {
|
||||||
|
let res, req, next;
|
||||||
|
let pathToRedirectsMiddleware = '../../../../../website/server/middlewares/redirects';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
res = generateRes();
|
||||||
|
req = generateReq();
|
||||||
|
next = generateNext();
|
||||||
|
});
|
||||||
|
|
||||||
|
context('forceSSL', () => {
|
||||||
|
it('sends http requests to https', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceSSL(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.calledOnce;
|
||||||
|
expect(res.redirect).to.be.calledWith('https://habitica.com/static/front');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect https forwarded requests', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('https');
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceSSL(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect outside of production environments', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(false);
|
||||||
|
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceSSL(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect if base URL is not https', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('http://habitica.com');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceSSL(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('forceHabitica', () => {
|
||||||
|
it('sends requests with differing hostname to base URL host', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.hostname = 'www.habitica.com';
|
||||||
|
req.method = 'GET';
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
req.url = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.calledOnce;
|
||||||
|
expect(res.redirect).to.be.calledWith(301, 'https://habitica.com/static/front');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect outside of production environments', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(false);
|
||||||
|
req.hostname = 'www.habitica.com';
|
||||||
|
req.method = 'GET';
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
req.url = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect if env is set to ignore redirection', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('true');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.hostname = 'www.habitica.com';
|
||||||
|
req.method = 'GET';
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
req.url = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect if request hostname matches base URL host', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.hostname = 'habitica.com';
|
||||||
|
req.method = 'GET';
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
req.url = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect if request is an API URL', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.hostname = 'www.habitica.com';
|
||||||
|
req.method = 'GET';
|
||||||
|
req.originalUrl = '/api/v3/challenges';
|
||||||
|
req.url = '/api/v3/challenges';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect if request method is not GET', () => {
|
||||||
|
let nconfStub = sandbox.stub(nconf, 'get');
|
||||||
|
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||||
|
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||||
|
nconfStub.withArgs('IS_PROD').returns(true);
|
||||||
|
req.hostname = 'www.habitica.com';
|
||||||
|
req.method = 'POST';
|
||||||
|
req.originalUrl = '/static/front';
|
||||||
|
req.url = '/static/front';
|
||||||
|
|
||||||
|
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||||
|
|
||||||
|
attachRedirects.forceHabitica(req, res, next);
|
||||||
|
|
||||||
|
expect(res.redirect).to.be.notCalled;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -30,16 +30,17 @@ export function generateChallenge (options = {}) {
|
|||||||
|
|
||||||
export function generateRes (options = {}) {
|
export function generateRes (options = {}) {
|
||||||
let defaultRes = {
|
let defaultRes = {
|
||||||
render: sandbox.stub(),
|
|
||||||
send: sandbox.stub(),
|
|
||||||
status: sandbox.stub().returnsThis(),
|
|
||||||
sendStatus: sandbox.stub().returnsThis(),
|
|
||||||
json: sandbox.stub(),
|
json: sandbox.stub(),
|
||||||
locals: {
|
locals: {
|
||||||
user: generateUser(options.localsUser),
|
user: generateUser(options.localsUser),
|
||||||
group: generateGroup(options.localsGroup),
|
group: generateGroup(options.localsGroup),
|
||||||
},
|
},
|
||||||
|
redirect: sandbox.stub(),
|
||||||
|
render: sandbox.stub(),
|
||||||
|
send: sandbox.stub(),
|
||||||
|
sendStatus: sandbox.stub().returnsThis(),
|
||||||
set: sandbox.stub(),
|
set: sandbox.stub(),
|
||||||
|
status: sandbox.stub().returnsThis(),
|
||||||
t (string) {
|
t (string) {
|
||||||
return i18n.t(string);
|
return i18n.t(string);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
|
|
||||||
const IS_PROD = nconf.get('IS_PROD');
|
const IS_PROD = nconf.get('IS_PROD');
|
||||||
const IGNORE_REDIRECT = nconf.get('IGNORE_REDIRECT');
|
const IGNORE_REDIRECT = nconf.get('IGNORE_REDIRECT') === 'true';
|
||||||
const BASE_URL = nconf.get('BASE_URL');
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
|
||||||
|
let baseUrlSplit = BASE_URL.split('//');
|
||||||
|
const BASE_URL_HOST = baseUrlSplit[1];
|
||||||
|
|
||||||
function isHTTP (req) {
|
function isHTTP (req) {
|
||||||
return ( // eslint-disable-line no-extra-parens
|
return ( // eslint-disable-line no-extra-parens
|
||||||
req.header('x-forwarded-proto') &&
|
req.header('x-forwarded-proto') &&
|
||||||
@@ -13,15 +16,8 @@ function isHTTP (req) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isProxied (req) {
|
|
||||||
return ( // eslint-disable-line no-extra-parens
|
|
||||||
req.header('x-habitica-lb') &&
|
|
||||||
req.header('x-habitica-lb') === 'Yes'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function forceSSL (req, res, next) {
|
export function forceSSL (req, res, next) {
|
||||||
if (isHTTP(req) && !isProxied(req)) {
|
if (isHTTP(req)) {
|
||||||
return res.redirect(BASE_URL + req.originalUrl);
|
return res.redirect(BASE_URL + req.originalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +31,7 @@ function nonApiUrl (req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function forceHabitica (req, res, next) {
|
export function forceHabitica (req, res, next) {
|
||||||
if (IS_PROD && !IGNORE_REDIRECT && !isProxied(req) && nonApiUrl(req)) {
|
if (IS_PROD && !IGNORE_REDIRECT && req.hostname !== BASE_URL_HOST && nonApiUrl(req) && req.method === 'GET') {
|
||||||
return res.redirect(301, BASE_URL + req.url);
|
return res.redirect(301, BASE_URL + req.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user