UNPKG

@r1tsu/payload

Version:

189 lines (188 loc) 7.25 kB
import jwt from 'jsonwebtoken'; import { buildAfterOperation } from '../../collections/operations/utils.js'; import { AuthenticationError, LockedAuth, ValidationError } from '../../errors/index.js'; import { afterRead } from '../../fields/hooks/afterRead/index.js'; import { commitTransaction } from '../../utilities/commitTransaction.js'; import { initTransaction } from '../../utilities/initTransaction.js'; import { killTransaction } from '../../utilities/killTransaction.js'; import sanitizeInternalFields from '../../utilities/sanitizeInternalFields.js'; import { getFieldsToSign } from '../getFieldsToSign.js'; import isLocked from '../isLocked.js'; import { authenticateLocalStrategy } from '../strategies/local/authenticate.js'; import { incrementLoginAttempts } from '../strategies/local/incrementLoginAttempts.js'; import { resetLoginAttempts } from '../strategies/local/resetLoginAttempts.js'; export const loginOperation = async (incomingArgs)=>{ let args = incomingArgs; try { const shouldCommit = await initTransaction(args.req); // ///////////////////////////////////// // beforeOperation - Collection // ///////////////////////////////////// await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook)=>{ await priorHook; args = await hook({ args, collection: args.collection?.config, context: args.req.context, operation: 'login', req: args.req }) || args; }, Promise.resolve()); const { collection: { config: collectionConfig }, data, depth, overrideAccess, req, req: { fallbackLocale, locale, payload, payload: { secret } }, showHiddenFields } = args; // ///////////////////////////////////// // Login // ///////////////////////////////////// const { email: unsanitizedEmail, password } = data; if (typeof unsanitizedEmail !== 'string' || unsanitizedEmail.trim() === '') { throw new ValidationError([ { field: 'email', message: req.i18n.t('validation:required') } ]); } if (typeof password !== 'string' || password.trim() === '') { throw new ValidationError([ { field: 'password', message: req.i18n.t('validation:required') } ]); } const email = unsanitizedEmail ? unsanitizedEmail.toLowerCase().trim() : null; let user = await payload.db.findOne({ collection: collectionConfig.slug, req, where: { email: { equals: email.toLowerCase() } } }); if (!user || args.collection.config.auth.verify && user._verified === false) { throw new AuthenticationError(req.t); } if (user && isLocked(user.lockUntil)) { throw new LockedAuth(req.t); } const authResult = await authenticateLocalStrategy({ doc: user, password }); user = sanitizeInternalFields(user); const maxLoginAttemptsEnabled = args.collection.config.auth.maxLoginAttempts > 0; if (!authResult) { if (maxLoginAttemptsEnabled) { await incrementLoginAttempts({ collection: collectionConfig, doc: user, payload: req.payload, req }); } if (shouldCommit) await commitTransaction(req); throw new AuthenticationError(req.t); } if (maxLoginAttemptsEnabled) { await resetLoginAttempts({ collection: collectionConfig, doc: user, payload: req.payload, req }); } const fieldsToSign = getFieldsToSign({ collectionConfig, email, user }); await collectionConfig.hooks.beforeLogin.reduce(async (priorHook, hook)=>{ await priorHook; user = await hook({ collection: args.collection?.config, context: args.req.context, req: args.req, user }) || user; }, Promise.resolve()); const token = jwt.sign(fieldsToSign, secret, { expiresIn: collectionConfig.auth.tokenExpiration }); req.user = user; // ///////////////////////////////////// // afterLogin - Collection // ///////////////////////////////////// await collectionConfig.hooks.afterLogin.reduce(async (priorHook, hook)=>{ await priorHook; user = await hook({ collection: args.collection?.config, context: args.req.context, req: args.req, token, user }) || user; }, Promise.resolve()); // ///////////////////////////////////// // afterRead - Fields // ///////////////////////////////////// user = await afterRead({ collection: collectionConfig, context: req.context, depth, doc: user, fallbackLocale, global: null, locale, overrideAccess, req, showHiddenFields }); // ///////////////////////////////////// // afterRead - Collection // ///////////////////////////////////// await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook)=>{ await priorHook; user = await hook({ collection: args.collection?.config, context: req.context, doc: user, req }) || user; }, Promise.resolve()); // ///////////////////////////////////// // afterRead - Collection // ///////////////////////////////////// await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook)=>{ await priorHook; user = await hook({ collection: args.collection?.config, context: req.context, doc: user, req }) || user; }, Promise.resolve()); let result = { exp: jwt.decode(token).exp, token, user }; // ///////////////////////////////////// // afterOperation - Collection // ///////////////////////////////////// result = await buildAfterOperation({ args, collection: args.collection?.config, operation: 'login', result }); // ///////////////////////////////////// // Return results // ///////////////////////////////////// if (shouldCommit) await commitTransaction(req); return result; } catch (error) { await killTransaction(args.req); throw error; } }; //# sourceMappingURL=login.js.map