diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index ebc16f9a61..6114c40701 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -168,11 +168,14 @@ import { isExternalSecretsEnabled } from './ExternalSecrets/externalSecretsHelpe import { isSourceControlLicensed } from '@/environments/sourceControl/sourceControlHelper.ee'; import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee'; import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee'; -import { ExecutionRepository } from '@db/repositories'; +import { ExecutionRepository, SettingsRepository } from '@db/repositories'; import type { ExecutionEntity } from '@db/entities/ExecutionEntity'; import { TOTPService } from './Mfa/totp.service'; import { MfaService } from './Mfa/mfa.service'; import { handleMfaDisable, isMfaFeatureEnabled } from './Mfa/helpers'; +import { JwtService } from './services/jwt.service'; +import { RoleService } from './services/role.service'; +import { UserService } from './services/user.service'; const exec = promisify(callbackExec); @@ -498,35 +501,50 @@ export class Server extends AbstractServer { const logger = LoggerProxy; const internalHooks = Container.get(InternalHooks); const mailer = Container.get(UserManagementMailer); + const userService = Container.get(UserService); + const jwtService = Container.get(JwtService); const postHog = this.postHog; const mfaService = new MfaService(repositories.User, new TOTPService(), encryptionKey); const controllers: object[] = [ new EventBusController(), - new AuthController({ config, internalHooks, logger, postHog, mfaService }), - new OwnerController({ config, internalHooks, repositories, logger, postHog }), - new MeController({ externalHooks, internalHooks, logger }), - new NodeTypesController({ config, nodeTypes }), - new PasswordResetController({ + new AuthController(config, logger, internalHooks, mfaService, userService, postHog), + new OwnerController( config, + logger, + internalHooks, + Container.get(SettingsRepository), + userService, + postHog, + ), + new MeController(logger, externalHooks, internalHooks, userService), + new NodeTypesController(config, nodeTypes), + new PasswordResetController( + config, + logger, externalHooks, internalHooks, mailer, - logger, + userService, + jwtService, mfaService, - }), + ), Container.get(TagsController), new TranslationController(config, this.credentialTypes), - new UsersController({ + new UsersController( config, - mailer, + logger, externalHooks, internalHooks, - repositories, + repositories.SharedCredentials, + repositories.SharedWorkflow, activeWorkflowRunner, - logger, + mailer, + jwtService, + Container.get(RoleService), + userService, postHog, - }), + ), Container.get(SamlController), Container.get(SourceControlController), Container.get(WorkflowStatisticsController), diff --git a/packages/cli/src/controllers/auth.controller.ts b/packages/cli/src/controllers/auth.controller.ts index 820e4f269d..a02be95cdb 100644 --- a/packages/cli/src/controllers/auth.controller.ts +++ b/packages/cli/src/controllers/auth.controller.ts @@ -12,13 +12,14 @@ import { sanitizeUser, withFeatureFlags } from '@/UserManagement/UserManagementH import { issueCookie, resolveJwt } from '@/auth/jwt'; import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants'; import { Request, Response } from 'express'; -import type { ILogger } from 'n8n-workflow'; +import { ILogger } from 'n8n-workflow'; import type { User } from '@db/entities/User'; import { LoginRequest, UserRequest } from '@/requests'; -import type { Config } from '@/config'; -import type { PublicUser, IInternalHooksClass, CurrentUser } from '@/Interfaces'; +import { Config } from '@/config'; +import { IInternalHooksClass } from '@/Interfaces'; +import type { PublicUser, CurrentUser } from '@/Interfaces'; import { handleEmailLogin, handleLdapLogin } from '@/auth'; -import type { PostHogClient } from '@/posthog'; +import { PostHogClient } from '@/posthog'; import { getCurrentAuthenticationMethod, isLdapCurrentAuthenticationMethod, @@ -27,42 +28,18 @@ import { import { InternalHooks } from '../InternalHooks'; import { License } from '@/License'; import { UserService } from '@/services/user.service'; -import type { MfaService } from '@/Mfa/mfa.service'; +import { MfaService } from '@/Mfa/mfa.service'; @RestController() export class AuthController { - private readonly config: Config; - - private readonly logger: ILogger; - - private readonly internalHooks: IInternalHooksClass; - - private readonly userService: UserService; - - private readonly postHog?: PostHogClient; - - private readonly mfaService: MfaService; - - constructor({ - config, - logger, - internalHooks, - postHog, - mfaService, - }: { - config: Config; - logger: ILogger; - internalHooks: IInternalHooksClass; - postHog?: PostHogClient; - mfaService: MfaService; - }) { - this.config = config; - this.logger = logger; - this.internalHooks = internalHooks; - this.postHog = postHog; - this.userService = Container.get(UserService); - this.mfaService = mfaService; - } + constructor( + private readonly config: Config, + private readonly logger: ILogger, + private readonly internalHooks: IInternalHooksClass, + private readonly mfaService: MfaService, + private readonly userService: UserService, + private readonly postHog?: PostHogClient, + ) {} /** * Log in a user. diff --git a/packages/cli/src/controllers/me.controller.ts b/packages/cli/src/controllers/me.controller.ts index bfebaf0a71..ad8e4ed393 100644 --- a/packages/cli/src/controllers/me.controller.ts +++ b/packages/cli/src/controllers/me.controller.ts @@ -12,44 +12,28 @@ import { validateEntity } from '@/GenericHelpers'; import { issueCookie } from '@/auth/jwt'; import type { User } from '@db/entities/User'; import { Response } from 'express'; -import type { ILogger } from 'n8n-workflow'; +import { ILogger } from 'n8n-workflow'; import { AuthenticatedRequest, MeRequest, UserSettingsUpdatePayload, UserUpdatePayload, } from '@/requests'; -import type { PublicUser, IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; +import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; +import type { PublicUser } from '@/Interfaces'; import { randomBytes } from 'crypto'; import { isSamlLicensedAndEnabled } from '../sso/saml/samlHelpers'; import { UserService } from '@/services/user.service'; -import Container from 'typedi'; @Authorized() @RestController('/me') export class MeController { - private readonly logger: ILogger; - - private readonly externalHooks: IExternalHooksClass; - - private readonly internalHooks: IInternalHooksClass; - - private readonly userService: UserService; - - constructor({ - logger, - externalHooks, - internalHooks, - }: { - logger: ILogger; - externalHooks: IExternalHooksClass; - internalHooks: IInternalHooksClass; - }) { - this.logger = logger; - this.externalHooks = externalHooks; - this.internalHooks = internalHooks; - this.userService = Container.get(UserService); - } + constructor( + private readonly logger: ILogger, + private readonly externalHooks: IExternalHooksClass, + private readonly internalHooks: IInternalHooksClass, + private readonly userService: UserService, + ) {} /** * Update the logged-in user's properties, except password. diff --git a/packages/cli/src/controllers/nodeTypes.controller.ts b/packages/cli/src/controllers/nodeTypes.controller.ts index 49dec0b674..675d0f9741 100644 --- a/packages/cli/src/controllers/nodeTypes.controller.ts +++ b/packages/cli/src/controllers/nodeTypes.controller.ts @@ -4,20 +4,16 @@ import { Request } from 'express'; import type { INodeTypeDescription, INodeTypeNameVersion } from 'n8n-workflow'; import { Authorized, Post, RestController } from '@/decorators'; import { getNodeTranslationPath } from '@/TranslationHelpers'; -import type { Config } from '@/config'; -import type { NodeTypes } from '@/NodeTypes'; +import { Config } from '@/config'; +import { NodeTypes } from '@/NodeTypes'; @Authorized() @RestController('/node-types') export class NodeTypesController { - private readonly config: Config; - - private readonly nodeTypes: NodeTypes; - - constructor({ config, nodeTypes }: { config: Config; nodeTypes: NodeTypes }) { - this.config = config; - this.nodeTypes = nodeTypes; - } + constructor( + private readonly config: Config, + private readonly nodeTypes: NodeTypes, + ) {} @Post('/') async getNodeInfo(req: Request) { diff --git a/packages/cli/src/controllers/owner.controller.ts b/packages/cli/src/controllers/owner.controller.ts index 3437884f1f..362b298761 100644 --- a/packages/cli/src/controllers/owner.controller.ts +++ b/packages/cli/src/controllers/owner.controller.ts @@ -10,50 +10,25 @@ import { } from '@/UserManagement/UserManagementHelper'; import { issueCookie } from '@/auth/jwt'; import { Response } from 'express'; -import type { ILogger } from 'n8n-workflow'; -import type { Config } from '@/config'; +import { ILogger } from 'n8n-workflow'; +import { Config } from '@/config'; import { OwnerRequest } from '@/requests'; -import type { IDatabaseCollections, IInternalHooksClass } from '@/Interfaces'; -import type { SettingsRepository } from '@db/repositories'; +import { IInternalHooksClass } from '@/Interfaces'; +import { SettingsRepository } from '@db/repositories'; +import { PostHogClient } from '@/posthog'; import { UserService } from '@/services/user.service'; -import Container from 'typedi'; -import type { PostHogClient } from '@/posthog'; @Authorized(['global', 'owner']) @RestController('/owner') export class OwnerController { - private readonly config: Config; - - private readonly logger: ILogger; - - private readonly internalHooks: IInternalHooksClass; - - private readonly userService: UserService; - - private readonly settingsRepository: SettingsRepository; - - private readonly postHog?: PostHogClient; - - constructor({ - config, - logger, - internalHooks, - repositories, - postHog, - }: { - config: Config; - logger: ILogger; - internalHooks: IInternalHooksClass; - repositories: Pick; - postHog?: PostHogClient; - }) { - this.config = config; - this.logger = logger; - this.internalHooks = internalHooks; - this.userService = Container.get(UserService); - this.settingsRepository = repositories.Settings; - this.postHog = postHog; - } + constructor( + private readonly config: Config, + private readonly logger: ILogger, + private readonly internalHooks: IInternalHooksClass, + private readonly settingsRepository: SettingsRepository, + private readonly userService: UserService, + private readonly postHog?: PostHogClient, + ) {} /** * Promote a shell into the owner of the n8n instance, diff --git a/packages/cli/src/controllers/passwordReset.controller.ts b/packages/cli/src/controllers/passwordReset.controller.ts index a0e34e8d28..838413c319 100644 --- a/packages/cli/src/controllers/passwordReset.controller.ts +++ b/packages/cli/src/controllers/passwordReset.controller.ts @@ -13,13 +13,13 @@ import { hashPassword, validatePassword, } from '@/UserManagement/UserManagementHelper'; -import type { UserManagementMailer } from '@/UserManagement/email'; +import { UserManagementMailer } from '@/UserManagement/email'; import { Response } from 'express'; -import type { ILogger } from 'n8n-workflow'; -import type { Config } from '@/config'; +import { ILogger } from 'n8n-workflow'; +import { Config } from '@/config'; import { PasswordResetRequest } from '@/requests'; -import type { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; +import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; import { issueCookie } from '@/auth/jwt'; import { isLdapEnabled } from '@/Ldap/helpers'; import { isSamlCurrentAuthenticationMethod } from '@/sso/ssoHelpers'; @@ -30,50 +30,20 @@ import { RESPONSE_ERROR_MESSAGES } from '@/constants'; import { TokenExpiredError } from 'jsonwebtoken'; import type { JwtPayload } from '@/services/jwt.service'; import { JwtService } from '@/services/jwt.service'; -import type { MfaService } from '@/Mfa/mfa.service'; +import { MfaService } from '@/Mfa/mfa.service'; @RestController() export class PasswordResetController { - private readonly config: Config; - - private readonly logger: ILogger; - - private readonly externalHooks: IExternalHooksClass; - - private readonly internalHooks: IInternalHooksClass; - - private readonly mailer: UserManagementMailer; - - private readonly jwtService: JwtService; - - private readonly userService: UserService; - - private readonly mfaService: MfaService; - - constructor({ - config, - logger, - externalHooks, - internalHooks, - mailer, - mfaService, - }: { - config: Config; - logger: ILogger; - externalHooks: IExternalHooksClass; - internalHooks: IInternalHooksClass; - mailer: UserManagementMailer; - mfaService: MfaService; - }) { - this.config = config; - this.logger = logger; - this.externalHooks = externalHooks; - this.internalHooks = internalHooks; - this.mailer = mailer; - this.jwtService = Container.get(JwtService); - this.userService = Container.get(UserService); - this.mfaService = mfaService; - } + constructor( + private readonly config: Config, + private readonly logger: ILogger, + private readonly externalHooks: IExternalHooksClass, + private readonly internalHooks: IInternalHooksClass, + private readonly mailer: UserManagementMailer, + private readonly userService: UserService, + private readonly jwtService: JwtService, + private readonly mfaService: MfaService, + ) {} /** * Send a password reset email. diff --git a/packages/cli/src/controllers/users.controller.ts b/packages/cli/src/controllers/users.controller.ts index 1cbf352557..518a11d90b 100644 --- a/packages/cli/src/controllers/users.controller.ts +++ b/packages/cli/src/controllers/users.controller.ts @@ -1,7 +1,6 @@ import validator from 'validator'; import { In } from 'typeorm'; -import type { ILogger } from 'n8n-workflow'; -import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow'; +import { ILogger, ErrorReporterProxy as ErrorReporter } from 'n8n-workflow'; import { User } from '@db/entities/User'; import { SharedCredentials } from '@db/entities/SharedCredentials'; import { SharedWorkflow } from '@db/entities/SharedWorkflow'; @@ -24,21 +23,16 @@ import { UnauthorizedError, } from '@/ResponseHelper'; import { Response } from 'express'; -import type { Config } from '@/config'; +import { Config } from '@/config'; import { UserRequest, UserSettingsUpdatePayload } from '@/requests'; -import type { UserManagementMailer } from '@/UserManagement/email'; -import type { - PublicUser, - IDatabaseCollections, - IExternalHooksClass, - IInternalHooksClass, - ITelemetryUserDeletionData, -} from '@/Interfaces'; -import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; +import { UserManagementMailer } from '@/UserManagement/email'; +import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; +import type { PublicUser, ITelemetryUserDeletionData } from '@/Interfaces'; +import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import { AuthIdentity } from '@db/entities/AuthIdentity'; -import type { PostHogClient } from '@/posthog'; +import { PostHogClient } from '@/posthog'; import { isSamlLicensedAndEnabled } from '../sso/saml/samlHelpers'; -import type { SharedCredentialsRepository, SharedWorkflowRepository } from '@db/repositories'; +import { SharedCredentialsRepository, SharedWorkflowRepository } from '@db/repositories'; import { plainToInstance } from 'class-transformer'; import { License } from '@/License'; import { Container } from 'typedi'; @@ -50,62 +44,20 @@ import { UserService } from '@/services/user.service'; @Authorized(['global', 'owner']) @RestController('/users') export class UsersController { - private config: Config; - - private logger: ILogger; - - private externalHooks: IExternalHooksClass; - - private internalHooks: IInternalHooksClass; - - private sharedCredentialsRepository: SharedCredentialsRepository; - - private sharedWorkflowRepository: SharedWorkflowRepository; - - private activeWorkflowRunner: ActiveWorkflowRunner; - - private mailer: UserManagementMailer; - - private jwtService: JwtService; - - private postHog?: PostHogClient; - - private roleService: RoleService; - - private userService: UserService; - - constructor({ - config, - logger, - externalHooks, - internalHooks, - repositories, - activeWorkflowRunner, - mailer, - postHog, - }: { - config: Config; - logger: ILogger; - externalHooks: IExternalHooksClass; - internalHooks: IInternalHooksClass; - repositories: Pick; - activeWorkflowRunner: ActiveWorkflowRunner; - mailer: UserManagementMailer; - postHog?: PostHogClient; - }) { - this.config = config; - this.logger = logger; - this.externalHooks = externalHooks; - this.internalHooks = internalHooks; - this.sharedCredentialsRepository = repositories.SharedCredentials; - this.sharedWorkflowRepository = repositories.SharedWorkflow; - this.activeWorkflowRunner = activeWorkflowRunner; - this.mailer = mailer; - this.jwtService = Container.get(JwtService); - this.postHog = postHog; - this.roleService = Container.get(RoleService); - this.userService = Container.get(UserService); - } + constructor( + private readonly config: Config, + private readonly logger: ILogger, + private readonly externalHooks: IExternalHooksClass, + private readonly internalHooks: IInternalHooksClass, + private readonly sharedCredentialsRepository: SharedCredentialsRepository, + private readonly sharedWorkflowRepository: SharedWorkflowRepository, + private readonly activeWorkflowRunner: ActiveWorkflowRunner, + private readonly mailer: UserManagementMailer, + private readonly jwtService: JwtService, + private readonly roleService: RoleService, + private readonly userService: UserService, + private readonly postHog?: PostHogClient, + ) {} /** * Send email invite(s) to one or multiple users and create user shell(s). diff --git a/packages/cli/test/integration/shared/utils/testServer.ts b/packages/cli/test/integration/shared/utils/testServer.ts index 26fa2b81a0..b00273eb66 100644 --- a/packages/cli/test/integration/shared/utils/testServer.ts +++ b/packages/cli/test/integration/shared/utils/testServer.ts @@ -55,6 +55,14 @@ import { MfaService } from '@/Mfa/mfa.service'; import { TOTPService } from '@/Mfa/totp.service'; import { UserSettings } from 'n8n-core'; import { MetricsService } from '@/services/metrics.service'; +import { + SettingsRepository, + SharedCredentialsRepository, + SharedWorkflowRepository, +} from '@/databases/repositories'; +import { JwtService } from '@/services/jwt.service'; +import { RoleService } from '@/services/role.service'; +import { UserService } from '@/services/user.service'; /** * Plugin to prefix a path segment into a request URL pathname. @@ -189,6 +197,7 @@ export const setupTestServer = ({ const internalHooks = Container.get(InternalHooks); const mailer = Container.get(UserManagementMailer); const mfaService = new MfaService(repositories.User, new TOTPService(), encryptionKey); + const userService = Container.get(UserService); for (const group of functionEndpoints) { switch (group) { @@ -202,7 +211,7 @@ export const setupTestServer = ({ registerController( app, config, - new AuthController({ config, logger, internalHooks, repositories, mfaService }), + new AuthController(config, logger, internalHooks, mfaService, userService), ); break; case 'mfa': @@ -235,52 +244,55 @@ export const setupTestServer = ({ registerController( app, config, - new MeController({ - logger, - externalHooks, - internalHooks, - }), + new MeController(logger, externalHooks, internalHooks, userService), ); break; case 'passwordReset': registerController( app, config, - new PasswordResetController({ + new PasswordResetController( config, logger, externalHooks, internalHooks, mailer, + userService, + Container.get(JwtService), mfaService, - }), + ), ); break; case 'owner': registerController( app, config, - new OwnerController({ + new OwnerController( config, logger, internalHooks, - repositories, - }), + Container.get(SettingsRepository), + userService, + ), ); break; case 'users': registerController( app, config, - new UsersController({ + new UsersController( config, - mailer, + logger, externalHooks, internalHooks, - repositories, - activeWorkflowRunner: Container.get(ActiveWorkflowRunner), - logger, - }), + Container.get(SharedCredentialsRepository), + Container.get(SharedWorkflowRepository), + Container.get(ActiveWorkflowRunner), + mailer, + Container.get(JwtService), + Container.get(RoleService), + userService, + ), ); break; case 'tags': diff --git a/packages/cli/test/unit/controllers/me.controller.test.ts b/packages/cli/test/unit/controllers/me.controller.test.ts index 950957c12c..f45c2a1256 100644 --- a/packages/cli/test/unit/controllers/me.controller.test.ts +++ b/packages/cli/test/unit/controllers/me.controller.test.ts @@ -9,20 +9,14 @@ import { AUTH_COOKIE_NAME } from '@/constants'; import { BadRequestError } from '@/ResponseHelper'; import type { AuthenticatedRequest, MeRequest } from '@/requests'; import { badPasswords } from '../shared/testData'; -import { UserService } from '@/services/user.service'; -import Container from 'typedi'; +import type { UserService } from '@/services/user.service'; describe('MeController', () => { const logger = mock(); const externalHooks = mock(); const internalHooks = mock(); const userService = mock(); - Container.set(UserService, userService); - const controller = new MeController({ - logger, - externalHooks, - internalHooks, - }); + const controller = new MeController(logger, externalHooks, internalHooks, userService); describe('updateCurrentUser', () => { it('should throw BadRequestError if email is missing in the payload', async () => { diff --git a/packages/cli/test/unit/controllers/owner.controller.test.ts b/packages/cli/test/unit/controllers/owner.controller.test.ts index 5c48c1a1d3..ee9ca3ac0b 100644 --- a/packages/cli/test/unit/controllers/owner.controller.test.ts +++ b/packages/cli/test/unit/controllers/owner.controller.test.ts @@ -12,7 +12,6 @@ import { OwnerController } from '@/controllers'; import { badPasswords } from '../shared/testData'; import { AUTH_COOKIE_NAME } from '@/constants'; import { UserService } from '@/services/user.service'; -import Container from 'typedi'; import { mockInstance } from '../../integration/shared/utils'; describe('OwnerController', () => { @@ -20,16 +19,14 @@ describe('OwnerController', () => { const logger = mock(); const internalHooks = mock(); const userService = mockInstance(UserService); - Container.set(UserService, userService); const settingsRepository = mock(); - const controller = new OwnerController({ + const controller = new OwnerController( config, logger, internalHooks, - repositories: { - Settings: settingsRepository, - }, - }); + settingsRepository, + userService, + ); describe('setupOwner', () => { it('should throw a BadRequestError if the instance owner is already setup', async () => {