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:
parent
51fa21324d
commit
7a18e829c5
5 changed files with 57 additions and 12 deletions
|
@ -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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue