mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
fix(core): Do not return inviteAcceptUrl
in response if email was sent (#7465)
This commit is contained in:
parent
ab6a9bbac2
commit
55c6a1b0d3
|
@ -310,7 +310,6 @@ export class Server extends AbstractServer {
|
||||||
new MeController(logger, externalHooks, internalHooks, userService),
|
new MeController(logger, externalHooks, internalHooks, userService),
|
||||||
new NodeTypesController(config, nodeTypes),
|
new NodeTypesController(config, nodeTypes),
|
||||||
new PasswordResetController(
|
new PasswordResetController(
|
||||||
config,
|
|
||||||
logger,
|
logger,
|
||||||
externalHooks,
|
externalHooks,
|
||||||
internalHooks,
|
internalHooks,
|
||||||
|
|
|
@ -12,13 +12,6 @@ import { License } from '@/License';
|
||||||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
|
|
||||||
export function isEmailSetUp(): boolean {
|
|
||||||
const smtp = config.getEnv('userManagement.emails.mode') === 'smtp';
|
|
||||||
const host = !!config.getEnv('userManagement.emails.smtp.host');
|
|
||||||
|
|
||||||
return smtp && host;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSharingEnabled(): boolean {
|
export function isSharingEnabled(): boolean {
|
||||||
return Container.get(License).isSharingEnabled();
|
return Container.get(License).isSharingEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,14 +34,17 @@ async function getTemplate(
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class UserManagementMailer {
|
export class UserManagementMailer {
|
||||||
|
readonly isEmailSetUp: boolean;
|
||||||
|
|
||||||
private mailer: NodeMailer | undefined;
|
private mailer: NodeMailer | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Other implementations can be used in the future.
|
this.isEmailSetUp =
|
||||||
if (
|
|
||||||
config.getEnv('userManagement.emails.mode') === 'smtp' &&
|
config.getEnv('userManagement.emails.mode') === 'smtp' &&
|
||||||
config.getEnv('userManagement.emails.smtp.host') !== ''
|
config.getEnv('userManagement.emails.smtp.host') !== '';
|
||||||
) {
|
|
||||||
|
// Other implementations can be used in the future.
|
||||||
|
if (this.isEmailSetUp) {
|
||||||
this.mailer = new NodeMailer();
|
this.mailer = new NodeMailer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { UserManagementMailer } from '@/UserManagement/email';
|
||||||
|
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { ILogger } from 'n8n-workflow';
|
import { ILogger } from 'n8n-workflow';
|
||||||
import { Config } from '@/config';
|
|
||||||
import { PasswordResetRequest } from '@/requests';
|
import { PasswordResetRequest } from '@/requests';
|
||||||
import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||||
import { issueCookie } from '@/auth/jwt';
|
import { issueCookie } from '@/auth/jwt';
|
||||||
|
@ -35,7 +34,6 @@ import { MfaService } from '@/Mfa/mfa.service';
|
||||||
@RestController()
|
@RestController()
|
||||||
export class PasswordResetController {
|
export class PasswordResetController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly config: Config,
|
|
||||||
private readonly logger: ILogger,
|
private readonly logger: ILogger,
|
||||||
private readonly externalHooks: IExternalHooksClass,
|
private readonly externalHooks: IExternalHooksClass,
|
||||||
private readonly internalHooks: IInternalHooksClass,
|
private readonly internalHooks: IInternalHooksClass,
|
||||||
|
@ -50,7 +48,7 @@ export class PasswordResetController {
|
||||||
*/
|
*/
|
||||||
@Post('/forgot-password')
|
@Post('/forgot-password')
|
||||||
async forgotPassword(req: PasswordResetRequest.Email) {
|
async forgotPassword(req: PasswordResetRequest.Email) {
|
||||||
if (this.config.getEnv('userManagement.emails.mode') === '') {
|
if (!this.mailer.isEmailSetUp) {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
'Request to send password reset email failed because emailing was not set up',
|
'Request to send password reset email failed because emailing was not set up',
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
generateUserInviteUrl,
|
generateUserInviteUrl,
|
||||||
getInstanceBaseUrl,
|
getInstanceBaseUrl,
|
||||||
hashPassword,
|
hashPassword,
|
||||||
isEmailSetUp,
|
|
||||||
validatePassword,
|
validatePassword,
|
||||||
} from '@/UserManagement/UserManagementHelper';
|
} from '@/UserManagement/UserManagementHelper';
|
||||||
import { issueCookie } from '@/auth/jwt';
|
import { issueCookie } from '@/auth/jwt';
|
||||||
|
@ -184,7 +183,7 @@ export class UsersController {
|
||||||
}
|
}
|
||||||
const inviteAcceptUrl = generateUserInviteUrl(req.user.id, id);
|
const inviteAcceptUrl = generateUserInviteUrl(req.user.id, id);
|
||||||
const resp: {
|
const resp: {
|
||||||
user: { id: string | null; email: string; inviteAcceptUrl: string; emailSent: boolean };
|
user: { id: string | null; email: string; inviteAcceptUrl?: string; emailSent: boolean };
|
||||||
error?: string;
|
error?: string;
|
||||||
} = {
|
} = {
|
||||||
user: {
|
user: {
|
||||||
|
@ -202,6 +201,7 @@ export class UsersController {
|
||||||
});
|
});
|
||||||
if (result.emailSent) {
|
if (result.emailSent) {
|
||||||
resp.user.emailSent = true;
|
resp.user.emailSent = true;
|
||||||
|
delete resp.user.inviteAcceptUrl;
|
||||||
void this.internalHooks.onUserTransactionalEmail({
|
void this.internalHooks.onUserTransactionalEmail({
|
||||||
user_id: id,
|
user_id: id,
|
||||||
message_type: 'New user invite',
|
message_type: 'New user invite',
|
||||||
|
@ -619,7 +619,7 @@ export class UsersController {
|
||||||
throw new UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
throw new UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEmailSetUp()) {
|
if (!this.mailer.isEmailSetUp) {
|
||||||
this.logger.error('Request to reinvite a user failed because email sending was not set up');
|
this.logger.error('Request to reinvite a user failed because email sending was not set up');
|
||||||
throw new InternalServerError('Email sending must be set up in order to invite other users');
|
throw new InternalServerError('Email sending must be set up in order to invite other users');
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
||||||
import { CredentialTypes } from '@/CredentialTypes';
|
import { CredentialTypes } from '@/CredentialTypes';
|
||||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { getInstanceBaseUrl, isEmailSetUp } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||||
import * as WebhookHelpers from '@/WebhookHelpers';
|
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||||
import { LoggerProxy } from 'n8n-workflow';
|
import { LoggerProxy } from 'n8n-workflow';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -28,6 +28,7 @@ import {
|
||||||
getWorkflowHistoryLicensePruneTime,
|
getWorkflowHistoryLicensePruneTime,
|
||||||
getWorkflowHistoryPruneTime,
|
getWorkflowHistoryPruneTime,
|
||||||
} from '@/workflows/workflowHistory/workflowHistoryHelper.ee';
|
} from '@/workflows/workflowHistory/workflowHistoryHelper.ee';
|
||||||
|
import { UserManagementMailer } from '@/UserManagement/email';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class FrontendService {
|
export class FrontendService {
|
||||||
|
@ -38,6 +39,7 @@ export class FrontendService {
|
||||||
private readonly credentialTypes: CredentialTypes,
|
private readonly credentialTypes: CredentialTypes,
|
||||||
private readonly credentialsOverwrites: CredentialsOverwrites,
|
private readonly credentialsOverwrites: CredentialsOverwrites,
|
||||||
private readonly license: License,
|
private readonly license: License,
|
||||||
|
private readonly mailer: UserManagementMailer,
|
||||||
) {
|
) {
|
||||||
this.initSettings();
|
this.initSettings();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +105,7 @@ export class FrontendService {
|
||||||
userManagement: {
|
userManagement: {
|
||||||
quota: this.license.getUsersLimit(),
|
quota: this.license.getUsersLimit(),
|
||||||
showSetupOnFirstLoad: !config.getEnv('userManagement.isInstanceOwnerSetUp'),
|
showSetupOnFirstLoad: !config.getEnv('userManagement.isInstanceOwnerSetUp'),
|
||||||
smtpSetup: isEmailSetUp(),
|
smtpSetup: this.mailer.isEmailSetUp,
|
||||||
authenticationMethod: getCurrentAuthenticationMethod(),
|
authenticationMethod: getCurrentAuthenticationMethod(),
|
||||||
},
|
},
|
||||||
sso: {
|
sso: {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
import type { Entry as LdapUser } from 'ldapts';
|
import type { Entry as LdapUser } from 'ldapts';
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { type ILogger, jsonParse, LoggerProxy } from 'n8n-workflow';
|
||||||
|
import { mock } from 'jest-mock-extended';
|
||||||
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import type { Role } from '@db/entities/Role';
|
import type { Role } from '@db/entities/Role';
|
||||||
|
@ -17,17 +19,13 @@ import { randomEmail, randomName, uniqueId } from './../shared/random';
|
||||||
import * as testDb from './../shared/testDb';
|
import * as testDb from './../shared/testDb';
|
||||||
import * as utils from '../shared/utils/';
|
import * as utils from '../shared/utils/';
|
||||||
|
|
||||||
import { LoggerProxy } from 'n8n-workflow';
|
|
||||||
import { getLogger } from '@/Logger';
|
|
||||||
|
|
||||||
jest.mock('@/telemetry');
|
jest.mock('@/telemetry');
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
|
||||||
|
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let owner: User;
|
let owner: User;
|
||||||
let authOwnerAgent: SuperAgentTest;
|
let authOwnerAgent: SuperAgentTest;
|
||||||
|
|
||||||
LoggerProxy.init(getLogger());
|
LoggerProxy.init(mock<ILogger>());
|
||||||
|
|
||||||
const defaultLdapConfig = {
|
const defaultLdapConfig = {
|
||||||
...LDAP_DEFAULT_CONFIGURATION,
|
...LDAP_DEFAULT_CONFIGURATION,
|
||||||
|
@ -80,7 +78,6 @@ beforeEach(async () => {
|
||||||
jest.mock('@/telemetry');
|
jest.mock('@/telemetry');
|
||||||
|
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
config.set('userManagement.emails.mode', '');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const createLdapConfig = async (attributes: Partial<LdapConfig> = {}): Promise<LdapConfig> => {
|
const createLdapConfig = async (attributes: Partial<LdapConfig> = {}): Promise<LdapConfig> => {
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { compare } from 'bcryptjs';
|
import { compare } from 'bcryptjs';
|
||||||
|
import { Container } from 'typedi';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { Role } from '@db/entities/Role';
|
import type { Role } from '@db/entities/Role';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
import { setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
||||||
|
import { ExternalHooks } from '@/ExternalHooks';
|
||||||
|
import { JwtService } from '@/services/jwt.service';
|
||||||
|
import { UserManagementMailer } from '@/UserManagement/email';
|
||||||
|
|
||||||
import * as utils from './shared/utils/';
|
import * as utils from './shared/utils/';
|
||||||
import {
|
import {
|
||||||
randomEmail,
|
randomEmail,
|
||||||
|
@ -15,12 +21,7 @@ import {
|
||||||
randomValidPassword,
|
randomValidPassword,
|
||||||
} from './shared/random';
|
} from './shared/random';
|
||||||
import * as testDb from './shared/testDb';
|
import * as testDb from './shared/testDb';
|
||||||
import { setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
|
||||||
import { ExternalHooks } from '@/ExternalHooks';
|
|
||||||
import { JwtService } from '@/services/jwt.service';
|
|
||||||
import { Container } from 'typedi';
|
|
||||||
|
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
|
||||||
config.set('userManagement.jwtSecret', randomString(5, 10));
|
config.set('userManagement.jwtSecret', randomString(5, 10));
|
||||||
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
|
@ -29,6 +30,7 @@ let owner: User;
|
||||||
let member: User;
|
let member: User;
|
||||||
|
|
||||||
const externalHooks = utils.mockInstance(ExternalHooks);
|
const externalHooks = utils.mockInstance(ExternalHooks);
|
||||||
|
const mailer = utils.mockInstance(UserManagementMailer, { isEmailSetUp: true });
|
||||||
const testServer = utils.setupTestServer({ endpointGroups: ['passwordReset'] });
|
const testServer = utils.setupTestServer({ endpointGroups: ['passwordReset'] });
|
||||||
const jwtService = Container.get(JwtService);
|
const jwtService = Container.get(JwtService);
|
||||||
|
|
||||||
|
@ -43,6 +45,7 @@ beforeEach(async () => {
|
||||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||||
externalHooks.run.mockReset();
|
externalHooks.run.mockReset();
|
||||||
|
jest.replaceProperty(mailer, 'isEmailSetUp', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /forgot-password', () => {
|
describe('POST /forgot-password', () => {
|
||||||
|
@ -52,8 +55,6 @@ describe('POST /forgot-password', () => {
|
||||||
globalRole: globalMemberRole,
|
globalRole: globalMemberRole,
|
||||||
});
|
});
|
||||||
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
[{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => {
|
[{ email: owner.email }, { email: member.email.toUpperCase() }].map(async (payload) => {
|
||||||
const response = await testServer.authlessAgent.post('/forgot-password').send(payload);
|
const response = await testServer.authlessAgent.post('/forgot-password').send(payload);
|
||||||
|
@ -65,7 +66,7 @@ describe('POST /forgot-password', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fail if emailing is not set up', async () => {
|
test('should fail if emailing is not set up', async () => {
|
||||||
config.set('userManagement.emails.mode', '');
|
jest.replaceProperty(mailer, 'isEmailSetUp', false);
|
||||||
|
|
||||||
await testServer.authlessAgent
|
await testServer.authlessAgent
|
||||||
.post('/forgot-password')
|
.post('/forgot-password')
|
||||||
|
@ -75,7 +76,6 @@ describe('POST /forgot-password', () => {
|
||||||
|
|
||||||
test('should fail if SAML is authentication method', async () => {
|
test('should fail if SAML is authentication method', async () => {
|
||||||
await setCurrentAuthenticationMethod('saml');
|
await setCurrentAuthenticationMethod('saml');
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
const member = await testDb.createUser({
|
const member = await testDb.createUser({
|
||||||
email: 'test@test.com',
|
email: 'test@test.com',
|
||||||
globalRole: globalMemberRole,
|
globalRole: globalMemberRole,
|
||||||
|
@ -91,7 +91,6 @@ describe('POST /forgot-password', () => {
|
||||||
|
|
||||||
test('should succeed if SAML is authentication method and requestor is owner', async () => {
|
test('should succeed if SAML is authentication method and requestor is owner', async () => {
|
||||||
await setCurrentAuthenticationMethod('saml');
|
await setCurrentAuthenticationMethod('saml');
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
|
|
||||||
const response = await testServer.authlessAgent
|
const response = await testServer.authlessAgent
|
||||||
.post('/forgot-password')
|
.post('/forgot-password')
|
||||||
|
@ -104,8 +103,6 @@ describe('POST /forgot-password', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fail with invalid inputs', async () => {
|
test('should fail with invalid inputs', async () => {
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
|
|
||||||
const invalidPayloads = [
|
const invalidPayloads = [
|
||||||
randomEmail(),
|
randomEmail(),
|
||||||
[randomEmail()],
|
[randomEmail()],
|
||||||
|
@ -121,8 +118,6 @@ describe('POST /forgot-password', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fail if user is not found', async () => {
|
test('should fail if user is not found', async () => {
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
|
|
||||||
const response = await testServer.authlessAgent
|
const response = await testServer.authlessAgent
|
||||||
.post('/forgot-password')
|
.post('/forgot-password')
|
||||||
.send({ email: randomEmail() });
|
.send({ email: randomEmail() });
|
||||||
|
@ -132,10 +127,6 @@ describe('POST /forgot-password', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /resolve-password-token', () => {
|
describe('GET /resolve-password-token', () => {
|
||||||
beforeEach(() => {
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should succeed with valid inputs', async () => {
|
test('should succeed with valid inputs', async () => {
|
||||||
const resetPasswordToken = jwtService.signData({ sub: owner.id });
|
const resetPasswordToken = jwtService.signData({ sub: owner.id });
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,6 @@ export const setupTestServer = ({
|
||||||
app,
|
app,
|
||||||
config,
|
config,
|
||||||
new PasswordResetController(
|
new PasswordResetController(
|
||||||
config,
|
|
||||||
logger,
|
logger,
|
||||||
externalHooks,
|
externalHooks,
|
||||||
internalHooks,
|
internalHooks,
|
||||||
|
|
|
@ -2,7 +2,6 @@ import validator from 'validator';
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import type { Role } from '@db/entities/Role';
|
import type { Role } from '@db/entities/Role';
|
||||||
|
@ -10,7 +9,6 @@ import type { User } from '@db/entities/User';
|
||||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import { compareHash } from '@/UserManagement/UserManagementHelper';
|
import { compareHash } from '@/UserManagement/UserManagementHelper';
|
||||||
import { UserManagementMailer } from '@/UserManagement/email/UserManagementMailer';
|
import { UserManagementMailer } from '@/UserManagement/email/UserManagementMailer';
|
||||||
import { NodeMailer } from '@/UserManagement/email/NodeMailer';
|
|
||||||
|
|
||||||
import { SUCCESS_RESPONSE_BODY } from './shared/constants';
|
import { SUCCESS_RESPONSE_BODY } from './shared/constants';
|
||||||
import {
|
import {
|
||||||
|
@ -23,14 +21,14 @@ import {
|
||||||
import * as testDb from './shared/testDb';
|
import * as testDb from './shared/testDb';
|
||||||
import * as utils from './shared/utils/';
|
import * as utils from './shared/utils/';
|
||||||
|
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
|
||||||
|
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let workflowOwnerRole: Role;
|
let workflowOwnerRole: Role;
|
||||||
let credentialOwnerRole: Role;
|
let credentialOwnerRole: Role;
|
||||||
let owner: User;
|
let owner: User;
|
||||||
let authOwnerAgent: SuperAgentTest;
|
let authOwnerAgent: SuperAgentTest;
|
||||||
|
|
||||||
|
const mailer = utils.mockInstance(UserManagementMailer, { isEmailSetUp: true });
|
||||||
|
|
||||||
const testServer = utils.setupTestServer({ endpointGroups: ['users'] });
|
const testServer = utils.setupTestServer({ endpointGroups: ['users'] });
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
@ -54,10 +52,7 @@ beforeEach(async () => {
|
||||||
await testDb.truncate(['SharedCredentials', 'SharedWorkflow', 'Workflow', 'Credentials']);
|
await testDb.truncate(['SharedCredentials', 'SharedWorkflow', 'Workflow', 'Credentials']);
|
||||||
await Db.collections.User.delete({ id: Not(owner.id) });
|
await Db.collections.User.delete({ id: Not(owner.id) });
|
||||||
|
|
||||||
jest.mock('@/config');
|
mailer.invite.mockResolvedValue({ emailSent: true });
|
||||||
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
config.set('userManagement.emails.smtp.host', '');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('DELETE /users/:id', () => {
|
describe('DELETE /users/:id', () => {
|
||||||
|
@ -313,11 +308,8 @@ describe('POST /users/:id', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /users', () => {
|
describe('POST /users', () => {
|
||||||
beforeEach(() => {
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should succeed if emailing is not set up', async () => {
|
test('should succeed if emailing is not set up', async () => {
|
||||||
|
mailer.invite.mockResolvedValueOnce({ emailSent: false });
|
||||||
const response = await authOwnerAgent.post('/users').send([{ email: randomEmail() }]);
|
const response = await authOwnerAgent.post('/users').send([{ email: randomEmail() }]);
|
||||||
|
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
@ -342,11 +334,12 @@ describe('POST /users', () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
for (const {
|
for (const {
|
||||||
user: { id, email: receivedEmail },
|
user: { id, email: receivedEmail, inviteAcceptUrl },
|
||||||
error,
|
error,
|
||||||
} of response.body.data) {
|
} of response.body.data) {
|
||||||
expect(validator.isUUID(id)).toBe(true);
|
expect(validator.isUUID(id)).toBe(true);
|
||||||
expect(id).not.toBe(member.id);
|
expect(id).not.toBe(member.id);
|
||||||
|
expect(inviteAcceptUrl).toBeUndefined();
|
||||||
|
|
||||||
const lowerCasedEmail = receivedEmail.toLowerCase();
|
const lowerCasedEmail = receivedEmail.toLowerCase();
|
||||||
expect(receivedEmail).toBe(lowerCasedEmail);
|
expect(receivedEmail).toBe(lowerCasedEmail);
|
||||||
|
@ -401,14 +394,6 @@ describe('POST /users', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /users/:id/reinvite', () => {
|
describe('POST /users/:id/reinvite', () => {
|
||||||
beforeEach(() => {
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
// those configs are needed to make sure the reinvite email is sent,because of this check isEmailSetUp()
|
|
||||||
config.set('userManagement.emails.smtp.host', 'host');
|
|
||||||
config.set('userManagement.emails.smtp.auth.user', 'user');
|
|
||||||
config.set('userManagement.emails.smtp.auth.pass', 'pass');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should send reinvite, but fail if user already accepted invite', async () => {
|
test('should send reinvite, but fail if user already accepted invite', async () => {
|
||||||
const email = randomEmail();
|
const email = randomEmail();
|
||||||
const payload = [{ email }];
|
const payload = [{ email }];
|
||||||
|
@ -428,38 +413,3 @@ describe('POST /users/:id/reinvite', () => {
|
||||||
expect(reinviteMemberResponse.statusCode).toBe(400);
|
expect(reinviteMemberResponse.statusCode).toBe(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('UserManagementMailer expect NodeMailer.verifyConnection', () => {
|
|
||||||
let mockInit: jest.SpyInstance<Promise<void>, []>;
|
|
||||||
let mockVerifyConnection: jest.SpyInstance<Promise<void>, []>;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
mockVerifyConnection = jest
|
|
||||||
.spyOn(NodeMailer.prototype, 'verifyConnection')
|
|
||||||
.mockImplementation(async () => {});
|
|
||||||
mockInit = jest.spyOn(NodeMailer.prototype, 'init').mockImplementation(async () => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
mockVerifyConnection.mockRestore();
|
|
||||||
mockInit.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('not be called when SMTP not set up', async () => {
|
|
||||||
const userManagementMailer = new UserManagementMailer();
|
|
||||||
// NodeMailer.verifyConnection gets called only explicitly
|
|
||||||
await expect(async () => userManagementMailer.verifyConnection()).rejects.toThrow();
|
|
||||||
|
|
||||||
expect(NodeMailer.prototype.verifyConnection).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('to be called when SMTP set up', async () => {
|
|
||||||
// host needs to be set, otherwise smtp is skipped
|
|
||||||
config.set('userManagement.emails.smtp.host', 'host');
|
|
||||||
config.set('userManagement.emails.mode', 'smtp');
|
|
||||||
|
|
||||||
const userManagementMailer = new UserManagementMailer();
|
|
||||||
// NodeMailer.verifyConnection gets called only explicitly
|
|
||||||
expect(async () => userManagementMailer.verifyConnection()).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
40
packages/cli/test/unit/UserManagementMailer.test.ts
Normal file
40
packages/cli/test/unit/UserManagementMailer.test.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import config from '@/config';
|
||||||
|
import { NodeMailer } from '@/UserManagement/email/NodeMailer';
|
||||||
|
import { UserManagementMailer } from '@/UserManagement/email/UserManagementMailer';
|
||||||
|
|
||||||
|
describe('UserManagementMailer', () => {
|
||||||
|
describe('expect NodeMailer.verifyConnection', () => {
|
||||||
|
let mockInit: jest.SpyInstance<Promise<void>, []>;
|
||||||
|
let mockVerifyConnection: jest.SpyInstance<Promise<void>, []>;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
mockVerifyConnection = jest
|
||||||
|
.spyOn(NodeMailer.prototype, 'verifyConnection')
|
||||||
|
.mockImplementation(async () => {});
|
||||||
|
mockInit = jest.spyOn(NodeMailer.prototype, 'init').mockImplementation(async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
mockVerifyConnection.mockRestore();
|
||||||
|
mockInit.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('not be called when SMTP not set up', async () => {
|
||||||
|
const userManagementMailer = new UserManagementMailer();
|
||||||
|
// NodeMailer.verifyConnection gets called only explicitly
|
||||||
|
await expect(async () => userManagementMailer.verifyConnection()).rejects.toThrow();
|
||||||
|
|
||||||
|
expect(NodeMailer.prototype.verifyConnection).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('to be called when SMTP set up', async () => {
|
||||||
|
// host needs to be set, otherwise smtp is skipped
|
||||||
|
config.set('userManagement.emails.smtp.host', 'host');
|
||||||
|
config.set('userManagement.emails.mode', 'smtp');
|
||||||
|
|
||||||
|
const userManagementMailer = new UserManagementMailer();
|
||||||
|
// NodeMailer.verifyConnection gets called only explicitly
|
||||||
|
expect(async () => userManagementMailer.verifyConnection()).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue