n8n
Version:
n8n Workflow Automation Tool
245 lines • 12 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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MeController = exports.isApiEnabledMiddleware = exports.API_KEY_PREFIX = void 0;
const validator_1 = __importDefault(require("validator"));
const class_transformer_1 = require("class-transformer");
const crypto_1 = require("crypto");
const auth_service_1 = require("../auth/auth.service");
const decorators_1 = require("../decorators");
const password_utility_1 = require("../services/password.utility");
const GenericHelpers_1 = require("../GenericHelpers");
const requests_1 = require("../requests");
const samlHelpers_1 = require("../sso/saml/samlHelpers");
const user_service_1 = require("../services/user.service");
const Logger_1 = require("../Logger");
const ExternalHooks_1 = require("../ExternalHooks");
const bad_request_error_1 = require("../errors/response-errors/bad-request.error");
const user_repository_1 = require("../databases/repositories/user.repository");
const PublicApi_1 = require("../PublicApi");
const event_service_1 = require("../events/event.service");
const mfa_service_1 = require("../Mfa/mfa.service");
const invalid_mfa_code_error_1 = require("../errors/response-errors/invalid-mfa-code.error");
exports.API_KEY_PREFIX = 'n8n_api_';
const isApiEnabledMiddleware = (_, res, next) => {
if ((0, PublicApi_1.isApiEnabled)()) {
next();
}
else {
res.status(404).end();
}
};
exports.isApiEnabledMiddleware = isApiEnabledMiddleware;
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) {
const { id: userId, email: currentEmail } = req.user;
const payload = (0, class_transformer_1.plainToInstance)(requests_1.UserUpdatePayload, req.body, { excludeExtraneousValues: true });
const { email } = payload;
if (!email) {
this.logger.debug('Request to update user email failed because of missing email in payload', {
userId,
payload,
});
throw new bad_request_error_1.BadRequestError('Email is mandatory');
}
if (!validator_1.default.isEmail(email)) {
this.logger.debug('Request to update user email failed because of invalid email in payload', {
userId,
invalidEmail: email,
});
throw new bad_request_error_1.BadRequestError('Invalid email address');
}
await (0, GenericHelpers_1.validateEntity)(payload);
if ((0, samlHelpers_1.isSamlLicensedAndEnabled)()) {
if (email !== currentEmail) {
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');
}
}
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 fieldsChanged = Object.keys(payload).filter((key) => 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) {
const { user } = req;
const { currentPassword, newPassword, mfaCode } = req.body;
if ((0, samlHelpers_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 (typeof currentPassword !== 'string' || typeof newPassword !== 'string') {
throw new bad_request_error_1.BadRequestError('Invalid payload.');
}
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 validPassword = this.passwordUtility.validate(newPassword);
if (user.mfaEnabled) {
if (typeof mfaCode !== 'string') {
throw new bad_request_error_1.BadRequestError('Two-factor code is required to change password.');
}
const isMfaTokenValid = await this.mfaService.validateMfa(user.id, mfaCode, undefined);
if (!isMfaTokenValid) {
throw new invalid_mfa_code_error_1.InvalidMfaCodeError();
}
}
user.password = await this.passwordUtility.hash(validPassword);
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 empty payload', {
userId: req.user.id,
});
throw new bad_request_error_1.BadRequestError('Personalization answers are mandatory');
}
await (0, GenericHelpers_1.validateRecordNoXss)(personalizationAnswers);
await this.userRepository.save({
id: req.user.id,
personalizationAnswers,
}, { 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: personalizationAnswers,
});
return { success: true };
}
async createAPIKey(req) {
const apiKey = `n8n_api_${(0, crypto_1.randomBytes)(40).toString('hex')}`;
await this.userService.update(req.user.id, { apiKey });
this.eventService.emit('public-api-key-created', { user: req.user, publicApi: false });
return { apiKey };
}
async getAPIKey(req) {
const apiKey = this.redactApiKey(req.user.apiKey);
return { apiKey };
}
async deleteAPIKey(req) {
await this.userService.update(req.user.id, { apiKey: null });
this.eventService.emit('public-api-key-deleted', { user: req.user, publicApi: false });
return { success: true };
}
async updateCurrentUserSettings(req) {
const payload = (0, class_transformer_1.plainToInstance)(requests_1.UserSettingsUpdatePayload, req.body, {
excludeExtraneousValues: true,
});
await (0, GenericHelpers_1.validateEntity)(payload);
const { id } = req.user;
await this.userService.updateSettings(id, payload);
const user = await this.userRepository.findOneOrFail({
select: ['settings'],
where: { id },
});
return user.settings;
}
redactApiKey(apiKey) {
if (!apiKey)
return;
const keepLength = 5;
return (exports.API_KEY_PREFIX +
apiKey.slice(exports.API_KEY_PREFIX.length, exports.API_KEY_PREFIX.length + keepLength) +
'*'.repeat(apiKey.length - exports.API_KEY_PREFIX.length - keepLength));
}
};
exports.MeController = MeController;
__decorate([
(0, decorators_1.Patch)('/'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "updateCurrentUser", null);
__decorate([
(0, decorators_1.Patch)('/password', { rateLimit: true }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__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.Post)('/api-key', { middlewares: [exports.isApiEnabledMiddleware] }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "createAPIKey", null);
__decorate([
(0, decorators_1.Get)('/api-key', { middlewares: [exports.isApiEnabledMiddleware] }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "getAPIKey", null);
__decorate([
(0, decorators_1.Delete)('/api-key', { middlewares: [exports.isApiEnabledMiddleware] }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "deleteAPIKey", null);
__decorate([
(0, decorators_1.Patch)('/settings'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], MeController.prototype, "updateCurrentUserSettings", null);
exports.MeController = MeController = __decorate([
(0, decorators_1.RestController)('/me'),
__metadata("design:paramtypes", [Logger_1.Logger,
ExternalHooks_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
;