0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Added endpoints for supporting 2FA

no refs

- Added `POST /session/verify` to send the user a verification code
- Added `PUT /session/verify` to verify the user's verification code
This commit is contained in:
Michael Barrett 2024-10-09 13:32:16 +01:00 committed by Kevin Ansfield
parent 51fa21324d
commit 7a18e829c5
5 changed files with 57 additions and 12 deletions

View file

@ -65,10 +65,15 @@ const controller = {
auth.session.logout(req, res, next);
});
},
verify() {
sendVerification() {
return Promise.resolve(function sendAuthCodeMw(req, res, next) {
auth.session.sendAuthCode(req, res, next);
});
},
verify() {
return Promise.resolve(function verifyAuthCodeMw(req, res, next) {
auth.session.verifyAuthCode(req, res, next);
});
}
};

View file

@ -3,6 +3,7 @@ const createSessionService = require('@tryghost/session-service');
const sessionFromToken = require('@tryghost/mw-session-from-token');
const createSessionMiddleware = require('./middleware');
const settingsCache = require('../../../../shared/settings-cache');
const {GhostMailer} = require('../../mail');
const expressSession = require('./express-session');
@ -29,6 +30,8 @@ function getOriginOfRequest(req) {
return null;
}
const mailer = new GhostMailer();
const sessionService = createSessionService({
getOriginOfRequest,
getSession: expressSession.getSession,
@ -37,7 +40,8 @@ const sessionService = createSessionService({
},
getSecret(key) {
return settingsCache.get(key);
}
},
mailer
});
module.exports = createSessionMiddleware({sessionService});

View file

@ -34,17 +34,33 @@ function SessionMiddleware({sessionService}) {
async function sendAuthCode(req, res, next) {
try {
await sessionService.sendAuthCodeToUser(req, res);
res.sendStatus(201);
} catch (err) {
next(err);
}
}
async function verifyAuthCode(req, res, next) {
try {
const verified = await sessionService.verifyAuthCodeForUser(req, res);
if (verified) {
res.sendStatus(200);
} else {
res.sendStatus(401);
}
} catch (err) {
next(err);
}
}
return {
createSession: createSession,
logout: logout,
authenticate: authenticate,
sendAuthCode: sendAuthCode
sendAuthCode: sendAuthCode,
verifyAuthCode: verifyAuthCode
};
}

View file

@ -243,8 +243,8 @@ module.exports = function apiRoutes() {
http(api.session.add)
);
router.del('/session', mw.authAdminApi, http(api.session.delete));
// resending verification code for 2FA
router.post('/session/verify', mw.authAdminApi, http(api.session.verify));
router.post('/session/verify', http(api.session.sendVerification));
router.put('/session/verify', http(api.session.verify));
// ## Identity
router.get('/identities', mw.authAdminApi, http(api.identities.read));

View file

@ -30,8 +30,7 @@ const {totp} = require('otplib');
* @prop {(req: Req, res: Res, user: User) => Promise<void>} createSessionForUser
* @prop {(req: Req, res: Res) => Promise<void>} verifySession
* @prop {(req: Req, res: Res) => Promise<void>} sendAuthCodeToUser
* @prop {(req: Req, res: Res) => string} generateAuthCodeForUser
* @prop {(req: Req, res: Res) => Promise<void>} verifyAuthCodeForUser
* @prop {(req: Req, res: Res) => Promise<boolean>} verifyAuthCodeForUser
*/
/**
@ -40,11 +39,18 @@ const {totp} = require('otplib');
* @param {(data: {id: string}) => Promise<User>} deps.findUserById
* @param {(req: Req) => string} deps.getOriginOfRequest
* @param {(key: string) => string} deps.getSecret
* @param {import('../../core/core/server/services/mail').GhostMailer} deps.mailer
*
* @returns {SessionService}
*/
module.exports = function createSessionService({getSession, findUserById, getOriginOfRequest, getSecret}) {
module.exports = function createSessionService({
getSession,
findUserById,
getOriginOfRequest,
getSecret,
mailer
}) {
/**
* cookieCsrfProtection
*
@ -117,10 +123,10 @@ module.exports = function createSessionService({getSession, findUserById, getOri
* @param {Res} res
* @returns {Promise<boolean>}
*/
async function verifyAuthCodeForUser(req, res, token) {
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 isValid = totp.check(token, secret);
const isValid = totp.check(req.body.token, secret);
return isValid;
}
@ -133,8 +139,22 @@ module.exports = function createSessionService({getSession, findUserById, getOri
*/
async function sendAuthCodeToUser(req, res) {
const session = await getSession(req, res); // eslint-disable-line
generateAuthCodeForUser();
// send auth code to user
const token = await generateAuthCodeForUser(req, res);
// 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',
html: email
});
return Promise.resolve();
}
/**