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

97 lines
2.8 KiB
JavaScript
Raw Normal View History

import loopback from 'loopback';
import jwt from 'jsonwebtoken';
import { isBefore } from 'date-fns';
2019-02-20 18:18:50 +00:00
import { isEmpty } from 'lodash';
import { homeLocation } from '../../../config/env';
2018-08-29 20:52:41 +01:00
import { wrapHandledError } from '../utils/create-handled-error';
2018-11-29 12:12:15 +00:00
// We need to tunnel through a proxy path set up within
// the gatsby app, at this time, that path is /internal
const apiProxyRE = /^\/internal\/|^\/external\//;
const newsShortLinksRE = /^\/internal\/n\/|^\/internal\/p\?/;
const loopbackAPIPathRE = /^\/internal\/api\//;
2019-02-16 13:51:46 +00:00
const _whiteListREs = [newsShortLinksRE, loopbackAPIPathRE];
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
2019-02-20 18:18:50 +00:00
export default ({
_jwtSecret = process.env.JWT_SECRET,
getUserById = _getUserById
} = {}) =>
function requestAuthorisation(req, res, next) {
2019-02-16 13:51:46 +00:00
const { path } = req;
if (apiProxyRE.test(path) && !isWhiteListedPath(path)) {
const cookie =
(req.signedCookies && req.signedCookies['jwt_access_token']) ||
(req.cookie && req.cookie['jwt_access_token']);
2018-11-29 12:12:15 +00:00
2019-02-16 13:51:46 +00:00
if (!cookie) {
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
}
);
}
let token;
try {
2019-02-20 18:18:50 +00:00
token = jwt.verify(cookie, _jwtSecret);
2019-02-16 13:51:46 +00:00
} catch (err) {
throw wrapHandledError(new Error(err.message), {
type: 'info',
2018-08-29 20:52:41 +01:00
redirect: `${homeLocation}/signin`,
message: 'Your access token is invalid',
status: 403
2019-02-16 13:51:46 +00:00
});
}
const {
accessToken: { created, ttl, userId }
} = token;
const valid = isBefore(Date.now(), Date.parse(created) + ttl);
if (!valid) {
throw wrapHandledError(new Error('Access token is no longer vaild'), {
type: 'info',
2018-08-29 20:52:41 +01:00
redirect: `${homeLocation}/signin`,
message: 'Access token is no longer vaild',
status: 403
2019-02-16 13:51:46 +00:00
});
}
2019-02-20 18:18:50 +00:00
if (isEmpty(req.user)) {
return getUserById(userId)
2019-02-16 13:51:46 +00:00
.then(user => {
if (user) {
user.points = user.progressTimestamps.length;
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
};
2019-02-20 18:18:50 +00:00
export function _getUserById(id) {
const User = loopback.getModelByType('User');
return new Promise((resolve, reject) =>
User.findById(id, (err, instance) => {
if (err) {
return reject(err);
}
return resolve(instance);
})
);
}