diff --git a/README.md b/README.md index ba2cc2f5..e18905d5 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,11 @@ The portal can run without any authentication infrastructure. Authentication con | Property name | Description | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | IDP_NAMES | Comma separated values of the name(s) of the Identity Providers (IDPs) used for authentication. | -| BASE*DOMAINS*${idp} | Comma separated values of base domains for the application. | -| AUTH*SERVER_URL*${idp} | The URL for the authentication service provider specific to the idp name. This URL is used for retrieveing an authenticating a user. | -| TOKEN*URL*${idp} | The URL for the authentication token service provider specific to the idp name. This URL is used for retrieveing an auth tokens. | -| OIDC*CLIENT_ID*${idp} | Client ID for the OpenID Connect (OIDC) configuration. The Client ID is used to identify the application to the OIDC provider (e.g., an authorization server). | -| OIDC*CLIENT_SECRET*${idp} | Client Secret for the OIDC configuration. The Client Secret is a confidential value known only to the application and the OIDC provider, used to authenticate the application to the provider. | +| BASE_DOMAINS_${idp} | Comma separated values of base domains for the application. | +| AUTH_SERVER_URL_${idp} | The URL for the authentication service provider specific to the idp name. This URL is used for retrieveing an authenticating a user. | +| TOKEN_URL_${idp} | The URL for the authentication token service provider specific to the idp name. This URL is used for retrieveing an auth tokens. | +| OIDC_CLIENT_ID_${idp} | Client ID for the OpenID Connect (OIDC) configuration. The Client ID is used to identify the application to the OIDC provider (e.g., an authorization server). | +| OIDC_CLIENT_SECRET_${idp} | Client Secret for the OIDC configuration. The Client Secret is a confidential value known only to the application and the OIDC provider, used to authenticate the application to the provider. | - **Optional** diff --git a/integration-tests/env.integration-spec.ts b/integration-tests/env.integration-spec.ts index faad2087..fc408977 100644 --- a/integration-tests/env.integration-spec.ts +++ b/integration-tests/env.integration-spec.ts @@ -18,7 +18,7 @@ describe('AppController (integration)', () => { beforeEach(async () => { const envVariablesProvider = { - getEnv: (hostname: string) => Promise.resolve(env), + getEnv: () => Promise.resolve(env), } as unknown as Type; const moduleFixture = await integrationTestModule({ @@ -34,10 +34,7 @@ describe('AppController (integration)', () => { }); it('/rest/envconfig (GET)', () => { - return request(app.getHttpServer()) - .get('/rest/envconfig') - .expect(200) - .expect(env); + return request(app.getHttpServer()).get('/rest/envconfig').expect(200); }); it('should implement integration-test', () => { diff --git a/integration-tests/integration-test-module.ts b/integration-tests/integration-test-module.ts index 9178cf5f..a72323cb 100644 --- a/integration-tests/integration-test-module.ts +++ b/integration-tests/integration-test-module.ts @@ -2,7 +2,7 @@ import { ENV_VARIABLES_PROVIDER_INJECTION_TOKEN, PortalModule, PortalModuleOptions, -} from '../src'; +} from '../src/index.js'; import { Test, TestingModuleBuilder } from '@nestjs/testing'; function integrationTestModule( diff --git a/package-lock.json b/package-lock.json index 063b712f..449a1b99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,10 +14,11 @@ "@nestjs/serve-static": "5.0.4", "axios": "1.13.2", "class-transformer": "0.5.1", - "class-validator": "0.14.2", + "class-validator": "0.14.3", "express": "5.1.0", "jwt-decode": "4.0.0", - "rxjs": "7.8.2" + "rxjs": "7.8.2", + "validator": ">=13.15.22" }, "devDependencies": { "@eslint/js": "9.38.0", @@ -4428,15 +4429,15 @@ "peer": true }, "node_modules/class-validator": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", - "integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==", + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", + "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", "license": "MIT", "peer": true, "dependencies": { - "@types/validator": "^13.11.8", + "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", - "validator": "^13.9.0" + "validator": "^13.15.20" } }, "node_modules/cli-cursor": { @@ -10454,9 +10455,9 @@ } }, "node_modules/validator": { - "version": "13.15.20", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.20.tgz", - "integrity": "sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==", + "version": "13.15.23", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", + "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", "license": "MIT", "engines": { "node": ">= 0.10" diff --git a/package.json b/package.json index d285cfc3..69a0c908 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "@nestjs/serve-static": "5.0.4", "axios": "1.13.2", "class-transformer": "0.5.1", - "class-validator": "0.14.2", + "class-validator": "0.14.3", + "validator": ">=13.15.22", "express": "5.1.0", "jwt-decode": "4.0.0", "rxjs": "7.8.2" diff --git a/src/auth/auth-config.service.ts b/src/auth/auth-config.service.ts index 476f0222..14552990 100644 --- a/src/auth/auth-config.service.ts +++ b/src/auth/auth-config.service.ts @@ -10,11 +10,11 @@ interface BaseDomainsToIdp { export interface ServerAuthVariables { idpName?: string; - baseDomain?: string; - oauthServerUrl?: string; - oauthTokenUrl?: string; - clientId?: string; - clientSecret?: string; + baseDomain: string; + oauthServerUrl: string; + oauthTokenUrl: string; + clientId: string; + clientSecret: string; oidcIssuerUrl?: string; endSessionUrl?: string; } @@ -28,7 +28,7 @@ export class EmptyAuthConfigService implements AuthConfigService { constructor() {} public async getAuthConfig(request: Request): Promise { - return {}; + return {} as ServerAuthVariables; } } @@ -72,9 +72,9 @@ export class EnvAuthConfigService implements AuthConfigService { continue; } - const env = this.envService.getEnv(); + const idpNames = this.envService.getIdpNames(); const subDomain = regExpExecArray[1]; - const subDomainIdpName = env.idpNames.includes(subDomain) + const subDomainIdpName = idpNames.includes(subDomain) ? subDomain : baseDomainToIdp.idpName; @@ -106,9 +106,9 @@ export class EnvAuthConfigService implements AuthConfigService { baseDomain: string, subDomainIdpName?: string, ): Promise { - const env = this.envService.getEnv(); + const idpNames = this.envService.getIdpNames(); - if (!env.idpNames.includes(idpName)) { + if (!idpNames.includes(idpName)) { throw new HttpException( { message: 'Identity provider not configured', diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts index 478636ee..e847953f 100644 --- a/src/auth/auth.controller.spec.ts +++ b/src/auth/auth.controller.spec.ts @@ -4,7 +4,10 @@ import { } from '../injection-tokens.js'; import { PortalModule } from '../portal.module.js'; import { CookiesService } from '../services/index.js'; -import { AuthConfigService } from './auth-config.service.js'; +import { + AuthConfigService, + ServerAuthVariables, +} from './auth-config.service.js'; import { AuthTokenData, AuthTokenService } from './auth-token.service.js'; import { AuthCallback } from './auth.callback.js'; import { AuthController } from './auth.controller.js'; @@ -57,7 +60,7 @@ describe('AuthController', () => { } as any; authConfigServicekMock.getAuthConfig.mockResolvedValue({ baseDomain: 'localhost', - }); + } as ServerAuthVariables); const authTokenResponse = { id_token: 'id', @@ -93,7 +96,7 @@ describe('AuthController', () => { } as any; authConfigServicekMock.getAuthConfig.mockResolvedValue({ baseDomain: 'otherdomain', - }); + } as ServerAuthVariables); const result = await controller.auth(requestMock, responseMock); diff --git a/src/config/context/entity-context-provider.ts b/src/config/context/entity-context-provider.ts index c95af574..29561475 100644 --- a/src/config/context/entity-context-provider.ts +++ b/src/config/context/entity-context-provider.ts @@ -3,7 +3,7 @@ import { Type } from '@nestjs/common'; export interface EntityContextProvider { getContextValues( token: string, - context?: Record, + context: Record, ): Promise>; } diff --git a/src/env/env-variables.service.spec.ts b/src/env/env-variables.service.spec.ts index 9bc3212c..4eed9502 100644 --- a/src/env/env-variables.service.spec.ts +++ b/src/env/env-variables.service.spec.ts @@ -1,127 +1,40 @@ -import { AuthConfigService, ServerAuthVariables } from '../auth/index.js'; -import { EnvVariablesServiceImpl } from './env-variables.service.js'; -import { EnvService } from './env.service.js'; +import { + EmptyVariablesService, + EnvConfigVariables, +} from './env-variables.service.js'; import type { Request, Response } from 'express'; -import { mock } from 'jest-mock-extended'; - -describe('EnvVariablesServiceImpl', () => { - let envVariablesService: EnvVariablesServiceImpl; - let envServiceMock: EnvService; - let authConfigServiceMock: jest.Mocked; - let mockRequest: Partial; - let mockResponse: Partial; - - const currentAuthEnv: ServerAuthVariables = { - oauthServerUrl: 'oauthServerUrl', - oauthTokenUrl: 'oauthTokenUrl', - oidcIssuerUrl: 'oidcIssuerUrl', - clientId: 'clientId', - idpName: 'idpName', - baseDomain: 'baseDomain', - clientSecret: 'clientSecret', - }; - - const env = { - validWebcomponentUrls: 'validWebcomponentUrls', - logoutRedirectUrl: 'logoutRedirectUrl', - isLocal: true, - developmentInstance: true, - uiOptions: 'uiOptions', - }; +describe('EmptyVariablesService', () => { + let service: EmptyVariablesService; beforeEach(() => { - envServiceMock = { - getEnv: jest.fn().mockReturnValue(env), - } as any; - - authConfigServiceMock = mock(); - authConfigServiceMock.getAuthConfig.mockResolvedValue(currentAuthEnv); - - envVariablesService = new EnvVariablesServiceImpl( - envServiceMock, - authConfigServiceMock, - ); - - mockRequest = {}; - mockResponse = {}; + service = new EmptyVariablesService(); }); - describe('getEnv', () => { - it('should return the result from authDataService.provideAuthData and current auth envs', async () => { - const result = await envVariablesService.getEnv( - mockRequest, - mockResponse, - ); - - expect(result).toEqual({ - idpName: 'idpName', - baseDomain: 'baseDomain', - oauthServerUrl: 'oauthServerUrl', - oauthTokenUrl: 'oauthTokenUrl', - oidcIssuerUrl: 'oidcIssuerUrl', - clientId: 'clientId', - validWebcomponentUrls: 'validWebcomponentUrls', - logoutRedirectUrl: 'logoutRedirectUrl', - isLocal: true, - developmentInstance: true, - uiOptions: 'uiOptions', - }); - }); - - it('should return a promise', () => { - const result = envVariablesService.getEnv(mockRequest, mockResponse); - expect(result).toBeInstanceOf(Promise); - }); - - it('should handle empty auth config values', async () => { - const emptyAuthConfig: ServerAuthVariables = {}; - authConfigServiceMock.getAuthConfig.mockResolvedValue(emptyAuthConfig); - - const result = await envVariablesService.getEnv( - mockRequest, - mockResponse, - ); - - expect(result).toEqual({ - idpName: undefined, - baseDomain: undefined, - oauthServerUrl: undefined, - oauthTokenUrl: undefined, - oidcIssuerUrl: undefined, - clientId: undefined, - validWebcomponentUrls: 'validWebcomponentUrls', - logoutRedirectUrl: 'logoutRedirectUrl', - isLocal: true, - developmentInstance: true, - uiOptions: 'uiOptions', - }); - }); + it('should be defined', () => { + expect(service).toBeDefined(); + }); - it('should handle partial auth config values', async () => { - const partialAuthConfig: ServerAuthVariables = { - idpName: 'test-idp', - baseDomain: 'test.com', - }; - authConfigServiceMock.getAuthConfig.mockResolvedValue(partialAuthConfig); + it('getEnv should return an object that matches EnvConfigVariables (empty)', async () => { + const req = {} as Request; + const res = {} as Response; + const result = await service.getEnv(req, res); + expect(result).toEqual({} as EnvConfigVariables); + expect(typeof result).toBe('object'); + }); - const result = await envVariablesService.getEnv( - mockRequest, - mockResponse, - ); + it('getEnv resolves to a Promise (async behavior)', () => { + const req = {} as Request; + const res = {} as Response; + const promise = service.getEnv(req, res); + expect(promise).toBeInstanceOf(Promise); + return expect(promise).resolves.toEqual({} as EnvConfigVariables); + }); - expect(result).toEqual({ - idpName: 'test-idp', - baseDomain: 'test.com', - oauthServerUrl: undefined, - oauthTokenUrl: undefined, - oidcIssuerUrl: undefined, - clientId: undefined, - validWebcomponentUrls: 'validWebcomponentUrls', - logoutRedirectUrl: 'logoutRedirectUrl', - isLocal: true, - developmentInstance: true, - uiOptions: 'uiOptions', - }); - }); + it('getEnv does not throw when request/response contain fields', async () => { + const req = { headers: { host: 'example.local' } } as unknown as Request; + const res = { status: () => res } as unknown as Response; + await expect(service.getEnv(req, res)).resolves.toEqual( + {} as EnvConfigVariables, + ); }); }); diff --git a/src/env/env-variables.service.ts b/src/env/env-variables.service.ts index f45f1116..c1f58725 100644 --- a/src/env/env-variables.service.ts +++ b/src/env/env-variables.service.ts @@ -1,63 +1,23 @@ -import { AuthConfigService } from '../auth/index.js'; -import { AUTH_CONFIG_INJECTION_TOKEN } from '../injection-tokens.js'; -import { EnvService, EnvVariables } from './env.service.js'; -import { Inject, Injectable } from '@nestjs/common'; +import { ServerAuthVariables } from '../auth/index.js'; +import { EnvVariables } from './env.service.js'; +import { Injectable } from '@nestjs/common'; import type { Request, Response } from 'express'; -export interface EnvConfigVariables extends EnvVariables { - idpName?: string; - baseDomain?: string; - oauthServerUrl?: string; - oauthTokenUrl?: string; - oidcIssuerUrl?: string; - clientId?: string; -} +export type EnvConfigVariables = ServerAuthVariables | EnvVariables; export interface EnvVariablesService { - getEnv: (request: Request, response: Response) => Promise; + getEnv: ( + request: Request, + response: Response, + ) => Promise>; } @Injectable() -export class EnvVariablesServiceImpl implements EnvVariablesService { - constructor( - private envService: EnvService, - @Inject(AUTH_CONFIG_INJECTION_TOKEN) - private authConfigService: AuthConfigService, - ) {} - +export class EmptyVariablesService implements EnvVariablesService { async getEnv( request: Request, _response: Response, - ): Promise { - const { - oauthServerUrl, - oauthTokenUrl, - oidcIssuerUrl, - clientId, - idpName, - baseDomain, - } = await this.authConfigService.getAuthConfig(request); - const { - validWebcomponentUrls, - logoutRedirectUrl, - isLocal, - developmentInstance, - uiOptions, - userAvatarUrl, - } = this.envService.getEnv(); - return { - idpName, - baseDomain, - oauthServerUrl, - oauthTokenUrl, - oidcIssuerUrl, - clientId, - validWebcomponentUrls, - logoutRedirectUrl, - isLocal, - developmentInstance, - uiOptions, - userAvatarUrl, - }; + ): Promise> { + return {}; } } diff --git a/src/env/env.controller.spec.ts b/src/env/env.controller.spec.ts index bbe328a2..bdd63ae2 100644 --- a/src/env/env.controller.spec.ts +++ b/src/env/env.controller.spec.ts @@ -1,55 +1,131 @@ -import { ENV_VARIABLES_PROVIDER_INJECTION_TOKEN } from '../injection-tokens.js'; +import { AuthConfigService, ServerAuthVariables } from '../auth/index.js'; import { - EnvConfigVariables, - EnvVariablesService, -} from './env-variables.service.js'; + AUTH_CONFIG_INJECTION_TOKEN, + ENV_VARIABLES_PROVIDER_INJECTION_TOKEN, +} from '../injection-tokens.js'; +import { EnvVariablesService } from './env-variables.service.js'; import { EnvController } from './env.controller.js'; +import { EnvService } from './env.service.js'; import { Test, TestingModule } from '@nestjs/testing'; import type { Request, Response } from 'express'; -import { MockProxy, mock } from 'jest-mock-extended'; describe('EnvController', () => { let controller: EnvController; - let envVariablesProvider: MockProxy; + let authConfigService: jest.Mocked; + let envVariablesProvider: jest.Mocked; + let envService: jest.Mocked; beforeEach(async () => { - envVariablesProvider = mock(); const module: TestingModule = await Test.createTestingModule({ controllers: [EnvController], providers: [ + { + provide: AUTH_CONFIG_INJECTION_TOKEN, + useValue: { + getAuthConfig: jest.fn(), + }, + }, { provide: ENV_VARIABLES_PROVIDER_INJECTION_TOKEN, - useValue: envVariablesProvider, + useValue: { + getEnv: jest.fn(), + }, + }, + { + provide: EnvService, + useValue: { + getEnv: jest.fn(), + }, }, ], }).compile(); + controller = module.get(EnvController); + authConfigService = module.get(AUTH_CONFIG_INJECTION_TOKEN); + envVariablesProvider = module.get(ENV_VARIABLES_PROVIDER_INJECTION_TOKEN); + envService = module.get(EnvService); }); it('should be defined', () => { - expect(true).toEqual(true); expect(controller).toBeDefined(); }); - describe('getEnv', function () { - const env = { - validWebcomponentUrls: ['ab', 'cd'], - developmentInstance: false, - isLocal: false, - idpNames: [], - } as EnvConfigVariables; + it('should merge env service, provider, and auth config values', async () => { + const req = {} as Request; + const res = {} as Response; - beforeEach(function () { - envVariablesProvider.getEnv.mockReturnValue(Promise.resolve(env)); + envService.getEnv.mockReturnValue({ + envA: 'a', + envB: 'b', + } as any); + + envVariablesProvider.getEnv.mockResolvedValue({ + customA: 'x', + customB: 'y', + } as any); + + authConfigService.getAuthConfig.mockResolvedValue({ + oauthServerUrl: 'srv', + oauthTokenUrl: 'token', + oidcIssuerUrl: 'issuer', + clientId: 'client', + clientSecret: 'clientSecret', + idpName: 'idp', + baseDomain: 'domain', }); - it('should get the env variables from the controller', async () => { - const requestMock = mock(); - const responseMock = mock(); + const result = await controller.getEnv(req, res); + + expect(envService.getEnv).toHaveBeenCalled(); + expect(envVariablesProvider.getEnv).toHaveBeenCalledWith(req, res); + expect(authConfigService.getAuthConfig).toHaveBeenCalledWith(req); + + expect(result).toEqual({ + baseDomain: 'domain', + idpName: 'idp', + envA: 'a', + envB: 'b', + customA: 'x', + customB: 'y', + oauthServerUrl: 'srv', + oidcIssuerUrl: 'issuer', + clientId: 'client', + }); + }); - const envVariables = await controller.getEnv(requestMock, responseMock); + it('should allow empty provider and env responses', async () => { + const req = {} as Request; + const res = {} as Response; - expect(envVariables).toMatchObject(env); + envService.getEnv.mockReturnValue({}); + envVariablesProvider.getEnv.mockResolvedValue({}); + authConfigService.getAuthConfig.mockResolvedValue({ + oauthServerUrl: undefined, + oauthTokenUrl: undefined, + oidcIssuerUrl: undefined, + clientId: undefined, + clientSecret: undefined, + idpName: undefined, + baseDomain: undefined, }); + + const result = await controller.getEnv(req, res); + + expect(result).toEqual({}); + }); + + it('should return a plain object', async () => { + const req = {} as Request; + const res = {} as Response; + + envService.getEnv.mockReturnValue({}); + envVariablesProvider.getEnv.mockResolvedValue({}); + authConfigService.getAuthConfig.mockResolvedValue( + {} as ServerAuthVariables, + ); + + const result = await controller.getEnv(req, res); + + expect(typeof result).toBe('object'); }); }); diff --git a/src/env/env.controller.ts b/src/env/env.controller.ts index f3b578b7..51807983 100644 --- a/src/env/env.controller.ts +++ b/src/env/env.controller.ts @@ -1,8 +1,13 @@ -import { ENV_VARIABLES_PROVIDER_INJECTION_TOKEN } from '../injection-tokens.js'; +import { AuthConfigService } from '../auth/index.js'; +import { + AUTH_CONFIG_INJECTION_TOKEN, + ENV_VARIABLES_PROVIDER_INJECTION_TOKEN, +} from '../injection-tokens.js'; import { EnvConfigVariables, EnvVariablesService, } from './env-variables.service.js'; +import { EnvService } from './env.service.js'; import { Controller, Get, Inject, Req, Res } from '@nestjs/common'; import type { Request, Response } from 'express'; @@ -11,6 +16,9 @@ export class EnvController { constructor( @Inject(ENV_VARIABLES_PROVIDER_INJECTION_TOKEN) private envVariablesProvider: EnvVariablesService, + @Inject(AUTH_CONFIG_INJECTION_TOKEN) + private authConfigService: AuthConfigService, + private envService: EnvService, ) {} @Get() @@ -18,6 +26,16 @@ export class EnvController { @Req() request: Request, @Res({ passthrough: true }) response: Response, ): Promise { - return this.envVariablesProvider.getEnv(request, response); + const { oauthServerUrl, oidcIssuerUrl, clientId, idpName, baseDomain } = + await this.authConfigService.getAuthConfig(request); + return { + ...this.envService.getEnv(), + ...(await this.envVariablesProvider.getEnv(request, response)), + oauthServerUrl, + oidcIssuerUrl, + clientId, + idpName, + baseDomain, + }; } } diff --git a/src/env/env.service.spec.ts b/src/env/env.service.spec.ts index 740dc711..e4c2652c 100644 --- a/src/env/env.service.spec.ts +++ b/src/env/env.service.spec.ts @@ -62,7 +62,7 @@ describe('EnvService', () => { process.env[envVarName] = value; } - expect(service.getEnv()[resultName]).toStrictEqual(expected); + expect(service.getHealthCheckInterval()).toStrictEqual(expected); delete process.env[envVarName]; }); @@ -95,7 +95,7 @@ describe('EnvService', () => { it('should the idp names', () => { process.env['IDP_NAMES'] = 'a,b.c,d'; - expect(service.getEnv().idpNames).toEqual(['a', 'b.c', 'd']); + expect(service.getIdpNames()).toEqual(['a', 'b.c', 'd']); delete process.env['IDP_NAMES']; }); diff --git a/src/env/env.service.ts b/src/env/env.service.ts index c9dfce67..3ae7a19a 100644 --- a/src/env/env.service.ts +++ b/src/env/env.service.ts @@ -1,10 +1,6 @@ import { Injectable } from '@nestjs/common'; -export interface EnvVariables extends Record { - idpNames?: string[]; - oauthServerUrl?: string; - oauthTokenUrl?: string; - clientId?: string; +export interface EnvVariables { logoutRedirectUrl?: string; healthCheckInterval?: number; isLocal?: boolean; @@ -20,8 +16,6 @@ export class EnvService { public getEnv(): EnvVariables { return { - idpNames: this.getIdpNames(), - healthCheckInterval: parseInt(process.env.HEALTH_CHECK_INTERVAL, 10), userAvatarUrl: process.env.USER_AVATAR_URL || '', logoutRedirectUrl: process.env.LOGOUT_REDIRECT_URL || '/logout', isLocal: process.env.ENVIRONMENT === 'local', @@ -47,6 +41,10 @@ export class EnvService { return result; } + public getHealthCheckInterval() { + return parseInt(process.env.HEALTH_CHECK_INTERVAL, 10); + } + public getIdpNames(): Array { const idpNames = process.env.IDP_NAMES || ''; return idpNames.split(',').filter(Boolean); diff --git a/src/health/health.controller.ts b/src/health/health.controller.ts index 4f81d038..cf0a186f 100644 --- a/src/health/health.controller.ts +++ b/src/health/health.controller.ts @@ -1,4 +1,4 @@ -import { EnvService } from '../env/env.service.js'; +import { EnvService } from '../env/index.js'; import { HEALTH_CHECKER_INJECTION_TOKEN } from '../injection-tokens.js'; import { HealthChecker } from './health-checker.js'; import { Controller, Get, Inject, Logger } from '@nestjs/common'; @@ -17,8 +17,7 @@ export class HealthController { private healthChecker: HealthChecker, ) { this.isHealthy = false; - this.healthCheckInterval = - this.envService.getEnv().healthCheckInterval || 2000; + this.healthCheckInterval = this.envService.getHealthCheckInterval() || 2000; this.isInitialized = false; } diff --git a/src/logout/logout-callback.ts b/src/logout/logout-callback.ts index 6401454b..3058d1d5 100644 --- a/src/logout/logout-callback.ts +++ b/src/logout/logout-callback.ts @@ -1,5 +1,5 @@ import type { Request, Response } from 'express'; export interface LogoutCallback { - handleLogout(request: Request, response: Response): Promise; + handleLogout(request: Request, response: Response): Promise; } diff --git a/src/portal.module.ts b/src/portal.module.ts index 3ca1befd..c3a50ec3 100644 --- a/src/portal.module.ts +++ b/src/portal.module.ts @@ -27,10 +27,10 @@ import { NodeExtendedDataService } from './config/luigi/luigi-data/node-extended import { TextsTranslateService } from './config/luigi/luigi-data/texts-translate.service.js'; import { DiscoveryService, + EmptyVariablesService, EnvController, EnvService, EnvVariablesService, - EnvVariablesServiceImpl, } from './env/index.js'; import { EmptyHealthChecker, @@ -83,7 +83,7 @@ export interface PortalModuleOptions { additionalProviders?: Provider[]; /** - * Will be called to determine the heath of the application. If there is a rejected promise, or false is returned, the + * Will be called to determine the health of the application. If there is a rejected promise, or false is returned, the * health is not successful */ healthChecker?: Type; @@ -93,15 +93,9 @@ export interface PortalModuleOptions { */ envVariablesProvider?: Type; - /** - * Will be called to execute additional logic, when a user is logged out. - * The portal will take care of clearing the authentication cookie and the redirection logic during the logout process. - */ - logoutCallbackProvider?: Type; - /** * Makes it possible to extend the luigi context of every luigi node with contextValues - * The values will be available in the context under the property 'frameContext' + * The values will be available in the context under the property 'portalContext' */ portalContextProvider?: Type; @@ -144,6 +138,12 @@ export interface PortalModuleOptions { * Auth config variables provider service. */ authConfigProvider?: Type; + + /** + * Will be called to execute additional logic, when a user is logged out. + * The portal will take care of clearing the authentication cookie and the redirection logic during the logout process. + */ + logoutCallbackProvider?: Type; } @Module({}) @@ -192,7 +192,7 @@ export class PortalModule implements NestModule { }, { provide: ENV_VARIABLES_PROVIDER_INJECTION_TOKEN, - useClass: options.envVariablesProvider || EnvVariablesServiceImpl, + useClass: options.envVariablesProvider || EmptyVariablesService, }, { provide: LOGOUT_CALLBACK_INJECTION_TOKEN,