freeCodeCamp/api-server/server/middlewares/request-authorization.js

104 lines
3.1 KiB
JavaScript
Raw Normal View History

2019-02-20 18:18:50 +00:00
import { isEmpty } from 'lodash';
2019-03-04 21:10:12 +00:00
import { getUserById as _getUserById } from '../utils/user-stats';
import {
getAccessTokenFromRequest,
errorTypes,
authHeaderNS
} from '../utils/getSetAccessToken';
import { homeLocation } from '../../../config/env';
import { jwtSecret as _jwtSecret } from '../../../config/secrets';
2018-08-29 19:52:41 +00:00
import { wrapHandledError } from '../utils/create-handled-error';
const authRE = /^\/auth\//;
const confirmEmailRE = /^\/confirm-email$/;
2020-03-06 16:51:58 +00:00
const newsShortLinksRE = /^\/n\/|^\/p\//;
const publicUserRE = /^\/api\/users\/get-public-profile$/;
const publicUsernameRE = /^\/api\/users\/exists$/;
const resubscribeRE = /^\/resubscribe\//;
2020-03-06 16:51:58 +00:00
const showCertRE = /^\/certificate\/showCert\//;
// note: signin may not have a trailing slash
2020-03-06 16:51:58 +00:00
const signinRE = /^\/signin/;
const statusRE = /^\/status\/ping$/;
2020-03-06 16:51:58 +00:00
const unsubscribedRE = /^\/unsubscribed\//;
const unsubscribeRE = /^\/u\/|^\/unsubscribe\/|^\/ue\//;
const updateHooksRE = /^\/hooks\/update-paypal$|^\/hooks\/update-stripe$/;
// note: this would be replaced by webhooks later
const donateRE = /^\/donate\/charge-stripe$/;
2020-03-13 09:25:57 +00:00
const _whiteListREs = [
authRE,
confirmEmailRE,
2020-03-13 09:25:57 +00:00
newsShortLinksRE,
publicUserRE,
publicUsernameRE,
resubscribeRE,
2020-03-06 16:51:58 +00:00
showCertRE,
signinRE,
statusRE,
2020-03-06 16:51:58 +00:00
unsubscribedRE,
unsubscribeRE,
updateHooksRE,
donateRE
2020-03-13 09:25:57 +00:00
];
2019-02-16 13:51:46 +00:00
export function isWhiteListedPath(path, whiteListREs = _whiteListREs) {
return whiteListREs.some(re => re.test(path));
}
2018-11-29 12:12:15 +00:00
export default ({ jwtSecret = _jwtSecret, getUserById = _getUserById } = {}) =>
2019-02-20 18:18:50 +00:00
function requestAuthorisation(req, res, next) {
2019-02-16 13:51:46 +00:00
const { path } = req;
2020-03-06 16:51:58 +00:00
if (!isWhiteListedPath(path)) {
const { accessToken, error, jwt } = getAccessTokenFromRequest(
req,
jwtSecret
);
if (!accessToken && error === errorTypes.noTokenFound) {
2019-02-16 13:51:46 +00:00
throw wrapHandledError(
new Error('Access token is required for this request'),
{
type: 'info',
redirect: `${homeLocation}/signin`,
message: 'Access token is required for this request',
status: 403
}
);
}
if (!accessToken && error === errorTypes.invalidToken) {
throw wrapHandledError(new Error('Access token is invalid'), {
type: 'info',
2018-08-29 19:52:41 +00:00
redirect: `${homeLocation}/signin`,
message: 'Your access token is invalid',
status: 403
2019-02-16 13:51:46 +00:00
});
}
if (!accessToken && error === errorTypes.expiredToken) {
throw wrapHandledError(new Error('Access token is no longer valid'), {
type: 'info',
2018-08-29 19:52:41 +00:00
redirect: `${homeLocation}/signin`,
message: 'Access token is no longer valid',
status: 403
2019-02-16 13:51:46 +00:00
});
}
res.set(authHeaderNS, jwt);
2019-02-20 18:18:50 +00:00
if (isEmpty(req.user)) {
const { userId } = accessToken;
2019-02-20 18:18:50 +00:00
return getUserById(userId)
2019-02-16 13:51:46 +00:00
.then(user => {
if (user) {
req.user = user;
}
return;
})
.then(next)
.catch(next);
} else {
2019-02-20 18:18:50 +00:00
return Promise.resolve(next());
2019-02-16 13:51:46 +00:00
}
}
2019-02-20 18:18:50 +00:00
return Promise.resolve(next());
2019-02-16 13:51:46 +00:00
};