2019-04-05 09:57:14 +03:00
|
|
|
const concat = require('concat-stream');
|
|
|
|
const Cookies = require('cookies');
|
|
|
|
const ignition = require('ghost-ignition');
|
|
|
|
|
|
|
|
const {
|
|
|
|
BadRequestError
|
|
|
|
} = ignition.errors;
|
|
|
|
|
|
|
|
const EMPTY = {};
|
|
|
|
const SIX_MONTHS_MS = 1000 * 60 * 60 * 24 * 184;
|
|
|
|
|
2019-05-06 13:23:24 +03:00
|
|
|
const withCookies = (fn, cookieConfig) => (req, res) => {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
const cookies = new Cookies(req, res, cookieConfig);
|
|
|
|
resolve(fn(req, res, {cookies}));
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const withBodyAndCookies = (fn, cookieConfig) => (req, res) => {
|
2019-04-05 09:57:14 +03:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const cookies = new Cookies(req, res, cookieConfig);
|
|
|
|
req.on('error', reject);
|
|
|
|
req.pipe(concat(function (buff) {
|
|
|
|
const body = buff.toString();
|
|
|
|
resolve(fn(req, res, {body, cookies}));
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2019-07-17 09:40:37 +03:00
|
|
|
const get = (value) => {
|
|
|
|
return typeof value === 'function' ? value() : value;
|
|
|
|
};
|
|
|
|
|
2019-04-05 09:57:14 +03:00
|
|
|
module.exports = function create(options = EMPTY) {
|
|
|
|
if (options === EMPTY) {
|
|
|
|
throw new Error('Must pass options');
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
cookieMaxAge = SIX_MONTHS_MS,
|
|
|
|
cookieSecure = true,
|
|
|
|
cookieName = 'members-ssr',
|
|
|
|
cookiePath = '/',
|
|
|
|
cookieKeys,
|
|
|
|
membersApi
|
|
|
|
} = options;
|
|
|
|
|
|
|
|
if (!membersApi) {
|
|
|
|
throw new Error('Missing option membersApi');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cookieKeys) {
|
|
|
|
throw new Error('Missing option cookieKeys');
|
|
|
|
}
|
|
|
|
|
|
|
|
const cookieConfig = {
|
|
|
|
keys: [].concat(cookieKeys),
|
|
|
|
secure: cookieSecure
|
|
|
|
};
|
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const getMemberDataFromToken = token => get(membersApi).getMemberDataFromMagicLinkToken(token);
|
2019-04-05 09:57:14 +03:00
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const exchangeTokenForSession = withBodyAndCookies(async (_req, _res, {body, cookies}) => {
|
2019-04-05 09:57:14 +03:00
|
|
|
const token = body;
|
|
|
|
if (!body || typeof body !== 'string') {
|
2019-04-11 17:10:32 +03:00
|
|
|
return Promise.reject(new BadRequestError({
|
2019-04-05 09:57:14 +03:00
|
|
|
message: 'Expected body containing JWT'
|
2019-04-11 17:10:32 +03:00
|
|
|
}));
|
2019-04-05 09:57:14 +03:00
|
|
|
}
|
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const member = await getMemberDataFromToken(token);
|
|
|
|
cookies.set(cookieName, member.email, {
|
|
|
|
signed: true,
|
|
|
|
httpOnly: true,
|
|
|
|
sameSite: 'lax',
|
|
|
|
maxAge: cookieMaxAge,
|
|
|
|
path: cookiePath
|
2019-04-05 09:57:14 +03:00
|
|
|
});
|
|
|
|
}, cookieConfig);
|
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const deleteSession = withCookies((_req, _res, {cookies}) => {
|
2019-04-11 17:10:53 +03:00
|
|
|
cookies.set(cookieName, {
|
|
|
|
signed: true,
|
|
|
|
httpOnly: true,
|
|
|
|
sameSite: 'lax',
|
|
|
|
maxAge: cookieMaxAge,
|
|
|
|
path: cookiePath
|
|
|
|
});
|
|
|
|
}, cookieConfig);
|
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const getMemberDataFromSession = withCookies(async (_req, _res, {cookies}) => {
|
2019-04-10 18:02:39 +03:00
|
|
|
try {
|
2019-09-03 07:34:59 +03:00
|
|
|
const email = cookies.get(cookieName, {
|
2019-04-10 18:02:39 +03:00
|
|
|
signed: true
|
|
|
|
});
|
2019-09-03 07:34:59 +03:00
|
|
|
return get(membersApi).getMemberIdentityData(email);
|
2019-04-10 18:02:39 +03:00
|
|
|
} catch (e) {
|
2019-09-03 07:34:59 +03:00
|
|
|
throw new BadRequestError({
|
2019-04-05 09:57:14 +03:00
|
|
|
message: `Cookie ${cookieName} not found`
|
2019-09-03 07:34:59 +03:00
|
|
|
});
|
2019-04-05 09:57:14 +03:00
|
|
|
}
|
|
|
|
}, cookieConfig);
|
|
|
|
|
2019-09-03 07:34:59 +03:00
|
|
|
const getIdentityTokenForMemberFromSession = withCookies(async (_req, _res, {cookies}) => {
|
|
|
|
try {
|
|
|
|
const email = cookies.get(cookieName, {
|
|
|
|
signed: true
|
|
|
|
});
|
|
|
|
return get(membersApi).getMemberIdentityToken(email);
|
|
|
|
} catch (e) {
|
|
|
|
throw new BadRequestError({
|
|
|
|
message: `Cookie ${cookieName} not found`
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-04-05 09:57:14 +03:00
|
|
|
return {
|
|
|
|
exchangeTokenForSession,
|
2019-04-11 17:10:53 +03:00
|
|
|
deleteSession,
|
2019-09-03 07:34:59 +03:00
|
|
|
getMemberDataFromSession,
|
|
|
|
getIdentityTokenForMemberFromSession
|
2019-04-05 09:57:14 +03:00
|
|
|
};
|
|
|
|
};
|