n8n
Version:
n8n Workflow Automation Tool
201 lines • 11.3 kB
JavaScript
"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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PasswordResetController = void 0;
const validator_1 = __importDefault(require("validator"));
const auth_service_1 = require("../auth/auth.service");
const decorators_1 = require("../decorators");
const password_utility_1 = require("../services/password.utility");
const email_1 = require("../UserManagement/email");
const ssoHelpers_1 = require("../sso/ssoHelpers");
const user_service_1 = require("../services/user.service");
const License_1 = require("../License");
const constants_1 = require("../constants");
const mfa_service_1 = require("../Mfa/mfa.service");
const Logger_1 = require("../Logger");
const ExternalHooks_1 = require("../ExternalHooks");
const url_service_1 = require("../services/url.service");
const internal_server_error_1 = require("../errors/response-errors/internal-server.error");
const bad_request_error_1 = require("../errors/response-errors/bad-request.error");
const forbidden_error_1 = require("../errors/response-errors/forbidden.error");
const not_found_error_1 = require("../errors/response-errors/not-found.error");
const unprocessable_error_1 = require("../errors/response-errors/unprocessable.error");
const user_repository_1 = require("../databases/repositories/user.repository");
const event_service_1 = require("../events/event.service");
let PasswordResetController = class PasswordResetController {
constructor(logger, externalHooks, mailer, authService, userService, mfaService, urlService, license, passwordUtility, userRepository, eventService) {
this.logger = logger;
this.externalHooks = externalHooks;
this.mailer = mailer;
this.authService = authService;
this.userService = userService;
this.mfaService = mfaService;
this.urlService = urlService;
this.license = license;
this.passwordUtility = passwordUtility;
this.userRepository = userRepository;
this.eventService = eventService;
}
async forgotPassword(req) {
var _a, _b;
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 } = req.body;
if (!email) {
this.logger.debug('Request to send password reset email failed because of missing email in payload', { payload: req.body });
throw new bad_request_error_1.BadRequestError('Email is mandatory');
}
if (!validator_1.default.isEmail(email)) {
this.logger.debug('Request to send password reset email failed because of invalid email in payload', { invalidEmail: email });
throw new bad_request_error_1.BadRequestError('Invalid email address');
}
const user = await this.userRepository.findNonShellUser(email);
if (!(user === null || user === void 0 ? void 0 : user.isOwner) && !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, ssoHelpers_1.isSamlCurrentAuthenticationMethod)() &&
!((user === null || user === void 0 ? void 0 : user.hasGlobalScope('user:resetPassword')) === true ||
((_a = user === null || user === void 0 ? void 0 : user.settings) === null || _a === void 0 ? void 0 : _a.allowSSOManualLogin) === true)) {
this.logger.debug('Request to send password reset email failed because login is handled by SAML');
throw new forbidden_error_1.ForbiddenError('Login is handled by SAML. Please contact your Identity Provider to reset your password.');
}
const ldapIdentity = (_b = user === null || user === void 0 ? void 0 : user.authIdentities) === null || _b === void 0 ? void 0 : _b.find((i) => i.providerType === 'ldap');
if (!(user === null || user === void 0 ? void 0 : 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, lastName } = user;
try {
await this.mailer.passwordReset({
email,
firstName,
lastName,
passwordResetUrl: url,
domain: this.urlService.getInstanceBaseUrl(),
});
}
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}`);
}
}
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) {
const { token } = req.query;
if (!token) {
this.logger.debug('Request to resolve password token failed because of missing password reset token', {
queryString: req.query,
});
throw new bad_request_error_1.BadRequestError('');
}
const user = await this.authService.resolvePasswordResetToken(token);
if (!user)
throw new not_found_error_1.NotFoundError('');
if (!(user === null || user === void 0 ? void 0 : user.isOwner) && !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) {
var _a;
const { token, password, mfaToken } = req.body;
if (!token || !password) {
this.logger.debug('Request to change password failed because of missing user ID or password or reset password token in payload', {
payload: req.body,
});
throw new bad_request_error_1.BadRequestError('Missing user ID or password or reset password token');
}
const validPassword = this.passwordUtility.validate(password);
const user = await this.authService.resolvePasswordResetToken(token);
if (!user)
throw new not_found_error_1.NotFoundError('');
if (user.mfaEnabled) {
if (!mfaToken)
throw new bad_request_error_1.BadRequestError('If MFA enabled, mfaToken is required.');
const { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(user.id);
const validToken = this.mfaService.totp.verifySecret({ secret, token: mfaToken });
if (!validToken)
throw new bad_request_error_1.BadRequestError('Invalid MFA token.');
}
const passwordHash = await this.passwordUtility.hash(validPassword);
await this.userService.update(user.id, { password: passwordHash });
this.logger.info('User password updated successfully', { userId: user.id });
this.authService.issueCookie(res, user, req.browserId);
this.eventService.emit('user-updated', { user, fieldsChanged: ['password'] });
const ldapIdentity = (_a = user === null || user === void 0 ? void 0 : user.authIdentities) === null || _a === void 0 ? void 0 : _a.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 } }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], PasswordResetController.prototype, "forgotPassword", null);
__decorate([
(0, decorators_1.Get)('/resolve-password-token', { skipAuth: true }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], PasswordResetController.prototype, "resolvePasswordToken", null);
__decorate([
(0, decorators_1.Post)('/change-password', { skipAuth: true }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], PasswordResetController.prototype, "changePassword", null);
exports.PasswordResetController = PasswordResetController = __decorate([
(0, decorators_1.RestController)(),
__metadata("design:paramtypes", [Logger_1.Logger,
ExternalHooks_1.ExternalHooks,
email_1.UserManagementMailer,
auth_service_1.AuthService,
user_service_1.UserService,
mfa_service_1.MfaService,
url_service_1.UrlService,
License_1.License,
password_utility_1.PasswordUtility,
user_repository_1.UserRepository,
event_service_1.EventService])
], PasswordResetController);
//# sourceMappingURL=passwordReset.controller.js.map