n8n
Version:
n8n Workflow Automation Tool
185 lines • 9.79 kB
JavaScript
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.MeController = void 0;
const api_types_1 = require("@n8n/api-types");
const class_transformer_1 = require("class-transformer");
const n8n_core_1 = require("n8n-core");
const auth_service_1 = require("../auth/auth.service");
const user_repository_1 = require("../databases/repositories/user.repository");
const decorators_1 = require("../decorators");
const bad_request_error_1 = require("../errors/response-errors/bad-request.error");
const invalid_mfa_code_error_1 = require("../errors/response-errors/invalid-mfa-code.error");
const event_service_1 = require("../events/event.service");
const external_hooks_1 = require("../external-hooks");
const generic_helpers_1 = require("../generic-helpers");
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 saml_helpers_1 = require("../sso.ee/saml/saml-helpers");
const survey_answers_dto_1 = require("./survey-answers.dto");
let MeController = class MeController {
constructor(logger, externalHooks, authService, userService, passwordUtility, userRepository, eventService, mfaService) {
this.logger = logger;
this.externalHooks = externalHooks;
this.authService = authService;
this.userService = userService;
this.passwordUtility = passwordUtility;
this.userRepository = userRepository;
this.eventService = eventService;
this.mfaService = mfaService;
}
async updateCurrentUser(req, res, payload) {
const { id: userId, email: currentEmail, mfaEnabled } = req.user;
const { email } = payload;
const isEmailBeingChanged = email !== currentEmail;
if ((0, saml_helpers_1.isSamlLicensedAndEnabled)() && isEmailBeingChanged) {
this.logger.debug('Request to update user failed because SAML user may not change their email', {
userId,
payload,
});
throw new bad_request_error_1.BadRequestError('SAML user may not change their email');
}
if (mfaEnabled && isEmailBeingChanged) {
if (!payload.mfaCode) {
throw new bad_request_error_1.BadRequestError('Two-factor code is required to change email');
}
const isMfaCodeValid = await this.mfaService.validateMfa(userId, payload.mfaCode, undefined);
if (!isMfaCodeValid) {
throw new invalid_mfa_code_error_1.InvalidMfaCodeError();
}
}
await this.externalHooks.run('user.profile.beforeUpdate', [userId, currentEmail, payload]);
const preUpdateUser = await this.userRepository.findOneByOrFail({ id: userId });
await this.userService.update(userId, payload);
const user = await this.userRepository.findOneOrFail({
where: { id: userId },
});
this.logger.info('User updated successfully', { userId });
this.authService.issueCookie(res, user, req.browserId);
const changeableFields = ['email', 'firstName', 'lastName'];
const fieldsChanged = changeableFields.filter((key) => key in payload && payload[key] !== preUpdateUser[key]);
this.eventService.emit('user-updated', { user, fieldsChanged });
const publicUser = await this.userService.toPublic(user);
await this.externalHooks.run('user.profile.update', [currentEmail, publicUser]);
return publicUser;
}
async updatePassword(req, res, payload) {
const { user } = req;
const { currentPassword, newPassword, mfaCode } = payload;
if ((0, saml_helpers_1.isSamlLicensedAndEnabled)()) {
this.logger.debug('Attempted to change password for user, while SAML is enabled', {
userId: user.id,
});
throw new bad_request_error_1.BadRequestError('With SAML enabled, users need to use their SAML provider to change passwords');
}
if (!user.password) {
throw new bad_request_error_1.BadRequestError('Requesting user not set up.');
}
const isCurrentPwCorrect = await this.passwordUtility.compare(currentPassword, user.password);
if (!isCurrentPwCorrect) {
throw new bad_request_error_1.BadRequestError('Provided current password is incorrect.');
}
const passwordValidation = api_types_1.passwordSchema.safeParse(newPassword);
if (!passwordValidation.success) {
throw new bad_request_error_1.BadRequestError(passwordValidation.error.errors.map(({ message }) => message).join(' '));
}
if (user.mfaEnabled) {
if (typeof mfaCode !== 'string') {
throw new bad_request_error_1.BadRequestError('Two-factor code is required to change password.');
}
const isMfaCodeValid = await this.mfaService.validateMfa(user.id, mfaCode, undefined);
if (!isMfaCodeValid) {
throw new invalid_mfa_code_error_1.InvalidMfaCodeError();
}
}
user.password = await this.passwordUtility.hash(newPassword);
const updatedUser = await this.userRepository.save(user, { transaction: false });
this.logger.info('Password updated successfully', { userId: user.id });
this.authService.issueCookie(res, updatedUser, req.browserId);
this.eventService.emit('user-updated', { user: updatedUser, fieldsChanged: ['password'] });
await this.externalHooks.run('user.password.update', [updatedUser.email, updatedUser.password]);
return { success: true };
}
async storeSurveyAnswers(req) {
const { body: personalizationAnswers } = req;
if (!personalizationAnswers) {
this.logger.debug('Request to store user personalization survey failed because of undefined payload', {
userId: req.user.id,
});
throw new bad_request_error_1.BadRequestError('Personalization answers are mandatory');
}
const validatedAnswers = (0, class_transformer_1.plainToInstance)(survey_answers_dto_1.PersonalizationSurveyAnswersV4, personalizationAnswers, { excludeExtraneousValues: true });
await (0, generic_helpers_1.validateEntity)(validatedAnswers);
await this.userRepository.save({
id: req.user.id,
personalizationAnswers: validatedAnswers,
}, { transaction: false });
this.logger.info('User survey updated successfully', { userId: req.user.id });
this.eventService.emit('user-submitted-personalization-survey', {
userId: req.user.id,
answers: validatedAnswers,
});
return { success: true };
}
async updateCurrentUserSettings(req, _, payload) {
const { id } = req.user;
await this.userService.updateSettings(id, payload);
const user = await this.userRepository.findOneOrFail({
select: ['settings'],
where: { id },
});
return user.settings;
}
};
exports.MeController = MeController;
__decorate([
(0, decorators_1.Patch)('/'),
__param(2, decorators_1.Body),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, api_types_1.UserUpdateRequestDto]),
__metadata("design:returntype", Promise)
], MeController.prototype, "updateCurrentUser", null);
__decorate([
(0, decorators_1.Patch)('/password', { rateLimit: true }),
__param(2, decorators_1.Body),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, api_types_1.PasswordUpdateRequestDto]),
__metadata("design:returntype", Promise)
], MeController.prototype, "updatePassword", null);
__decorate([
(0, decorators_1.Post)('/survey'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "storeSurveyAnswers", null);
__decorate([
(0, decorators_1.Patch)('/settings'),
__param(2, decorators_1.Body),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, api_types_1.SettingsUpdateRequestDto]),
__metadata("design:returntype", Promise)
], MeController.prototype, "updateCurrentUserSettings", null);
exports.MeController = MeController = __decorate([
(0, decorators_1.RestController)('/me'),
__metadata("design:paramtypes", [n8n_core_1.Logger,
external_hooks_1.ExternalHooks,
auth_service_1.AuthService,
user_service_1.UserService,
password_utility_1.PasswordUtility,
user_repository_1.UserRepository,
event_service_1.EventService,
mfa_service_1.MfaService])
], MeController);
//# sourceMappingURL=me.controller.js.map
;