2018-05-24 12:19:51 +01:00
|
|
|
import loopback from 'loopback';
|
2018-05-23 21:10:56 +01:00
|
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
import { isBefore } from 'date-fns';
|
2018-05-24 12:19:51 +01:00
|
|
|
|
2018-08-31 16:04:04 +01:00
|
|
|
import { homeLocation } from '../../../config/env';
|
2018-08-29 20:52:41 +01:00
|
|
|
|
2018-05-23 21:10:56 +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
|
2019-02-15 21:02:38 +00:00
|
|
|
const apiProxyRE = /^\/internal\/|^\/external\//;
|
|
|
|
const newsShortLinksRE = /^\/internal\/n\/|^\/internal\/p\?/;
|
|
|
|
const loopbackAPIPathRE = /^\/internal\/api\//;
|
|
|
|
|
|
|
|
const _whiteListREs = [
|
|
|
|
newsShortLinksRE,
|
|
|
|
loopbackAPIPathRE
|
|
|
|
];
|
|
|
|
|
|
|
|
export function isWhiteListedPath(path, whiteListREs= _whiteListREs) {
|
|
|
|
return whiteListREs.some(re => re.test(path))
|
|
|
|
}
|
2018-11-29 12:12:15 +00:00
|
|
|
|
|
|
|
|
2018-05-23 21:10:56 +01:00
|
|
|
export default () => function authorizeByJWT(req, res, next) {
|
2019-02-15 21:02:38 +00:00
|
|
|
const { path } = req;
|
|
|
|
if (apiProxyRE.test(path) && !isWhiteListedPath(path)) {
|
2018-05-24 12:19:51 +01:00
|
|
|
const cookie = req.signedCookies && req.signedCookies['jwt_access_token'] ||
|
|
|
|
req.cookie && req.cookie['jwt_access_token'];
|
2019-02-13 12:15:23 +00:00
|
|
|
|
2018-05-23 21:10:56 +01:00
|
|
|
if (!cookie) {
|
|
|
|
throw wrapHandledError(
|
|
|
|
new Error('Access token is required for this request'),
|
|
|
|
{
|
|
|
|
type: 'info',
|
2018-08-29 20:52:41 +01:00
|
|
|
redirect: `${homeLocation}/signin`,
|
2018-05-23 21:10:56 +01:00
|
|
|
message: 'Access token is required for this request',
|
|
|
|
status: 403
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let token;
|
|
|
|
try {
|
|
|
|
token = jwt.verify(cookie, process.env.JWT_SECRET);
|
|
|
|
} catch (err) {
|
|
|
|
throw wrapHandledError(
|
|
|
|
new Error(err.message),
|
|
|
|
{
|
|
|
|
type: 'info',
|
2018-08-29 20:52:41 +01:00
|
|
|
redirect: `${homeLocation}/signin`,
|
2018-05-23 21:10:56 +01:00
|
|
|
message: 'Your access token is invalid',
|
|
|
|
status: 403
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2018-05-24 12:19:51 +01:00
|
|
|
const { accessToken: {created, ttl, userId }} = token;
|
2018-05-23 21:10:56 +01:00
|
|
|
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`,
|
2018-05-23 21:10:56 +01:00
|
|
|
message: 'Access token is no longer vaild',
|
|
|
|
status: 403
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2018-05-24 12:19:51 +01:00
|
|
|
if (!req.user) {
|
|
|
|
const User = loopback.getModelByType('User');
|
|
|
|
return User.findById(userId)
|
2019-02-06 14:19:58 +00:00
|
|
|
.then(user => {
|
|
|
|
if (user) {
|
|
|
|
user.points = user.progressTimestamps.length;
|
|
|
|
req.user = user;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
})
|
|
|
|
.then(next)
|
|
|
|
.catch(next);
|
2018-05-24 12:19:51 +01:00
|
|
|
} else {
|
|
|
|
return next();
|
|
|
|
}
|
2018-05-23 21:10:56 +01:00
|
|
|
}
|
|
|
|
return next();
|
|
|
|
};
|