UNPKG

n8n

Version:

n8n Workflow Automation Tool

181 lines 10 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PasswordResetController = void 0; const api_types_1 = require("@n8n/api-types"); const backend_common_1 = require("@n8n/backend-common"); const db_1 = require("@n8n/db"); const decorators_1 = require("@n8n/decorators"); const permissions_1 = require("@n8n/permissions"); const auth_service_1 = require("../auth/auth.service"); const constants_1 = require("../constants"); const bad_request_error_1 = require("../errors/response-errors/bad-request.error"); const forbidden_error_1 = require("../errors/response-errors/forbidden.error"); const internal_server_error_1 = require("../errors/response-errors/internal-server.error"); const not_found_error_1 = require("../errors/response-errors/not-found.error"); const unprocessable_error_1 = require("../errors/response-errors/unprocessable.error"); const event_service_1 = require("../events/event.service"); const external_hooks_1 = require("../external-hooks"); const license_1 = require("../license"); const mfa_service_1 = require("../mfa/mfa.service"); const password_utility_1 = require("../services/password.utility"); const user_service_1 = require("../services/user.service"); const sso_helpers_1 = require("../sso.ee/sso-helpers"); const email_1 = require("../user-management/email"); let PasswordResetController = class PasswordResetController { constructor(logger, externalHooks, mailer, authService, userService, mfaService, license, passwordUtility, userRepository, eventService) { this.logger = logger; this.externalHooks = externalHooks; this.mailer = mailer; this.authService = authService; this.userService = userService; this.mfaService = mfaService; this.license = license; this.passwordUtility = passwordUtility; this.userRepository = userRepository; this.eventService = eventService; } async forgotPassword(_req, _res, payload) { if (!this.mailer.isEmailSetUp) { this.logger.debug('Request to send password reset email failed because emailing was not set up'); throw new internal_server_error_1.InternalServerError('Email sending must be set up in order to request a password reset email'); } const { email } = payload; const user = await this.userRepository.findNonShellUser(email); if (!user) { this.logger.debug('No user found in the system'); return; } if (user.role !== 'global:owner' && !this.license.isWithinUsersLimit()) { this.logger.debug('Request to send password reset email failed because the user limit was reached'); throw new forbidden_error_1.ForbiddenError(constants_1.RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED); } if (((0, sso_helpers_1.isSamlCurrentAuthenticationMethod)() || (0, sso_helpers_1.isOidcCurrentAuthenticationMethod)()) && !((0, permissions_1.hasGlobalScope)(user, 'user:resetPassword') || user.settings?.allowSSOManualLogin === true)) { const currentAuthenticationMethod = (0, sso_helpers_1.isSamlCurrentAuthenticationMethod)() ? 'SAML' : 'OIDC'; this.logger.debug(`Request to send password reset email failed because login is handled by ${currentAuthenticationMethod}`); throw new forbidden_error_1.ForbiddenError(`Login is handled by ${currentAuthenticationMethod}. Please contact your Identity Provider to reset your password.`); } const ldapIdentity = user.authIdentities?.find((i) => i.providerType === 'ldap'); if (!user.password || (ldapIdentity && user.disabled)) { this.logger.debug('Request to send password reset email failed because no user was found for the provided email', { invalidEmail: email }); return; } if (this.license.isLdapEnabled() && ldapIdentity) { throw new unprocessable_error_1.UnprocessableRequestError('forgotPassword.ldapUserPasswordResetUnavailable'); } const url = this.authService.generatePasswordResetUrl(user); const { id, firstName } = user; try { await this.mailer.passwordReset({ email, firstName, passwordResetUrl: url, }); } catch (error) { this.eventService.emit('email-failed', { user, messageType: 'Reset password', publicApi: false, }); if (error instanceof Error) { throw new internal_server_error_1.InternalServerError(`Please contact your administrator: ${error.message}`, error); } } this.logger.info('Sent password reset email successfully', { userId: user.id, email }); this.eventService.emit('user-transactional-email-sent', { userId: id, messageType: 'Reset password', publicApi: false, }); this.eventService.emit('user-password-reset-request-click', { user }); } async resolvePasswordToken(_req, _res, payload) { const { token } = payload; const user = await this.authService.resolvePasswordResetToken(token); if (!user) throw new not_found_error_1.NotFoundError(''); if (user.role !== 'global:owner' && !this.license.isWithinUsersLimit()) { this.logger.debug('Request to resolve password token failed because the user limit was reached', { userId: user.id }); throw new forbidden_error_1.ForbiddenError(constants_1.RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED); } this.logger.info('Reset-password token resolved successfully', { userId: user.id }); this.eventService.emit('user-password-reset-email-click', { user }); } async changePassword(req, res, payload) { const { token, password, mfaCode } = payload; const user = await this.authService.resolvePasswordResetToken(token); if (!user) throw new not_found_error_1.NotFoundError(''); if (user.mfaEnabled) { if (!mfaCode) throw new bad_request_error_1.BadRequestError('If MFA enabled, mfaCode is required.'); const { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(user.id); const validToken = this.mfaService.totp.verifySecret({ secret, mfaCode }); if (!validToken) throw new bad_request_error_1.BadRequestError('Invalid MFA token.'); } const passwordHash = await this.passwordUtility.hash(password); await this.userService.update(user.id, { password: passwordHash }); this.logger.info('User password updated successfully', { userId: user.id }); this.authService.issueCookie(res, user, user.mfaEnabled, req.browserId); this.eventService.emit('user-updated', { user, fieldsChanged: ['password'] }); const ldapIdentity = user?.authIdentities?.find((i) => i.providerType === 'ldap'); if (ldapIdentity) { this.eventService.emit('user-signed-up', { user, userType: 'email', wasDisabledLdapUser: true, }); } await this.externalHooks.run('user.password.update', [user.email, passwordHash]); } }; exports.PasswordResetController = PasswordResetController; __decorate([ (0, decorators_1.Post)('/forgot-password', { skipAuth: true, rateLimit: { limit: 3 } }), __param(2, decorators_1.Body), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, api_types_1.ForgotPasswordRequestDto]), __metadata("design:returntype", Promise) ], PasswordResetController.prototype, "forgotPassword", null); __decorate([ (0, decorators_1.Get)('/resolve-password-token', { skipAuth: true }), __param(2, decorators_1.Query), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, api_types_1.ResolvePasswordTokenQueryDto]), __metadata("design:returntype", Promise) ], PasswordResetController.prototype, "resolvePasswordToken", null); __decorate([ (0, decorators_1.Post)('/change-password', { skipAuth: true }), __param(2, decorators_1.Body), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, api_types_1.ChangePasswordRequestDto]), __metadata("design:returntype", Promise) ], PasswordResetController.prototype, "changePassword", null); exports.PasswordResetController = PasswordResetController = __decorate([ (0, decorators_1.RestController)(), __metadata("design:paramtypes", [backend_common_1.Logger, external_hooks_1.ExternalHooks, email_1.UserManagementMailer, auth_service_1.AuthService, user_service_1.UserService, mfa_service_1.MfaService, license_1.License, password_utility_1.PasswordUtility, db_1.UserRepository, event_service_1.EventService]) ], PasswordResetController); //# sourceMappingURL=password-reset.controller.js.map