UNPKG

payload-totp

Version:

Add an extra security layer to PayloadCMS using a Time-based One-time Password (TOTP).

75 lines (74 loc) 2.57 kB
import { Secret, TOTP } from 'otpauth'; import { setCookie } from '../setCookie.js'; export function setSecret(pluginOptions) { const handler = async (req)=>{ const { payload, user } = req; const i18n = req.i18n; if (!user) { return Response.json({ message: i18n.t('error:unauthorized'), ok: false }); } if (user.hasTotp) { return Response.json({ message: i18n.t('totpPlugin:errors:alreadySet'), ok: false }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any let data; try { data = req.json && await req.json(); // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-empty } catch (err) {} // TODO: Better validation if (typeof data !== 'object' || typeof data['token'] !== 'string' || typeof data['secret'] !== 'string') { return Response.json({ message: i18n.t('error:unspecific'), ok: false }); } const totp = new TOTP({ algorithm: pluginOptions.totp?.algorithm || 'SHA1', digits: pluginOptions.totp?.digits || 6, issuer: pluginOptions.totp?.issuer || 'Payload', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore label: user.email || user.username, period: pluginOptions.totp?.period || 30, secret: Secret.fromBase32(data['secret']) }); const delta = totp.validate({ token: data['token'].toString(), window: 1 }); if (delta === null) { return Response.json({ message: i18n.t('totpPlugin:setup:incorrectCode'), ok: false }); } await payload.update({ id: user.id, collection: pluginOptions.collection, data: { totpSecret: data['secret'] }, overrideAccess: true }) // TODO: Report this to Payload ; const collection = payload.collections[pluginOptions.collection]; await setCookie({ authConfig: collection.config.auth, cookiePrefix: payload.config.cookiePrefix, secret: payload.secret, user }); return Response.json({ ok: true }); }; return handler; } //# sourceMappingURL=setSecret.js.map