mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Prevent regression / e2e tests from trying to use 2fa
This commit is contained in:
parent
1a05652b50
commit
f772008c69
6 changed files with 62 additions and 30 deletions
|
@ -4,6 +4,7 @@ const sessionFromToken = require('@tryghost/mw-session-from-token');
|
|||
const createSessionMiddleware = require('./middleware');
|
||||
const settingsCache = require('../../../../shared/settings-cache');
|
||||
const {GhostMailer} = require('../../mail');
|
||||
const {t} = require('../../i18n');
|
||||
|
||||
const expressSession = require('./express-session');
|
||||
|
||||
|
@ -38,10 +39,12 @@ const sessionService = createSessionService({
|
|||
findUserById({id}) {
|
||||
return models.User.findOne({id, status: 'active'});
|
||||
},
|
||||
getSecret(key) {
|
||||
getSettingsCache(key) {
|
||||
return settingsCache.get(key);
|
||||
},
|
||||
mailer
|
||||
mailer,
|
||||
urlUtils,
|
||||
t
|
||||
});
|
||||
|
||||
module.exports = createSessionMiddleware({sessionService});
|
||||
|
|
|
@ -30,7 +30,6 @@ Object {
|
|||
"members": true,
|
||||
"newEmailAddresses": true,
|
||||
"outboundLinkTagging": true,
|
||||
"staff2fa": true,
|
||||
"stripeAutomaticTax": true,
|
||||
"themeErrorsNotification": true,
|
||||
"urlCache": true,
|
||||
|
|
|
@ -22,6 +22,9 @@ Object {
|
|||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"set-cookie": Array [
|
||||
StringMatching /\\^ghost-admin-api-session=/,
|
||||
],
|
||||
"vary": "Accept-Version, Origin",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
|
|
|
@ -713,7 +713,10 @@ const fixtures = {
|
|||
},
|
||||
|
||||
async enableAllLabsFeatures() {
|
||||
const labsValue = Object.fromEntries(labsService.WRITABLE_KEYS_ALLOWLIST.map(key => [key, true]));
|
||||
const labsValue = Object.fromEntries(labsService.WRITABLE_KEYS_ALLOWLIST
|
||||
// TODO: should test with 2fa enabled
|
||||
.filter(key => key !== 'staff2fa')
|
||||
.map(key => [key, true]));
|
||||
const labsSetting = DataGenerator.forKnex.createSetting({
|
||||
key: 'labs',
|
||||
group: 'labs',
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
const {
|
||||
BadRequestError
|
||||
} = require('@tryghost/errors');
|
||||
const {totp} = require('otplib');
|
||||
const emailTemplate = require('../lib/emails/signin');
|
||||
|
||||
const {totp} = require('otplib');
|
||||
totp.options = {
|
||||
digits: 6,
|
||||
step: 60,
|
||||
|
@ -12,6 +13,7 @@ totp.options = {
|
|||
/**
|
||||
* @typedef {object} User
|
||||
* @prop {string} id
|
||||
* @prop {(attr: string) => string} get
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -45,9 +47,10 @@ totp.options = {
|
|||
* @param {(req: Req, res: Res) => Promise<Session>} deps.getSession
|
||||
* @param {(data: {id: string}) => Promise<User>} deps.findUserById
|
||||
* @param {(req: Req) => string} deps.getOriginOfRequest
|
||||
* @param {(key: string) => string} deps.getSecret
|
||||
* @param {(key: string) => string} deps.getSettingsCache
|
||||
* @param {import('../../core/core/server/services/mail').GhostMailer} deps.mailer
|
||||
*
|
||||
* @param {import('../../core/core/server/services/i18n').t} deps.t
|
||||
* @param {import('../../core/core/shared/url-utils')} deps.urlUtils
|
||||
* @returns {SessionService}
|
||||
*/
|
||||
|
||||
|
@ -55,8 +58,10 @@ module.exports = function createSessionService({
|
|||
getSession,
|
||||
findUserById,
|
||||
getOriginOfRequest,
|
||||
getSecret,
|
||||
mailer
|
||||
getSettingsCache,
|
||||
mailer,
|
||||
urlUtils,
|
||||
t
|
||||
}) {
|
||||
/**
|
||||
* cookieCsrfProtection
|
||||
|
@ -112,8 +117,8 @@ module.exports = function createSessionService({
|
|||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateAuthCodeForUser(req, res) {
|
||||
const session = await getSession(req, res); // Todo: Do we need to handle "No session found"?
|
||||
const secret = getSecret('admin_session_secret') + session.user_id;
|
||||
const session = await getSession(req, res);
|
||||
const secret = getSettingsCache('admin_session_secret') + session.user_id;
|
||||
const token = totp.generate(secret);
|
||||
return token;
|
||||
}
|
||||
|
@ -126,8 +131,8 @@ module.exports = function createSessionService({
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function verifyAuthCodeForUser(req, res) {
|
||||
const session = await getSession(req, res); // Todo: Do we need to handle "No session found"?
|
||||
const secret = getSecret('admin_session_secret') + session.user_id;
|
||||
const session = await getSession(req, res);
|
||||
const secret = getSettingsCache('admin_session_secret') + session.user_id;
|
||||
const isValid = totp.check(req.body.token, secret);
|
||||
return isValid;
|
||||
}
|
||||
|
@ -140,19 +145,30 @@ module.exports = function createSessionService({
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function sendAuthCodeToUser(req, res) {
|
||||
const session = await getSession(req, res); // eslint-disable-line
|
||||
const token = await generateAuthCodeForUser(req, res);
|
||||
const user = await getUserForSession(req, res);
|
||||
if(!user) {
|
||||
throw new BadRequestError({
|
||||
message: 'Could not fetch user from the session.'
|
||||
});
|
||||
}
|
||||
const recipient = user.get('email');
|
||||
const siteTitle = getSettingsCache('title');
|
||||
const siteUrl = urlUtils.urlFor('home', true);
|
||||
const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
|
||||
const siteDomain = (domain && domain[1]);
|
||||
const email = emailTemplate({
|
||||
t,
|
||||
siteTitle: siteTitle,
|
||||
email: recipient,
|
||||
siteDomain: siteDomain,
|
||||
siteUrl: siteUrl,
|
||||
token
|
||||
});
|
||||
|
||||
// TODO: Find email address for user associated with user requesting token
|
||||
const recipient = 'TODO';
|
||||
|
||||
// TODO: Generate email
|
||||
const email = `<html><body><p>Here is your token matey: ${token}</p></body></html>`;
|
||||
|
||||
// TODO: Send email
|
||||
await mailer.send({
|
||||
to: recipient,
|
||||
subject: 'tokens4u',
|
||||
subject: `Verification code: ${token}`,
|
||||
html: email
|
||||
});
|
||||
|
||||
|
|
|
@ -199,13 +199,13 @@ describe('SessionService', function () {
|
|||
};
|
||||
const findUserById = sinon.spy(async ({id}) => ({id}));
|
||||
const getOriginOfRequest = sinon.stub().returns('origin');
|
||||
const getSecret = sinon.stub().returns('secret-key');
|
||||
const getSettingsCache = sinon.stub().returns('secret-key');
|
||||
|
||||
const sessionService = SessionService({
|
||||
getSession,
|
||||
findUserById,
|
||||
getOriginOfRequest,
|
||||
getSecret
|
||||
getSettingsCache
|
||||
});
|
||||
|
||||
const req = Object.create(express.request, {
|
||||
|
@ -227,8 +227,12 @@ describe('SessionService', function () {
|
|||
const authCode = await sessionService.generateAuthCodeForUser(req, res);
|
||||
should.exist(authCode);
|
||||
|
||||
req.body = {
|
||||
token: authCode
|
||||
};
|
||||
|
||||
// Verify the auth code
|
||||
const isValid = await sessionService.verifyAuthCodeForUser(req, res, authCode);
|
||||
const isValid = await sessionService.verifyAuthCodeForUser(req, res);
|
||||
should.equal(isValid, true);
|
||||
});
|
||||
|
||||
|
@ -245,13 +249,13 @@ describe('SessionService', function () {
|
|||
};
|
||||
const findUserById = sinon.spy(async ({id}) => ({id}));
|
||||
const getOriginOfRequest = sinon.stub().returns('origin');
|
||||
const getSecret = sinon.stub().returns('secret-key');
|
||||
const getSettingsCache = sinon.stub().returns('secret-key');
|
||||
|
||||
const sessionService = SessionService({
|
||||
getSession,
|
||||
findUserById,
|
||||
getOriginOfRequest,
|
||||
getSecret
|
||||
getSettingsCache
|
||||
});
|
||||
|
||||
const req = Object.create(express.request, {
|
||||
|
@ -273,8 +277,12 @@ describe('SessionService', function () {
|
|||
const authCode = await sessionService.generateAuthCodeForUser(req, res);
|
||||
should.exist(authCode);
|
||||
|
||||
req.body = {
|
||||
token: 'wrong-code'
|
||||
};
|
||||
|
||||
// Verify an incorrect auth code
|
||||
const isValid = await sessionService.verifyAuthCodeForUser(req, res, 'wrong-code');
|
||||
const isValid = await sessionService.verifyAuthCodeForUser(req, res);
|
||||
should.equal(isValid, false);
|
||||
});
|
||||
|
||||
|
@ -313,7 +321,7 @@ describe('SessionService', function () {
|
|||
getSession,
|
||||
findUserById,
|
||||
getOriginOfRequest,
|
||||
getSecret: getSecretFirst
|
||||
getSettingsCache: getSecretFirst
|
||||
});
|
||||
|
||||
const authCodeFirst = await sessionServiceFirst.generateAuthCodeForUser(req, res);
|
||||
|
@ -324,7 +332,7 @@ describe('SessionService', function () {
|
|||
getSession,
|
||||
findUserById,
|
||||
getOriginOfRequest,
|
||||
getSecret: getSecretSecond
|
||||
getSettingsCache: getSecretSecond
|
||||
});
|
||||
|
||||
const authCodeSecond = await sessionServiceSecond.generateAuthCodeForUser(req, res);
|
||||
|
|
Loading…
Add table
Reference in a new issue