mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-13 05:47:31 -08:00
fix: Fix typeorm .save usage (no-changelog) (#8678)
This commit is contained in:
parent
afd2eb1f4a
commit
05e13a68ea
|
@ -216,10 +216,13 @@ export const processUsers = async (
|
||||||
export const saveLdapSynchronization = async (
|
export const saveLdapSynchronization = async (
|
||||||
data: Omit<AuthProviderSyncHistory, 'id' | 'providerType'>,
|
data: Omit<AuthProviderSyncHistory, 'id' | 'providerType'>,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
await Container.get(AuthProviderSyncHistoryRepository).save({
|
await Container.get(AuthProviderSyncHistoryRepository).save(
|
||||||
|
{
|
||||||
...data,
|
...data,
|
||||||
providerType: 'ldap',
|
providerType: 'ldap',
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -257,15 +260,20 @@ export const getMappingAttributes = (ldapConfig: LdapConfig): string[] => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createLdapAuthIdentity = async (user: User, ldapId: string) => {
|
export const createLdapAuthIdentity = async (user: User, ldapId: string) => {
|
||||||
return await Container.get(AuthIdentityRepository).save(AuthIdentity.create(user, ldapId));
|
return await Container.get(AuthIdentityRepository).save(AuthIdentity.create(user, ldapId), {
|
||||||
|
transaction: false,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createLdapUserOnLocalDb = async (data: Partial<User>, ldapId: string) => {
|
export const createLdapUserOnLocalDb = async (data: Partial<User>, ldapId: string) => {
|
||||||
const user = await Container.get(UserRepository).save({
|
const user = await Container.get(UserRepository).save(
|
||||||
|
{
|
||||||
password: randomPassword(),
|
password: randomPassword(),
|
||||||
role: 'global:member',
|
role: 'global:member',
|
||||||
...data,
|
...data,
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
await createLdapAuthIdentity(user, ldapId);
|
await createLdapAuthIdentity(user, ldapId);
|
||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|
|
@ -163,7 +163,7 @@ export class InvitationController {
|
||||||
invitee.lastName = lastName;
|
invitee.lastName = lastName;
|
||||||
invitee.password = await this.passwordUtility.hash(validPassword);
|
invitee.password = await this.passwordUtility.hash(validPassword);
|
||||||
|
|
||||||
const updatedUser = await this.userRepository.save(invitee);
|
const updatedUser = await this.userRepository.save(invitee, { transaction: false });
|
||||||
|
|
||||||
await issueCookie(res, updatedUser);
|
await issueCookie(res, updatedUser);
|
||||||
|
|
||||||
|
|
|
@ -104,12 +104,13 @@ export class MeController {
|
||||||
*/
|
*/
|
||||||
@Patch('/password')
|
@Patch('/password')
|
||||||
async updatePassword(req: MeRequest.Password, res: Response) {
|
async updatePassword(req: MeRequest.Password, res: Response) {
|
||||||
|
const { user } = req;
|
||||||
const { currentPassword, newPassword } = req.body;
|
const { currentPassword, newPassword } = req.body;
|
||||||
|
|
||||||
// If SAML is enabled, we don't allow the user to change their email address
|
// If SAML is enabled, we don't allow the user to change their email address
|
||||||
if (isSamlLicensedAndEnabled()) {
|
if (isSamlLicensedAndEnabled()) {
|
||||||
this.logger.debug('Attempted to change password for user, while SAML is enabled', {
|
this.logger.debug('Attempted to change password for user, while SAML is enabled', {
|
||||||
userId: req.user?.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
throw new BadRequestError(
|
throw new BadRequestError(
|
||||||
'With SAML enabled, users need to use their SAML provider to change passwords',
|
'With SAML enabled, users need to use their SAML provider to change passwords',
|
||||||
|
@ -120,33 +121,30 @@ export class MeController {
|
||||||
throw new BadRequestError('Invalid payload.');
|
throw new BadRequestError('Invalid payload.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.user.password) {
|
if (!user.password) {
|
||||||
throw new BadRequestError('Requesting user not set up.');
|
throw new BadRequestError('Requesting user not set up.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCurrentPwCorrect = await this.passwordUtility.compare(
|
const isCurrentPwCorrect = await this.passwordUtility.compare(currentPassword, user.password);
|
||||||
currentPassword,
|
|
||||||
req.user.password,
|
|
||||||
);
|
|
||||||
if (!isCurrentPwCorrect) {
|
if (!isCurrentPwCorrect) {
|
||||||
throw new BadRequestError('Provided current password is incorrect.');
|
throw new BadRequestError('Provided current password is incorrect.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const validPassword = this.passwordUtility.validate(newPassword);
|
const validPassword = this.passwordUtility.validate(newPassword);
|
||||||
|
|
||||||
req.user.password = await this.passwordUtility.hash(validPassword);
|
user.password = await this.passwordUtility.hash(validPassword);
|
||||||
|
|
||||||
const user = await this.userRepository.save(req.user);
|
const updatedUser = await this.userRepository.save(user, { transaction: false });
|
||||||
this.logger.info('Password updated successfully', { userId: user.id });
|
this.logger.info('Password updated successfully', { userId: user.id });
|
||||||
|
|
||||||
await issueCookie(res, user);
|
await issueCookie(res, updatedUser);
|
||||||
|
|
||||||
void this.internalHooks.onUserUpdate({
|
void this.internalHooks.onUserUpdate({
|
||||||
user,
|
user: updatedUser,
|
||||||
fields_changed: ['password'],
|
fields_changed: ['password'],
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.externalHooks.run('user.password.update', [user.email, req.user.password]);
|
await this.externalHooks.run('user.password.update', [updatedUser.email, updatedUser.password]);
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
@ -168,11 +166,13 @@ export class MeController {
|
||||||
throw new BadRequestError('Personalization answers are mandatory');
|
throw new BadRequestError('Personalization answers are mandatory');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.userRepository.save({
|
await this.userRepository.save(
|
||||||
|
{
|
||||||
id: req.user.id,
|
id: req.user.id,
|
||||||
// @ts-ignore
|
|
||||||
personalizationAnswers,
|
personalizationAnswers,
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
|
|
||||||
this.logger.info('User survey updated successfully', { userId: req.user.id });
|
this.logger.info('User survey updated successfully', { userId: req.user.id });
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ export class OwnerController {
|
||||||
|
|
||||||
await validateEntity(owner);
|
await validateEntity(owner);
|
||||||
|
|
||||||
owner = await this.userRepository.save(owner);
|
owner = await this.userRepository.save(owner, { transaction: false });
|
||||||
|
|
||||||
this.logger.info('Owner was set up successfully', { userId });
|
this.logger.info('Owner was set up successfully', { userId });
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,11 @@ export class SettingsRepository extends Repository<Settings> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEncryptedSecretsProviderSettings(): Promise<string | null> {
|
async getEncryptedSecretsProviderSettings(): Promise<string | null> {
|
||||||
return (await this.findOne({ where: { key: EXTERNAL_SECRETS_DB_KEY } }))?.value ?? null;
|
return (await this.findByKey(EXTERNAL_SECRETS_DB_KEY))?.value ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByKey(key: string): Promise<Settings | null> {
|
||||||
|
return await this.findOneBy({ key });
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveEncryptedSecretsProviderSettings(data: string): Promise<void> {
|
async saveEncryptedSecretsProviderSettings(data: string): Promise<void> {
|
||||||
|
@ -38,7 +42,7 @@ export class SettingsRepository extends Repository<Settings> {
|
||||||
await this.update({ key }, { value, loadOnStartup: true });
|
await this.update({ key }, { value, loadOnStartup: true });
|
||||||
} else {
|
} else {
|
||||||
value = JSON.stringify([bannerName]);
|
value = JSON.stringify([bannerName]);
|
||||||
await this.save({ key, value, loadOnStartup: true });
|
await this.save({ key, value, loadOnStartup: true }, { transaction: false });
|
||||||
}
|
}
|
||||||
config.set(key, value);
|
config.set(key, value);
|
||||||
return { success: true };
|
return { success: true };
|
||||||
|
|
|
@ -492,7 +492,7 @@ export class SourceControlImportService {
|
||||||
key,
|
key,
|
||||||
value: valueOverrides[key],
|
value: valueOverrides[key],
|
||||||
});
|
});
|
||||||
await Container.get(VariablesRepository).save(newVariable);
|
await Container.get(VariablesRepository).save(newVariable, { transaction: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,11 +173,14 @@ export class SourceControlPreferencesService {
|
||||||
if (saveToDb) {
|
if (saveToDb) {
|
||||||
const settingsValue = JSON.stringify(this._sourceControlPreferences);
|
const settingsValue = JSON.stringify(this._sourceControlPreferences);
|
||||||
try {
|
try {
|
||||||
await Container.get(SettingsRepository).save({
|
await Container.get(SettingsRepository).save(
|
||||||
|
{
|
||||||
key: SOURCE_CONTROL_PREFERENCES_DB_KEY,
|
key: SOURCE_CONTROL_PREFERENCES_DB_KEY,
|
||||||
value: settingsValue,
|
value: settingsValue,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ApplicationError('Failed to save source control preferences', { cause: error });
|
throw new ApplicationError('Failed to save source control preferences', { cause: error });
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,10 +71,13 @@ export class VariablesService {
|
||||||
this.validateVariable(variable);
|
this.validateVariable(variable);
|
||||||
|
|
||||||
void Container.get(InternalHooks).onVariableCreated({ variable_type: variable.type });
|
void Container.get(InternalHooks).onVariableCreated({ variable_type: variable.type });
|
||||||
const saveResult = await this.variablesRepository.save({
|
const saveResult = await this.variablesRepository.save(
|
||||||
|
{
|
||||||
...variable,
|
...variable,
|
||||||
id: generateNanoId(),
|
id: generateNanoId(),
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
await this.updateCache();
|
await this.updateCache();
|
||||||
return saveResult;
|
return saveResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ export class TagService {
|
||||||
|
|
||||||
await this.externalHooks.run(`tag.before${action}`, [tag]);
|
await this.externalHooks.run(`tag.before${action}`, [tag]);
|
||||||
|
|
||||||
const savedTag = this.tagRepository.save(tag);
|
const savedTag = this.tagRepository.save(tag, { transaction: false });
|
||||||
|
|
||||||
await this.externalHooks.run(`tag.after${action}`, [tag]);
|
await this.externalHooks.run(`tag.after${action}`, [tag]);
|
||||||
|
|
||||||
|
|
|
@ -287,13 +287,18 @@ export class SamlService {
|
||||||
let result: Settings;
|
let result: Settings;
|
||||||
if (samlPreferences) {
|
if (samlPreferences) {
|
||||||
samlPreferences.value = settingsValue;
|
samlPreferences.value = settingsValue;
|
||||||
result = await Container.get(SettingsRepository).save(samlPreferences);
|
result = await Container.get(SettingsRepository).save(samlPreferences, {
|
||||||
|
transaction: false,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
result = await Container.get(SettingsRepository).save({
|
result = await Container.get(SettingsRepository).save(
|
||||||
|
{
|
||||||
key: SAML_PREFERENCES_DB_KEY,
|
key: SAML_PREFERENCES_DB_KEY,
|
||||||
value: settingsValue,
|
value: settingsValue,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (result) return jsonParse<SamlPreferences>(result.value);
|
if (result) return jsonParse<SamlPreferences>(result.value);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -109,10 +109,12 @@ export async function createUserFromSamlAttributes(attributes: SamlUserAttribute
|
||||||
authIdentity.providerId = attributes.userPrincipalName;
|
authIdentity.providerId = attributes.userPrincipalName;
|
||||||
authIdentity.providerType = 'saml';
|
authIdentity.providerType = 'saml';
|
||||||
authIdentity.user = user;
|
authIdentity.user = user;
|
||||||
const resultAuthIdentity = await Container.get(AuthIdentityRepository).save(authIdentity);
|
const resultAuthIdentity = await Container.get(AuthIdentityRepository).save(authIdentity, {
|
||||||
|
transaction: false,
|
||||||
|
});
|
||||||
if (!resultAuthIdentity) throw new AuthError('Could not create AuthIdentity');
|
if (!resultAuthIdentity) throw new AuthError('Could not create AuthIdentity');
|
||||||
user.authIdentities = [authIdentity];
|
user.authIdentities = [authIdentity];
|
||||||
const resultUser = await Container.get(UserRepository).save(user);
|
const resultUser = await Container.get(UserRepository).save(user, { transaction: false });
|
||||||
if (!resultUser) throw new AuthError('Could not create User');
|
if (!resultUser) throw new AuthError('Could not create User');
|
||||||
return resultUser;
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
@ -133,10 +135,10 @@ export async function updateUserFromSamlAttributes(
|
||||||
} else {
|
} else {
|
||||||
samlAuthIdentity.providerId = attributes.userPrincipalName;
|
samlAuthIdentity.providerId = attributes.userPrincipalName;
|
||||||
}
|
}
|
||||||
await Container.get(AuthIdentityRepository).save(samlAuthIdentity);
|
await Container.get(AuthIdentityRepository).save(samlAuthIdentity, { transaction: false });
|
||||||
user.firstName = attributes.firstName;
|
user.firstName = attributes.firstName;
|
||||||
user.lastName = attributes.lastName;
|
user.lastName = attributes.lastName;
|
||||||
const resultUser = await Container.get(UserRepository).save(user);
|
const resultUser = await Container.get(UserRepository).save(user, { transaction: false });
|
||||||
if (!resultUser) throw new AuthError('Could not create User');
|
if (!resultUser) throw new AuthError('Could not create User');
|
||||||
return resultUser;
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,14 @@ export async function setCurrentAuthenticationMethod(
|
||||||
authenticationMethod: AuthProviderType,
|
authenticationMethod: AuthProviderType,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
config.set('userManagement.authenticationMethod', authenticationMethod);
|
config.set('userManagement.authenticationMethod', authenticationMethod);
|
||||||
await Container.get(SettingsRepository).save({
|
await Container.get(SettingsRepository).save(
|
||||||
|
{
|
||||||
key: 'userManagement.authenticationMethod',
|
key: 'userManagement.authenticationMethod',
|
||||||
value: authenticationMethod,
|
value: authenticationMethod,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
});
|
},
|
||||||
|
{ transaction: false },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentAuthenticationMethod(): AuthProviderType {
|
export function getCurrentAuthenticationMethod(): AuthProviderType {
|
||||||
|
|
|
@ -192,6 +192,17 @@ describe('MeController', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('storeSurveyAnswers', () => {
|
||||||
|
it('should throw BadRequestError if answers are missing in the payload', async () => {
|
||||||
|
const req = mock<MeRequest.SurveyAnswers>({
|
||||||
|
body: undefined,
|
||||||
|
});
|
||||||
|
await expect(controller.storeSurveyAnswers(req)).rejects.toThrowError(
|
||||||
|
new BadRequestError('Personalization answers are mandatory'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('API Key methods', () => {
|
describe('API Key methods', () => {
|
||||||
let req: AuthenticatedRequest;
|
let req: AuthenticatedRequest;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
|
|
@ -95,7 +95,7 @@ describe('OwnerController', () => {
|
||||||
|
|
||||||
await controller.setupOwner(req, res);
|
await controller.setupOwner(req, res);
|
||||||
|
|
||||||
expect(userRepository.save).toHaveBeenCalledWith(user);
|
expect(userRepository.save).toHaveBeenCalledWith(user, { transaction: false });
|
||||||
|
|
||||||
const cookieOptions = captor<CookieOptions>();
|
const cookieOptions = captor<CookieOptions>();
|
||||||
expect(res.cookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME, 'signed-token', cookieOptions);
|
expect(res.cookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME, 'signed-token', cookieOptions);
|
||||||
|
|
Loading…
Reference in a new issue