From df9cb8914a3acccc21c6bdc0e11bdc889eda234a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:06:22 +0000 Subject: [PATCH 1/7] chore(deps-dev): bump typescript from 5.9.3 to 6.0.3 in /back Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 6.0.3. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.3...v6.0.3) --- updated-dependencies: - dependency-name: typescript dependency-version: 6.0.3 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- back/package.json | 2 +- back/yarn.lock | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/back/package.json b/back/package.json index 8e666b397..41665498a 100644 --- a/back/package.json +++ b/back/package.json @@ -102,7 +102,7 @@ "ts-node": "^10.9.1", "tsconfig-paths": "4.2.0", "tsx": "^4.22.4", - "typescript": "^5.9.3", + "typescript": "^6.0.3", "webpack-stats-plugin": "^1.1.3" }, "engines": { diff --git a/back/yarn.lock b/back/yarn.lock index 43c6c8c59..bb39bae6c 100644 --- a/back/yarn.lock +++ b/back/yarn.lock @@ -6285,11 +6285,16 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@5.9.3, typescript@^5.9.3: +typescript@5.9.3: version "5.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== +typescript@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" + integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== + uglify-js@^3.1.4: version "3.19.3" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" From 44ef66e3e73952af351aa0945c567013180d2639 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 15:32:23 +0200 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20back:=20add=20truth?= =?UTF-8?q?ful=20type=20overloads=20to=20ConfigParser=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem** TS6 strict mode flags lying return types in ConfigParser: string() could return undefined but declared `string`, callers masked it with `as string`/`as boolean`/`as number` casts that hid real type unsafety across all config files. **Proposal** Add proper overloads so single-arg calls (`string(path)`, `boolean(path)`, `number(path)`) return the truthful required type and throw on missing/invalid values. Two-arg calls with `undefinedIfEmpty: true` return `string | undefined` for optional config values. Remove lying casts from all core-fca-low config files. --- .../core-fca-low/src/config/api-entreprise.ts | 2 +- back/apps/core-fca-low/src/config/app.ts | 11 +++-- .../src/config/hyyyperbridge-broker.ts | 2 +- back/apps/core-fca-low/src/config/mongoose.ts | 6 +-- .../core-fca-low/src/config/oidc-client.ts | 2 +- .../core-fca-low/src/config/oidc-provider.ts | 2 +- back/apps/core-fca-low/src/config/redis.ts | 10 ++--- .../src/controllers/health.controller.ts | 4 +- back/apps/core-fca-low/src/main.ts | 12 +++--- .../config/src/helpers/config-parser.spec.ts | 40 ++++++++++++++++--- back/libs/config/src/helpers/config-parser.ts | 35 +++++++++++----- back/package.json | 1 + back/yarn.lock | 5 +++ 13 files changed, 93 insertions(+), 39 deletions(-) diff --git a/back/apps/core-fca-low/src/config/api-entreprise.ts b/back/apps/core-fca-low/src/config/api-entreprise.ts index 4d82c0465..56bd3c9a3 100644 --- a/back/apps/core-fca-low/src/config/api-entreprise.ts +++ b/back/apps/core-fca-low/src/config/api-entreprise.ts @@ -6,7 +6,7 @@ const env = new ConfigParser(process.env, "ApiEntreprise"); const apiEntrepriseConfig: ApiEntrepriseConfig = { token: env.string("API_TOKEN"), baseUrl: env.string("API_BASE_URL"), - shouldMockApi: env.boolean("SHOULD_MOCK_API") || false, + shouldMockApi: env.boolean("SHOULD_MOCK_API", true) ?? false, featureFetchOrganizationData: env.boolean("FEATURE_FETCH_ORGANIZATION_DATA"), organizationSiret: "13002526500013", cachedTTL: 86400000, // 24h diff --git a/back/apps/core-fca-low/src/config/app.ts b/back/apps/core-fca-low/src/config/app.ts index 868ac29fc..d27dd0368 100644 --- a/back/apps/core-fca-low/src/config/app.ts +++ b/back/apps/core-fca-low/src/config/app.ts @@ -8,13 +8,13 @@ const appConfig: AppConfig = { urlPrefix: "/api/v2", assetsPaths: env.json("ASSETS_PATHS"), assetsDsfrPaths: env.json("DSFR_ASSETS_PATHS"), - assetsCacheTtl: env.number("ASSETS_CACHE_TTL"), + assetsCacheTtl: env.number("ASSETS_CACHE_TTL", true), viewsPaths: env.json("VIEWS_PATHS"), httpsOptions: { key: env.file("HTTPS_SERVER_KEY", true), cert: env.file("HTTPS_SERVER_CERT", true), }, - fqdn: process.env.FQDN, + fqdn: process.env.FQDN as string, defaultIdpId: env.string("DEFAULT_IDP_UID"), spAuthorizedFqdnsConfigs: env.json("SP_AUTHORIZED_FQDNS_CONFIGS"), defaultEmailRenater: env.string("DEFAULT_EMAIL_RENATER"), @@ -47,8 +47,11 @@ const appConfig: AppConfig = { "wss://client.relay.crisp.chat", ], }, - displayTestEnvWarning: env.boolean("FEATURE_DISPLAY_TEST_ENV_WARNING"), - displayMaintenanceNotice: env.boolean("FEATURE_DISPLAY_MAINTENANCE_NOTICE"), + displayTestEnvWarning: env.boolean("FEATURE_DISPLAY_TEST_ENV_WARNING", true), + displayMaintenanceNotice: env.boolean( + "FEATURE_DISPLAY_MAINTENANCE_NOTICE", + true, + ), maintenanceDatetime: env.string("MAINTENANCE_DATETIME"), maintenanceDuration: env.string("MAINTENANCE_DURATION"), defaultRedirectUri: "https://www.proconnect.gouv.fr", diff --git a/back/apps/core-fca-low/src/config/hyyyperbridge-broker.ts b/back/apps/core-fca-low/src/config/hyyyperbridge-broker.ts index 7916863ef..f2a73f079 100644 --- a/back/apps/core-fca-low/src/config/hyyyperbridge-broker.ts +++ b/back/apps/core-fca-low/src/config/hyyyperbridge-broker.ts @@ -8,7 +8,7 @@ const hyyyperbridgeBrokerConfig: RabbitmqConfig = { queue: env.string("QUEUE"), queueOptions: { durable: true }, // Global request timeout used for any outgoing app requests. - requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10), + requestTimeout: parseInt(process.env.REQUEST_TIMEOUT as string, 10), urls: env.json("URLS"), }; diff --git a/back/apps/core-fca-low/src/config/mongoose.ts b/back/apps/core-fca-low/src/config/mongoose.ts index a7c62ce8f..4065ad009 100644 --- a/back/apps/core-fca-low/src/config/mongoose.ts +++ b/back/apps/core-fca-low/src/config/mongoose.ts @@ -10,10 +10,10 @@ const mongooseConfig: MongooseConfig = { database: env.string("DATABASE"), options: { authSource: env.string("DATABASE"), - tls: env.boolean("TLS"), - tlsAllowInvalidCertificates: env.boolean("TLS_INSECURE"), + tls: env.boolean("TLS", true), + tlsAllowInvalidCertificates: env.boolean("TLS_INSECURE", true), tlsCAFile: env.string("TLS_CA_FILE", true), - tlsAllowInvalidHostnames: env.boolean("TLS_ALLOW_INVALID_HOST_NAME"), + tlsAllowInvalidHostnames: env.boolean("TLS_ALLOW_INVALID_HOST_NAME", true), }, watcherDebounceWaitDuration: env.number("WATCHER_DEBOUNCE_WAIT_DURATION", true) ?? 1_000, diff --git a/back/apps/core-fca-low/src/config/oidc-client.ts b/back/apps/core-fca-low/src/config/oidc-client.ts index e2f9fd810..d5ed443a8 100644 --- a/back/apps/core-fca-low/src/config/oidc-client.ts +++ b/back/apps/core-fca-low/src/config/oidc-client.ts @@ -10,7 +10,7 @@ const oidcClientConfig: OidcClientConfig = { // This duration is in seconds and is typically set to 6000 in most environments, // which equals 100 minutes. // This value is unusually high and should be reassessed in the future. - timeout: parseInt(process.env.REQUEST_TIMEOUT, 10), + timeout: parseInt(process.env.REQUEST_TIMEOUT as string, 10), // This value is not used in the current implementation. jwks: { keys: env.json("CRYPTO_ENC_LOCALE_PRIV_KEYS"), diff --git a/back/apps/core-fca-low/src/config/oidc-provider.ts b/back/apps/core-fca-low/src/config/oidc-provider.ts index 964696df3..f0ed3d6d0 100644 --- a/back/apps/core-fca-low/src/config/oidc-provider.ts +++ b/back/apps/core-fca-low/src/config/oidc-provider.ts @@ -60,7 +60,7 @@ const oidcProviderConfig: OidcProviderConfig = { "https://proconnect.gouv.fr/assurance/certification-dirigeant", ], // Global request timeout used for any outgoing app requests. - timeout: parseInt(process.env.REQUEST_TIMEOUT, 10), + timeout: parseInt(process.env.REQUEST_TIMEOUT as string, 10), }; export default oidcProviderConfig; diff --git a/back/apps/core-fca-low/src/config/redis.ts b/back/apps/core-fca-low/src/config/redis.ts index 840ba3853..755b4f1a6 100644 --- a/back/apps/core-fca-low/src/config/redis.ts +++ b/back/apps/core-fca-low/src/config/redis.ts @@ -14,13 +14,13 @@ const sentinels = env.stringArray("SENTINELS").map((entry) => { const useSentinels = sentinels.length > 0; const redisConfig: RedisConfig = { - host: useSentinels ? undefined : env.string("HOST"), - port: useSentinels ? undefined : env.number("PORT"), + host: (useSentinels ? undefined : env.string("HOST")) as string, + port: (useSentinels ? undefined : env.number("PORT")) as number, password: env.string("PASSWORD"), db: env.number("DB"), - sentinels: useSentinels ? sentinels : undefined, - name: useSentinels ? env.string("NAME") : undefined, - sentinelPassword: env.string("SENTINEL_PASSWORD", true), + sentinels: (useSentinels ? sentinels : undefined) as RedisConfig["sentinels"], + name: (useSentinels ? env.string("NAME") : undefined) as string, + sentinelPassword: env.string("SENTINEL_PASSWORD", true) as string, sentinelTLS: tlsSettings, tls: tlsSettings, enableTLSForSentinelMode: env.boolean("ENABLE_TLS_FOR_SENTINEL_MODE"), diff --git a/back/apps/core-fca-low/src/controllers/health.controller.ts b/back/apps/core-fca-low/src/controllers/health.controller.ts index e56ae8895..0458b4f56 100644 --- a/back/apps/core-fca-low/src/controllers/health.controller.ts +++ b/back/apps/core-fca-low/src/controllers/health.controller.ts @@ -124,13 +124,13 @@ export class HealthController { if (excludeSet.has(name)) { return { name, status: "excluded" }; } - return this.runCheck(name); + return this.runCheck(name as CheckTarget); }), ); } private async runCheck( - name: string, + name: CheckTarget, ): Promise { try { await this.checks[name](); diff --git a/back/apps/core-fca-low/src/main.ts b/back/apps/core-fca-low/src/main.ts index 9d6391d91..efdd7646d 100644 --- a/back/apps/core-fca-low/src/main.ts +++ b/back/apps/core-fca-low/src/main.ts @@ -38,7 +38,7 @@ async function bootstrap() { const appModule = AppModule.forRoot(configService); - const httpsOptions = key && cert ? { key, cert } : null; + const httpsOptions = key && cert ? { key, cert } : undefined; const app = await NestFactory.create(appModule, { /** @@ -110,7 +110,7 @@ async function bootstrap() { app.setViewEngine("ejs"); app.set( "views", - viewsPaths.map((viewsPath) => { + viewsPaths!.map((viewsPath) => { return join(__dirname, viewsPath, "views"); }), ); @@ -121,16 +121,16 @@ async function bootstrap() { * @TODO #1203 All below useStaticAssets functions need to be removed (until line 146) when webpack has been configured to load assets from @gouvfr/dsfr package * @ticket FC-1203 */ - assetsDsfrPaths.forEach(({ assetPath, prefix }) => { + assetsDsfrPaths!.forEach(({ assetPath, prefix }) => { app.useStaticAssets(join(__dirname, assetPath), { - maxAge: assetsCacheTtl * 1000, + maxAge: assetsCacheTtl! * 1000, prefix, }); }); - assetsPaths.forEach((assetsPath) => { + assetsPaths!.forEach((assetsPath) => { app.useStaticAssets(join(__dirname, assetsPath, "public"), { - maxAge: assetsCacheTtl * 1000, + maxAge: assetsCacheTtl! * 1000, }); }); diff --git a/back/libs/config/src/helpers/config-parser.spec.ts b/back/libs/config/src/helpers/config-parser.spec.ts index efba045aa..5aeca594e 100644 --- a/back/libs/config/src/helpers/config-parser.spec.ts +++ b/back/libs/config/src/helpers/config-parser.spec.ts @@ -101,6 +101,26 @@ describe("ConfigParser", () => { // Then expect(result).toBe(parseBooleanMockReturnValue); }); + + it("should throw if parseBoolean returns undefined", () => { + // Given + const path = "baz"; + parseBooleanMock.mockReturnValue(undefined); + // Then + expect(() => reader.boolean(path)).toThrow( + 'Config "someprefix/baz" is not a valid boolean (true/false expected)', + ); + }); + + it("should return undefined if undefinedIfEmpty is true and parseBoolean returns undefined", () => { + // Given + const path = "baz"; + parseBooleanMock.mockReturnValue(undefined); + // When + const result = reader.boolean(path, true); + // Then + expect(result).toBe(undefined); + }); }); describe("json", () => { @@ -159,13 +179,13 @@ describe("ConfigParser", () => { expect(result).toBe("bar"); }); - it("should return empty string if undefinedIfEmpty is false", () => { + it("should throw if value is empty", () => { // Given const path = "emptyString"; - // When - const result = reader.string(path, false); // Then - expect(result).toBe(""); + expect(() => reader.string(path)).toThrow( + 'Config "someprefix/emptyString" is required but empty or missing', + ); }); it("should return undefined if undefinedIfEmpty is true", () => { @@ -217,7 +237,17 @@ describe("ConfigParser", () => { expect(typeof result).toBe("number"); expect(result).toBe(42); }); - it("should return undefined", () => { + + it("should throw if value is empty", () => { + // Given + const path = "emptyString"; + // Then + expect(() => reader.number(path)).toThrow( + 'Config "someprefix/emptyString" is required but empty or missing', + ); + }); + + it("should return undefined if undefinedIfEmpty is true and value is empty", () => { // Given const path = "emptyString"; // When diff --git a/back/libs/config/src/helpers/config-parser.ts b/back/libs/config/src/helpers/config-parser.ts index a2eceecdb..8b7dbfe85 100644 --- a/back/libs/config/src/helpers/config-parser.ts +++ b/back/libs/config/src/helpers/config-parser.ts @@ -18,9 +18,18 @@ export class ConfigParser { return this.source.hasOwnProperty(fullPath); } - boolean(path: string): boolean | undefined { + boolean(path: string): boolean; + boolean(path: string, undefinedIfEmpty: true): boolean | undefined; + boolean(path: string, undefinedIfEmpty = false): boolean | undefined { const fullPath = this.getFullPath(path); - return parseBoolean(this.source[fullPath]); + const value = parseBoolean(this.source[fullPath]); + if (value === undefined) { + if (undefinedIfEmpty) return undefined; + throw new Error( + `Config "${fullPath}" is not a valid boolean (true/false expected)`, + ); + } + return value; } json(path: string): any { @@ -31,13 +40,16 @@ export class ConfigParser { return parseJsonProperty(this.source, fullPath); } - string(path: string, undefinedIfEmpty: boolean = false): string | undefined { + string(path: string): string; + string(path: string, undefinedIfEmpty: boolean): string | undefined; + string(path: string, undefinedIfEmpty = false): string | undefined { const fullPath = this.getFullPath(path); const value = this.source[fullPath]; - if (undefinedIfEmpty && isEmpty(value)) { - return undefined; + if (isEmpty(value)) { + if (undefinedIfEmpty) return undefined; + throw new Error(`Config "${fullPath}" is required but empty or missing`); } - return value; + return String(value); } stringArray(path: string): string[] { @@ -45,16 +57,19 @@ export class ConfigParser { return parsedString?.split(",") || []; } - number(path: string, undefinedIfEmpty: boolean = false): number { + number(path: string): number; + number(path: string, undefinedIfEmpty: true): number | undefined; + number(path: string, undefinedIfEmpty = false): number | undefined { const fullPath = this.getFullPath(path); const value = this.source[fullPath]; - if (undefinedIfEmpty && isEmpty(value)) { - return undefined; + if (isEmpty(value)) { + if (undefinedIfEmpty) return undefined; + throw new Error(`Config "${fullPath}" is required but empty or missing`); } return parseInt(this.source[fullPath], 10); } - file(path: string, undefinedIfEmpty: boolean = false): string { + file(path: string, undefinedIfEmpty: boolean = false): string | undefined { const fullPath = this.getFullPath(path); const filePath = this.source[fullPath]; diff --git a/back/package.json b/back/package.json index 41665498a..39d34f724 100644 --- a/back/package.json +++ b/back/package.json @@ -83,6 +83,7 @@ "devDependencies": { "@nestjs/cli": "^11.0.23", "@nestjs/testing": "^10.4.22", + "@types/cookie-parser": "^1.4.10", "@types/deep-freeze": "^0.1.2", "@types/express": "^5.0.6", "@types/express-session": "^1.19.0", diff --git a/back/yarn.lock b/back/yarn.lock index bb39bae6c..358c5a906 100644 --- a/back/yarn.lock +++ b/back/yarn.lock @@ -1543,6 +1543,11 @@ resolved "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.8.tgz" integrity sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg== +"@types/cookie-parser@^1.4.10": + version "1.4.10" + resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.10.tgz#a045272a383a30597a01955d4f9c790018f214e4" + integrity sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg== + "@types/cookies@*": version "0.9.0" resolved "https://registry.npmjs.org/@types/cookies/-/cookies-0.9.0.tgz" From 448353571b4aa21efda8dcf228ef4c2dd88e1010 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 16:06:37 +0200 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=90=9B=20(back/core-fca-low):=20type?= =?UTF-8?q?=20oidc-provider=20controller=20params=20with=20Request/Respons?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace untyped @Req() req and @Res() res with properly typed @Req() req: Request / @Res() res: Response from express. Also fix two type bugs revealed by proper typing: - URLSearchParams req.query cast - res.redirect null assertion for getEndSessionUrl --- .../src/controllers/interaction.controller.ts | 8 ++-- .../src/controllers/oidc-client.controller.ts | 8 ++-- .../controllers/oidc-provider.controller.ts | 45 ++++++++++++------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/back/apps/core-fca-low/src/controllers/interaction.controller.ts b/back/apps/core-fca-low/src/controllers/interaction.controller.ts index a8f6bf2c2..e8242785c 100644 --- a/back/apps/core-fca-low/src/controllers/interaction.controller.ts +++ b/back/apps/core-fca-low/src/controllers/interaction.controller.ts @@ -58,7 +58,7 @@ export class InteractionController { @Get(Routes.DEFAULT) @Header("cache-control", "no-store") - getDefault(@Res() res) { + getDefault(@Res() res: Response) { const { defaultRedirectUri } = this.config.get("App"); res.redirect(301, defaultRedirectUri); } @@ -120,7 +120,7 @@ export class InteractionController { const { acrClaims } = this.oidcAcr.getFilteredAcrParamsFromInteraction(interaction); const spEssentialAcr = - acrClaims?.value || acrClaims?.values.join(" ") || null; + acrClaims?.value || acrClaims?.values?.join(" ") || null; if (!canReuseActiveSession) { userSession.clear(); @@ -129,7 +129,7 @@ export class InteractionController { spLoginHint, spSiretHint, interactionId, - spEssentialAcr, + spEssentialAcr: spEssentialAcr ?? undefined, spId, spName, spState, @@ -222,7 +222,7 @@ export class InteractionController { isSilentAuthentication, spEssentialAcr, spId, - } = userSessionService.get(); + } = userSessionService.get()!; const account = await this.accountService.getAccountBySub(sub); if (!account || !account.active) { diff --git a/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts b/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts index ab6c41d96..f93dd969a 100644 --- a/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts +++ b/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts @@ -57,7 +57,7 @@ export class OidcClientController { @UserSessionDecorator(AfterRedirectToIdpWithEmailSessionDto) userSession: ISessionService, ) { - const { idpLoginHint: email } = userSession.get(); + const { idpLoginHint: email } = userSession.get()!; const identityProviders = await this.coreFcaService.selectIdpsFromEmail(email); @@ -130,10 +130,10 @@ export class OidcClientController { await userSession.duplicate(); const { idpId, idpNonce, idpState, interactionId, spId, spName } = - userSession.get(); + userSession.get()!; // Remove nonce and state from the session to prevent replay attacks - userSession.set({ idpNonce: null, idpState: null }); + userSession.set({ idpNonce: undefined, idpState: undefined }); this.logger.track(TrackedEvent.IDP_CALLEDBACK); @@ -186,7 +186,7 @@ export class OidcClientController { idpIdentity, idpId, account.sub, - claims.acr, + claims.acr as string, ); userSession.set({ diff --git a/back/apps/core-fca-low/src/controllers/oidc-provider.controller.ts b/back/apps/core-fca-low/src/controllers/oidc-provider.controller.ts index 82123e2e0..a25478860 100644 --- a/back/apps/core-fca-low/src/controllers/oidc-provider.controller.ts +++ b/back/apps/core-fca-low/src/controllers/oidc-provider.controller.ts @@ -19,6 +19,7 @@ import { } from "@nestjs/common"; import { plainToInstance } from "class-transformer"; import { validate } from "class-validator"; +import type { Request, Response } from "express"; import { isEmpty } from "lodash"; import { UserSessionDecorator } from "../decorators"; import { @@ -50,7 +51,11 @@ export class OidcProviderController { whitelist: true, }), ) - getAuthorize(@Req() req, @Res() res, @Query() _query: AuthorizeParamsDto) { + getAuthorize( + @Req() req: Request, + @Res() res: Response, + @Query() _query: AuthorizeParamsDto, + ) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @@ -65,20 +70,24 @@ export class OidcProviderController { validationError: { target: true }, }), ) - postAuthorize(@Req() req, @Res() res, @Body() _body: AuthorizeParamsDto) { + postAuthorize( + @Req() req: Request, + @Res() res: Response, + @Body() _body: AuthorizeParamsDto, + ) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Get(OidcProviderRoutes.AUTHORIZATION_RESUME) - getAuthorizeResume(@Req() req, @Res() res) { + getAuthorizeResume(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Post(OidcProviderRoutes.TOKEN) @Header("Content-Type", "application/json") - postToken(@Req() req, @Res() res) { + postToken(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @@ -90,20 +99,24 @@ export class OidcProviderController { whitelist: true, }), ) - revokeToken(@Req() req, @Res() res, @Body() _body: RevocationTokenParamsDTO) { + revokeToken( + @Req() req: Request, + @Res() res: Response, + @Body() _body: RevocationTokenParamsDTO, + ) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Get(OidcProviderRoutes.USERINFO) @Header("Content-Type", "application/jwt") - getUserInfo(@Req() req, @Res() res) { + getUserInfo(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Post(OidcProviderRoutes.USERINFO) - postUserInfo(@Req() req, @Res() res) { + postUserInfo(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @@ -115,8 +128,8 @@ export class OidcProviderController { }), ) async getEndSession( - @Req() req, - @Res() res, + @Req() req: Request, + @Res() res: Response, @Query() _query: LogoutParamsDto, @UserSessionDecorator() userSession: ISessionService, ) { @@ -144,11 +157,11 @@ export class OidcProviderController { userSession.set({ orginalLogoutUrlSearchParamsFromSp: new URLSearchParams( - req.query, + req.query as Record, ).toString(), }); - return res.redirect(endSessionUrl); + return res.redirect(endSessionUrl!); } } @@ -161,13 +174,13 @@ export class OidcProviderController { } @Post(OidcProviderRoutes.END_SESSION_CONFIRM) - postEndSessionConfirm(@Req() req, @Res() res) { + postEndSessionConfirm(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Get(OidcProviderRoutes.END_SESSION_SUCCESS) - getEndSessionSuccess(@Req() req, @Res() res) { + getEndSessionSuccess(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @@ -175,20 +188,20 @@ export class OidcProviderController { @Get(OidcProviderRoutes.JWKS) @Header("Content-Type", "application/jwk-set+json") @Header("cache-control", "public, max-age=600") - getJwks(@Req() req, @Res() res) { + getJwks(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Get(OidcProviderRoutes.OPENID_CONFIGURATION) @Header("cache-control", "public, max-age=600") - getOpenidConfiguration(@Req() req, @Res() res) { + getOpenidConfiguration(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } @Post(OidcProviderRoutes.INTROSPECTION) - postTokenIntrospection(@Req() req, @Res() res) { + postTokenIntrospection(@Req() req: Request, @Res() res: Response) { req.url = req.originalUrl.replace(this.prefix, ""); return this.oidcProviderService.getCallback()(req, res); } From 0b5349957c8dfaf89c5b331b6cd674403713076b Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 16:08:39 +0200 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=90=9B=20(back/dto):=20add=20definite?= =?UTF-8?q?=20assignment=20assertions=20to=20DTO=20properties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ! to readonly DTO properties to satisfy strictPropertyInitialization. Also fix a type narrowing for oidc-provider-config and add @ts-expect-error for jose-v2 import. --- .../core-fca-low/src/dto/app-config.dto.ts | 14 ++++---- .../src/dto/authorize-params.dto.ts | 12 +++---- .../src/dto/content-secury-policy.dto.ts | 14 ++++---- .../src/dto/core-fca-config.dto.ts | 26 +++++++------- .../src/dto/core-fca-session.dto.ts | 2 +- .../src/dto/identity-for-sp.dto.ts | 8 ++--- .../src/dto/identity-from-idp.dto.ts | 10 +++--- .../core-fca-low/src/dto/interaction.dto.ts | 2 +- .../src/dto/interaction_error_query.dto.ts | 4 +-- .../post-identity-provider-selection.dto.ts | 4 +-- .../src/dto/redirect-to-idp.dto.ts | 6 ++-- .../src/dto/revocation-token-params.dto.ts | 6 ++-- .../src/dto/sp-authorized-fqdns-config.dto.ts | 8 ++--- .../csmr-rie/src/dto/bridge-payload.dto.ts | 6 ++-- back/libs/app/src/dto/app-config.dto.ts | 10 +++--- back/libs/app/src/dto/app-rmq-config.dto.ts | 2 +- .../src/dto/email-validator-config.dto.ts | 4 +-- .../src/dto/exception-config.dto.ts | 2 +- .../src/dto/hyyyperbridge-enveloppe.dto.ts | 4 +-- .../src/dto/hyyyperbridge-response.dto.ts | 8 ++--- .../identity-provider-adapter-mongo.dto.ts | 36 +++++++++---------- back/libs/logger/src/dto/logger-config.dto.ts | 2 +- .../mongoose/src/dto/mongoose-config.dto.ts | 14 ++++---- .../src/dto/identity-service.dto.ts | 6 ++-- .../src/dto/oidc-client-config.dto.ts | 9 ++--- .../src/dto/oidc-provider-config.dto.ts | 12 ++++--- back/libs/oidc/src/dto/idp-metadata.dto.ts | 12 +++---- .../oidc/src/dto/pcf-client-metadata.dto.ts | 22 ++++++------ ...rvice-provider-adapter-mongo-config.dto.ts | 2 +- .../dto/service-provider-adapter-mongo.dto.ts | 18 +++++----- 30 files changed, 144 insertions(+), 141 deletions(-) diff --git a/back/apps/core-fca-low/src/dto/app-config.dto.ts b/back/apps/core-fca-low/src/dto/app-config.dto.ts index e55d3ac7f..426ef9c4e 100644 --- a/back/apps/core-fca-low/src/dto/app-config.dto.ts +++ b/back/apps/core-fca-low/src/dto/app-config.dto.ts @@ -15,28 +15,28 @@ import { SpAuthorizedFqdnsConfig } from "./sp-authorized-fqdns-config.dto"; export class AppConfig extends AppGenericConfig { @IsString() - readonly defaultIdpId: string; + readonly defaultIdpId!: string; @IsArray() @ValidateNested({ each: true }) @Type(() => SpAuthorizedFqdnsConfig) - readonly spAuthorizedFqdnsConfigs: SpAuthorizedFqdnsConfig[]; + readonly spAuthorizedFqdnsConfigs!: SpAuthorizedFqdnsConfig[]; @IsString() - readonly defaultEmailRenater: string; + readonly defaultEmailRenater!: string; @ValidateNested() @Type(() => ContentSecurityPolicy) - readonly contentSecurityPolicy: ContentSecurityPolicy; + readonly contentSecurityPolicy!: ContentSecurityPolicy; @IsUrl() - readonly defaultRedirectUri: string; + readonly defaultRedirectUri!: string; @IsEmail() - readonly supportEmail: string; + readonly supportEmail!: string; @IsString() - readonly passeDroitEmailSuffix: string; + readonly passeDroitEmailSuffix!: string; @IsBoolean() @IsOptional() diff --git a/back/apps/core-fca-low/src/dto/authorize-params.dto.ts b/back/apps/core-fca-low/src/dto/authorize-params.dto.ts index ca7fd2e09..4cc67fe9f 100644 --- a/back/apps/core-fca-low/src/dto/authorize-params.dto.ts +++ b/back/apps/core-fca-low/src/dto/authorize-params.dto.ts @@ -15,7 +15,7 @@ const URL_REGEX = /^https?:\/\/[^/].+$/; */ export class AuthorizeParamsDto { @IsString() - readonly client_id: string; + readonly client_id!: string; @IsOptional() @IsString() @@ -26,11 +26,11 @@ export class AuthorizeParamsDto { readonly claims?: string; @IsString() - readonly response_type: string; + readonly response_type!: string; @IsOptional() @IsString() - readonly response_mode: string; + readonly response_mode!: string; @IsOptional() @IsString() @@ -47,14 +47,14 @@ export class AuthorizeParamsDto { readonly siret_hint?: string; @IsString() - readonly state: string; + readonly state!: string; @Matches(URL_REGEX) - readonly redirect_uri: string; + readonly redirect_uri!: string; // The openid verification is made into oidc-provider @IsString() - readonly scope: string; + readonly scope!: string; @IsOptional() @IsString() diff --git a/back/apps/core-fca-low/src/dto/content-secury-policy.dto.ts b/back/apps/core-fca-low/src/dto/content-secury-policy.dto.ts index 53f2157cd..1cd695076 100644 --- a/back/apps/core-fca-low/src/dto/content-secury-policy.dto.ts +++ b/back/apps/core-fca-low/src/dto/content-secury-policy.dto.ts @@ -3,29 +3,29 @@ import { IsArray, IsString } from "class-validator"; export class ContentSecurityPolicy { @IsArray() @IsString({ each: true }) - connectSrc: string[]; + connectSrc!: string[]; @IsArray() @IsString({ each: true }) - defaultSrc: string[]; + defaultSrc!: string[]; @IsArray() @IsString({ each: true }) - styleSrc: string[]; + styleSrc!: string[]; @IsArray() @IsString({ each: true }) - scriptSrc: string[]; + scriptSrc!: string[]; @IsArray() @IsString({ each: true }) - frameSrc: string[]; + frameSrc!: string[]; @IsArray() @IsString({ each: true }) - frameAncestors: string[]; + frameAncestors!: string[]; @IsArray() @IsString({ each: true }) - imgSrc: string[]; + imgSrc!: string[]; } diff --git a/back/apps/core-fca-low/src/dto/core-fca-config.dto.ts b/back/apps/core-fca-low/src/dto/core-fca-config.dto.ts index f2a73b384..d1922f3b3 100644 --- a/back/apps/core-fca-low/src/dto/core-fca-config.dto.ts +++ b/back/apps/core-fca-low/src/dto/core-fca-config.dto.ts @@ -18,65 +18,65 @@ export class CoreFcaConfig { @IsObject() @ValidateNested() @Type(() => AppConfig) - readonly App: AppConfig; + readonly App!: AppConfig; @IsObject() @ValidateNested() @Type(() => ApiEntrepriseConfig) - readonly ApiEntreprise: ApiEntrepriseConfig; + readonly ApiEntreprise!: ApiEntrepriseConfig; @IsObject() @ValidateNested() @Type(() => ExceptionsConfig) - readonly Exceptions: ExceptionsConfig; + readonly Exceptions!: ExceptionsConfig; @IsObject() @ValidateNested() @Type(() => EmailValidatorConfig) - readonly EmailValidator: EmailValidatorConfig; + readonly EmailValidator!: EmailValidatorConfig; @IsObject() @ValidateNested() @Type(() => RabbitmqConfig) - readonly HyyyperbridgeBroker: RabbitmqConfig; + readonly HyyyperbridgeBroker!: RabbitmqConfig; @IsObject() @ValidateNested() @Type(() => LoggerConfig) - readonly Logger: LoggerConfig; + readonly Logger!: LoggerConfig; @IsObject() @ValidateNested() @Type(() => OidcProviderConfig) - readonly OidcProvider: OidcProviderConfig; + readonly OidcProvider!: OidcProviderConfig; @IsObject() @ValidateNested() @Type(() => OidcClientConfig) - readonly OidcClient: OidcClientConfig; + readonly OidcClient!: OidcClientConfig; @IsObject() @ValidateNested() @Type(() => MongooseConfig) - readonly Mongoose: MongooseConfig; + readonly Mongoose!: MongooseConfig; @IsObject() @ValidateNested() @Type(() => RedisConfig) - readonly Redis: RedisConfig; + readonly Redis!: RedisConfig; @IsObject() @ValidateNested() @Type(() => SessionConfig) - readonly Session: SessionConfig; + readonly Session!: SessionConfig; @IsObject() @ValidateNested() @Type(() => ServiceProviderAdapterMongoConfig) - readonly ServiceProviderAdapterMongo: ServiceProviderAdapterMongoConfig; + readonly ServiceProviderAdapterMongo!: ServiceProviderAdapterMongoConfig; @IsObject() @ValidateNested() @Type(() => IdentityProviderAdapterMongoConfig) - readonly IdentityProviderAdapterMongo: IdentityProviderAdapterMongoConfig; + readonly IdentityProviderAdapterMongo!: IdentityProviderAdapterMongoConfig; } diff --git a/back/apps/core-fca-low/src/dto/core-fca-session.dto.ts b/back/apps/core-fca-low/src/dto/core-fca-session.dto.ts index f9838aa86..cf8e275c6 100644 --- a/back/apps/core-fca-low/src/dto/core-fca-session.dto.ts +++ b/back/apps/core-fca-low/src/dto/core-fca-session.dto.ts @@ -8,7 +8,7 @@ export class CoreFcaSession { @ValidateNested() @Type(() => UserSession) @Expose() - readonly User: UserSession; + readonly User!: UserSession; @IsObject() @ValidateNested() diff --git a/back/apps/core-fca-low/src/dto/identity-for-sp.dto.ts b/back/apps/core-fca-low/src/dto/identity-for-sp.dto.ts index bdd704f4e..30da5caa4 100644 --- a/back/apps/core-fca-low/src/dto/identity-for-sp.dto.ts +++ b/back/apps/core-fca-low/src/dto/identity-for-sp.dto.ts @@ -25,15 +25,15 @@ export class IdentityForSpDto extends IdentityFromIdpDto { declare phone_number?: string; @IsObject() - custom: { + custom!: { [key: string]: unknown; }; @IsString() - idp_id: string; + idp_id!: string; @IsString() - idp_acr: string; + idp_acr!: string; @IsString() @IsOptional() @@ -50,5 +50,5 @@ export class IdentityForSpDto extends IdentityFromIdpDto { ], { each: true }, ) - roles: string[]; + roles!: string[]; } diff --git a/back/apps/core-fca-low/src/dto/identity-from-idp.dto.ts b/back/apps/core-fca-low/src/dto/identity-from-idp.dto.ts index be5e6474e..5d7aab96e 100644 --- a/back/apps/core-fca-low/src/dto/identity-from-idp.dto.ts +++ b/back/apps/core-fca-low/src/dto/identity-from-idp.dto.ts @@ -13,25 +13,25 @@ export class IdentityFromIdpDto { @MinLength(1) @MaxLength(256) @IsAscii() - sub: string; + sub!: string; @IsString() @MinLength(1) @MaxLength(256) - given_name: string; + given_name!: string; @IsString() @MinLength(1) @MaxLength(256) - usual_name: string; + usual_name!: string; @IsEmail() - email: string; + email!: string; @MinLength(1) @MaxLength(256) @IsAscii() - uid: string; + uid!: string; @IsString() @MinLength(1) diff --git a/back/apps/core-fca-low/src/dto/interaction.dto.ts b/back/apps/core-fca-low/src/dto/interaction.dto.ts index eb75c9253..fa240b4c0 100644 --- a/back/apps/core-fca-low/src/dto/interaction.dto.ts +++ b/back/apps/core-fca-low/src/dto/interaction.dto.ts @@ -4,5 +4,5 @@ export class Interaction { @IsString() @IsAscii() @Length(21, 21) - readonly uid: string; + readonly uid!: string; } diff --git a/back/apps/core-fca-low/src/dto/interaction_error_query.dto.ts b/back/apps/core-fca-low/src/dto/interaction_error_query.dto.ts index 953748a8a..70ee18f8d 100644 --- a/back/apps/core-fca-low/src/dto/interaction_error_query.dto.ts +++ b/back/apps/core-fca-low/src/dto/interaction_error_query.dto.ts @@ -6,11 +6,11 @@ export class InteractionErrorQuery { @IsString() @MaxLength(256) @Transform(({ value }) => value || undefined) - error: string; + error!: string; @IsOptional() @IsString() @MaxLength(256) @Transform(({ value }) => value || undefined) - error_description: string; + error_description!: string; } diff --git a/back/apps/core-fca-low/src/dto/post-identity-provider-selection.dto.ts b/back/apps/core-fca-low/src/dto/post-identity-provider-selection.dto.ts index 1649771a7..926c03e0e 100644 --- a/back/apps/core-fca-low/src/dto/post-identity-provider-selection.dto.ts +++ b/back/apps/core-fca-low/src/dto/post-identity-provider-selection.dto.ts @@ -3,9 +3,9 @@ import { IsAscii, IsString } from "class-validator"; export class PostIdentityProviderSelectionDto { @IsString() @IsAscii() - readonly identityProviderUid: string; + readonly identityProviderUid!: string; @IsString() @IsAscii() - readonly csrfToken: string; + readonly csrfToken!: string; } diff --git a/back/apps/core-fca-low/src/dto/redirect-to-idp.dto.ts b/back/apps/core-fca-low/src/dto/redirect-to-idp.dto.ts index d2bdfee6e..3f90925b6 100644 --- a/back/apps/core-fca-low/src/dto/redirect-to-idp.dto.ts +++ b/back/apps/core-fca-low/src/dto/redirect-to-idp.dto.ts @@ -9,14 +9,14 @@ import { export class RedirectToIdp { @IsEmail() - readonly email: string; + readonly email!: string; @IsBoolean() @IsOptional() @Transform(({ value }) => value === "on", { toClassOnly: true }) - readonly rememberMe: boolean; + readonly rememberMe!: boolean; @IsString() @IsAscii() - readonly csrfToken: string; + readonly csrfToken!: string; } diff --git a/back/apps/core-fca-low/src/dto/revocation-token-params.dto.ts b/back/apps/core-fca-low/src/dto/revocation-token-params.dto.ts index c27e74457..f902427ac 100644 --- a/back/apps/core-fca-low/src/dto/revocation-token-params.dto.ts +++ b/back/apps/core-fca-low/src/dto/revocation-token-params.dto.ts @@ -6,13 +6,13 @@ export class RevocationTokenParamsDTO { @IsString() @MinLength(43) @Matches(SAFE_STRING_REGEX) - readonly token: string; + readonly token!: string; @IsString() - readonly client_id: string; + readonly client_id!: string; @IsString() @MinLength(32) @IsAscii() - readonly client_secret: string; + readonly client_secret!: string; } diff --git a/back/apps/core-fca-low/src/dto/sp-authorized-fqdns-config.dto.ts b/back/apps/core-fca-low/src/dto/sp-authorized-fqdns-config.dto.ts index fd9d3a674..1e08c998b 100644 --- a/back/apps/core-fca-low/src/dto/sp-authorized-fqdns-config.dto.ts +++ b/back/apps/core-fca-low/src/dto/sp-authorized-fqdns-config.dto.ts @@ -2,15 +2,15 @@ import { IsArray, IsString } from "class-validator"; export class SpAuthorizedFqdnsConfig { @IsString() - readonly spId: string; + readonly spId!: string; @IsString() - readonly spName: string; + readonly spName!: string; @IsString() - readonly spContact: string; + readonly spContact!: string; @IsArray() @IsString({ each: true }) - readonly authorizedFqdns: string[]; + readonly authorizedFqdns!: string[]; } diff --git a/back/apps/csmr-rie/src/dto/bridge-payload.dto.ts b/back/apps/csmr-rie/src/dto/bridge-payload.dto.ts index 53f4c0577..d0efbf4a6 100644 --- a/back/apps/csmr-rie/src/dto/bridge-payload.dto.ts +++ b/back/apps/csmr-rie/src/dto/bridge-payload.dto.ts @@ -3,17 +3,17 @@ import { IsIn, IsObject, IsOptional, IsString, IsUrl } from "class-validator"; export class BridgePayloadDto { @IsUrl() - readonly url: string; + readonly url!: string; @IsIn(["get", "post"]) @Transform( /* istanbul ignore next */ ({ value }) => value.toLowerCase(), ) - readonly method: string; + readonly method!: string; @IsObject() - readonly headers: Record; + readonly headers!: Record; /** * this parameter is voluntary abstract. diff --git a/back/libs/app/src/dto/app-config.dto.ts b/back/libs/app/src/dto/app-config.dto.ts index 109d0406e..8c0a41e5f 100644 --- a/back/libs/app/src/dto/app-config.dto.ts +++ b/back/libs/app/src/dto/app-config.dto.ts @@ -24,15 +24,15 @@ class HttpsOptions { class DsfrAssets { @IsString() - readonly assetPath: string; + readonly assetPath!: string; @IsString() - readonly prefix: string; + readonly prefix!: string; } export class AppConfig { @IsString() - readonly name: string; + readonly name!: string; /** * @TODO #195 @@ -40,11 +40,11 @@ export class AppConfig { * @see https://gitlab.dev-franceconnect.fr/france-connect/fc/-/issues/195 */ @IsString() - readonly urlPrefix: string; + readonly urlPrefix!: string; @ValidateNested() @Type(() => HttpsOptions) - readonly httpsOptions: HttpsOptions; + readonly httpsOptions!: HttpsOptions; @IsOptional() @IsString() diff --git a/back/libs/app/src/dto/app-rmq-config.dto.ts b/back/libs/app/src/dto/app-rmq-config.dto.ts index 22373aabc..a3306c2e2 100644 --- a/back/libs/app/src/dto/app-rmq-config.dto.ts +++ b/back/libs/app/src/dto/app-rmq-config.dto.ts @@ -2,5 +2,5 @@ import { IsString } from "class-validator"; export class AppRmqConfig { @IsString() - readonly name: string; + readonly name!: string; } diff --git a/back/libs/email-validator/src/dto/email-validator-config.dto.ts b/back/libs/email-validator/src/dto/email-validator-config.dto.ts index f9d9e3b69..861677451 100644 --- a/back/libs/email-validator/src/dto/email-validator-config.dto.ts +++ b/back/libs/email-validator/src/dto/email-validator-config.dto.ts @@ -2,8 +2,8 @@ import { IsArray, IsBoolean } from "class-validator"; export class EmailValidatorConfig { @IsArray() - readonly domainWhitelist: string[]; + readonly domainWhitelist!: string[]; @IsBoolean() - readonly featureMxResolutionValidation: boolean; + readonly featureMxResolutionValidation!: boolean; } diff --git a/back/libs/exceptions/src/dto/exception-config.dto.ts b/back/libs/exceptions/src/dto/exception-config.dto.ts index 79a9147b2..171b5d99a 100644 --- a/back/libs/exceptions/src/dto/exception-config.dto.ts +++ b/back/libs/exceptions/src/dto/exception-config.dto.ts @@ -3,5 +3,5 @@ import { IsNotEmpty, IsString } from "class-validator"; export class ExceptionsConfig { @IsString() @IsNotEmpty() - readonly prefix: string; + readonly prefix!: string; } diff --git a/back/libs/hyyyperbridge/src/dto/hyyyperbridge-enveloppe.dto.ts b/back/libs/hyyyperbridge/src/dto/hyyyperbridge-enveloppe.dto.ts index bbfd9cb33..8f722e47a 100644 --- a/back/libs/hyyyperbridge/src/dto/hyyyperbridge-enveloppe.dto.ts +++ b/back/libs/hyyyperbridge/src/dto/hyyyperbridge-enveloppe.dto.ts @@ -3,8 +3,8 @@ import { HyyyperbridgeMessageType } from "../enums/hyyyperbridge-message-type.en export class HyyyperbridgeEnveloppeDto { @IsEnum(HyyyperbridgeMessageType) - readonly type: HyyyperbridgeMessageType; + readonly type!: HyyyperbridgeMessageType; @IsNotEmptyObject() - readonly data: object; + readonly data!: object; } diff --git a/back/libs/hyyyperbridge/src/dto/hyyyperbridge-response.dto.ts b/back/libs/hyyyperbridge/src/dto/hyyyperbridge-response.dto.ts index 8a8183ac0..a87ccfbda 100644 --- a/back/libs/hyyyperbridge/src/dto/hyyyperbridge-response.dto.ts +++ b/back/libs/hyyyperbridge/src/dto/hyyyperbridge-response.dto.ts @@ -2,18 +2,18 @@ import { IsNumber, IsObject, IsString } from "class-validator"; export class HyyyperbridgeResponseDto { @IsNumber() - readonly status: number; + readonly status!: number; @IsString() - readonly statusText: string; + readonly statusText!: string; @IsObject() - readonly headers: Record; + readonly headers!: Record; /** * this parameter is voluntary abstract. * the proxy is not in charge to validate the exactness of the data itself */ @IsString() - readonly data: string; + readonly data!: string; } diff --git a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.ts b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.ts index fd8b40e5d..a4f0134a0 100644 --- a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.ts +++ b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.ts @@ -12,24 +12,24 @@ const URL_REGEX = /^https?:\/\/[^/].+$/; export class MetadataIdpAdapterMongoDTO { @IsString() - readonly uid: string; + readonly uid!: string; @IsOptional() @Matches(URL_REGEX) @Transform(({ value }) => value || undefined) - readonly url: string; + readonly url!: string; @IsString() - readonly name: string; + readonly name!: string; @IsString() - readonly title: string; + readonly title!: string; @IsBoolean() - readonly active: boolean; + readonly active!: boolean; @IsString() - readonly clientID: string; + readonly clientID!: string; @IsOptional() @IsString() @@ -62,11 +62,11 @@ export class MetadataIdpAdapterMongoDTO { readonly id_token_encrypted_response_enc?: string; @IsString() - readonly token_endpoint_auth_method: string; + readonly token_endpoint_auth_method!: string; @IsString() @MinLength(32) - readonly client_secret: string; + readonly client_secret!: string; // issuer metadata @IsOptional() @@ -75,10 +75,10 @@ export class MetadataIdpAdapterMongoDTO { readonly endSessionURL?: string; @IsBoolean() - readonly discovery: boolean; + readonly discovery!: boolean; @IsString() - readonly siret: string; + readonly siret!: string; @IsOptional() @IsString() @@ -92,10 +92,10 @@ export class MetadataIdpAdapterMongoDTO { readonly fqdns?: string[]; @IsBoolean() - readonly isRoutingEnabled: boolean; + readonly isRoutingEnabled!: boolean; @IsBoolean() - readonly isEntraID: boolean; + readonly isEntraID!: boolean; @IsOptional() @IsArray() @@ -104,15 +104,15 @@ export class MetadataIdpAdapterMongoDTO { readonly extraAcceptedEmailDomains?: string[]; @IsBoolean() - readonly isBlockingForUnlistedEmailDomainsEnabled: boolean; + readonly isBlockingForUnlistedEmailDomainsEnabled!: boolean; @IsBoolean() - readonly useTheHyyyperbridge: boolean; + readonly useTheHyyyperbridge!: boolean; } export class DiscoveryIdpAdapterMongoDTO extends MetadataIdpAdapterMongoDTO { @Matches(URL_REGEX) - readonly discoveryUrl: string; + readonly discoveryUrl!: string; } export class NoDiscoveryIdpAdapterMongoDTO extends MetadataIdpAdapterMongoDTO { @@ -122,11 +122,11 @@ export class NoDiscoveryIdpAdapterMongoDTO extends MetadataIdpAdapterMongoDTO { readonly jwksURL?: string | undefined; @Matches(URL_REGEX) - readonly authzURL: string; + readonly authzURL!: string; @Matches(URL_REGEX) - readonly tokenURL: string; + readonly tokenURL!: string; @Matches(URL_REGEX) - readonly userInfoURL: string; + readonly userInfoURL!: string; } diff --git a/back/libs/logger/src/dto/logger-config.dto.ts b/back/libs/logger/src/dto/logger-config.dto.ts index f1edb8507..cc81458f3 100644 --- a/back/libs/logger/src/dto/logger-config.dto.ts +++ b/back/libs/logger/src/dto/logger-config.dto.ts @@ -3,5 +3,5 @@ import { LogLevels } from "../enums"; export class LoggerConfig { @IsEnum(LogLevels) - readonly threshold: string; + readonly threshold!: string; } diff --git a/back/libs/mongoose/src/dto/mongoose-config.dto.ts b/back/libs/mongoose/src/dto/mongoose-config.dto.ts index 65a342603..7fa3f7e69 100644 --- a/back/libs/mongoose/src/dto/mongoose-config.dto.ts +++ b/back/libs/mongoose/src/dto/mongoose-config.dto.ts @@ -11,7 +11,7 @@ import { export class MongooseConfigOptions { @IsString() - readonly authSource: string; + readonly authSource!: string; @IsBoolean() @IsOptional() @@ -33,11 +33,11 @@ export class MongooseConfigOptions { export class MongooseConfig { @IsString() @IsNotEmpty() - readonly user: string; + readonly user!: string; @IsString() @IsNotEmpty() - readonly password: string; + readonly password!: string; @IsString() @IsNotEmpty() @@ -46,17 +46,17 @@ export class MongooseConfig { @IsString() @IsNotEmpty() - readonly hosts: string; + readonly hosts!: string; @IsString() @IsNotEmpty() - readonly database: string; + readonly database!: string; @IsObject() @ValidateNested() @Type(() => MongooseConfigOptions) - readonly options: MongooseConfigOptions; + readonly options!: MongooseConfigOptions; @IsNumber() - readonly watcherDebounceWaitDuration: number; + readonly watcherDebounceWaitDuration!: number; } diff --git a/back/libs/oidc-client/src/dto/identity-service.dto.ts b/back/libs/oidc-client/src/dto/identity-service.dto.ts index 3a9edc2dc..e30da83a3 100644 --- a/back/libs/oidc-client/src/dto/identity-service.dto.ts +++ b/back/libs/oidc-client/src/dto/identity-service.dto.ts @@ -33,16 +33,16 @@ export class TokenDto { @IsString() @MinLength(1) @IsAscii() - readonly accessToken: string; + readonly accessToken!: string; @IsString() @MinLength(1) @IsJWT() - readonly idToken: string; + readonly idToken!: string; @IsObject() @ValidateNested() // Only the amr and acr claims need to be validated @Type(() => ClaimsDto) - readonly claims: IDToken & ClaimsDto; + readonly claims!: IDToken & ClaimsDto; } diff --git a/back/libs/oidc-client/src/dto/oidc-client-config.dto.ts b/back/libs/oidc-client/src/dto/oidc-client-config.dto.ts index 0743322d5..f8043774e 100644 --- a/back/libs/oidc-client/src/dto/oidc-client-config.dto.ts +++ b/back/libs/oidc-client/src/dto/oidc-client-config.dto.ts @@ -6,11 +6,12 @@ import { IsUrl, } from "class-validator"; +// @ts-expect-error import { JSONWebKeySet } from "jose-v2"; export class OidcClientConfig { @IsNumber() - readonly timeout: number; + readonly timeout!: number; @IsOptional() @IsObject() @@ -20,14 +21,14 @@ export class OidcClientConfig { protocols: ["https"], require_protocol: true, }) - readonly redirectUri: string; + readonly redirectUri!: string; @IsUrl({ protocols: ["https"], require_protocol: true, }) - readonly postLogoutRedirectUri: string; + readonly postLogoutRedirectUri!: string; @IsBoolean() - readonly enableHyyyperbridge: boolean; + readonly enableHyyyperbridge!: boolean; } diff --git a/back/libs/oidc-provider/src/dto/oidc-provider-config.dto.ts b/back/libs/oidc-provider/src/dto/oidc-provider-config.dto.ts index 8de25b776..95af3a4f5 100644 --- a/back/libs/oidc-provider/src/dto/oidc-provider-config.dto.ts +++ b/back/libs/oidc-provider/src/dto/oidc-provider-config.dto.ts @@ -13,10 +13,10 @@ import { OidcProviderPrompt } from "../enums"; export class OidcProviderConfig { @IsString() - readonly prefix: string; + readonly prefix!: string; @IsString() - readonly issuer: string; + readonly issuer!: string; @IsObject() readonly routes: Configuration["routes"]; @@ -31,15 +31,17 @@ export class OidcProviderConfig { readonly jwks: Configuration["jwks"]; @IsNumber() - readonly timeout: ReturnType["timeout"]; + readonly timeout!: ReturnType< + NonNullable + >["timeout"]; @IsArray() @IsEnum(OidcProviderPrompt, { each: true }) - readonly forcedPrompt: OidcProviderPrompt[]; + readonly forcedPrompt!: OidcProviderPrompt[]; @IsArray() @IsEnum(OidcProviderPrompt, { each: true }) - readonly allowedPrompt: OidcProviderPrompt[]; + readonly allowedPrompt!: OidcProviderPrompt[]; @IsBoolean() @IsOptional() diff --git a/back/libs/oidc/src/dto/idp-metadata.dto.ts b/back/libs/oidc/src/dto/idp-metadata.dto.ts index 636d8e3dc..c9a83e39e 100644 --- a/back/libs/oidc/src/dto/idp-metadata.dto.ts +++ b/back/libs/oidc/src/dto/idp-metadata.dto.ts @@ -8,22 +8,22 @@ export class FederationServerMetadata implements Pick< (typeof IDP_METADATA)[number] > { @IsString() - issuer: string; + issuer!: string; @IsString() - token_endpoint: string; + token_endpoint!: string; @IsString() - authorization_endpoint: string; + authorization_endpoint!: string; @IsString() - jwks_uri: string; + jwks_uri!: string; @IsString() - userinfo_endpoint: string; + userinfo_endpoint!: string; @IsString() - end_session_endpoint: string; + end_session_endpoint!: string; [metadata: string]: JsonValue | undefined; } diff --git a/back/libs/oidc/src/dto/pcf-client-metadata.dto.ts b/back/libs/oidc/src/dto/pcf-client-metadata.dto.ts index ddd69b2a2..4b2e7c411 100644 --- a/back/libs/oidc/src/dto/pcf-client-metadata.dto.ts +++ b/back/libs/oidc/src/dto/pcf-client-metadata.dto.ts @@ -9,37 +9,37 @@ export class FederationClientMetadata implements Pick< (typeof CLIENT_METADATA)[number] > { @IsString() - client_id: string; + client_id!: string; @IsString() - client_secret: string; + client_secret!: string; @IsArray() - response_types: string[]; + response_types!: string[]; @IsString() - id_token_signed_response_alg: string; + id_token_signed_response_alg!: string; @IsString() - token_endpoint_auth_method: string; + token_endpoint_auth_method!: string; @IsString() - revocation_endpoint_auth_method: string; + revocation_endpoint_auth_method!: string; @IsString() - id_token_encrypted_response_alg: string; + id_token_encrypted_response_alg!: string; @IsString() - id_token_encrypted_response_enc: string; + id_token_encrypted_response_enc!: string; @IsString() - userinfo_encrypted_response_alg: string; + userinfo_encrypted_response_alg!: string; @IsString() - userinfo_encrypted_response_enc: string; + userinfo_encrypted_response_enc!: string; @IsString() - userinfo_signed_response_alg: string; + userinfo_signed_response_alg!: string; [metadata: string]: JsonValue | undefined; } diff --git a/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo-config.dto.ts b/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo-config.dto.ts index f94ccf59b..5bba29692 100644 --- a/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo-config.dto.ts +++ b/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo-config.dto.ts @@ -2,5 +2,5 @@ import { IsString } from "class-validator"; export class ServiceProviderAdapterMongoConfig { @IsString() - readonly clientSecretEncryptKey: string; + readonly clientSecretEncryptKey!: string; } diff --git a/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo.dto.ts b/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo.dto.ts index d5e81b999..2d7f60fa6 100644 --- a/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo.dto.ts +++ b/back/libs/service-provider-adapter-mongo/src/dto/service-provider-adapter-mongo.dto.ts @@ -13,33 +13,33 @@ const URL_REGEX = /^https?:\/\/[^/].+$/; export class ServiceProviderAdapterMongoDTO { @IsBoolean() - readonly active: boolean; + readonly active!: boolean; @IsString() - readonly key: string; + readonly key!: string; @IsString() - readonly name: string; + readonly name!: string; @IsString() @MinLength(32) - readonly client_secret: string; + readonly client_secret!: string; @IsArray() @Matches(URL_REGEX, { each: true }) - readonly redirect_uris: string[]; + readonly redirect_uris!: string[]; @IsArray() @Matches(URL_REGEX, { each: true }) - readonly post_logout_redirect_uris: string[]; + readonly post_logout_redirect_uris!: string[]; @IsArray() @IsString({ each: true }) - readonly scopes: string[]; + readonly scopes!: string[]; @IsString() @IsIn(["ES256", "RS256", "HS256"]) - readonly id_token_signed_response_alg: "ES256" | "RS256" | "HS256"; + readonly id_token_signed_response_alg!: "ES256" | "RS256" | "HS256"; @IsOptional() @IsString() @@ -70,7 +70,7 @@ export class ServiceProviderAdapterMongoDTO { // 'private' = sp that also accepts private sector employees @IsString() @IsIn(["private", "public"]) - readonly type: "private" | "public"; + readonly type!: "private" | "public"; @IsOptional() @IsArray() From 37e981b2902d248b90f06987c0bbc1e008c064c0 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 16:32:11 +0200 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B=20(back):=20narrow=20catch=20c?= =?UTF-8?q?lause=20types=20and=20add=20explicit=20any=20params?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit type annotations for catch error vars (error as Error/any) and implicit any parameters across services, validators, and providers. Replaces anonymous context/object params with typed signatures. --- .../services/core-fca-middleware.service.ts | 2 +- .../src/services/identity.sanitizer.ts | 8 ++- ...phone-number-simple-validator.validator.ts | 4 +- .../src/validators/is-siret-validator.ts | 2 +- .../controllers/csmr-http-proxy.controller.ts | 7 +- .../src/services/api-entreprise.service.ts | 8 +-- back/libs/config/src/config.module.ts | 2 +- back/libs/config/src/config.service.ts | 2 +- .../src/providers/mongoose.provider.ts | 4 +- .../src/notifications.service.ts | 4 +- .../oidc-client/src/oidc-client.module.ts | 2 +- .../src/services/oidc-client.service.ts | 68 ++++++++++--------- .../src/oidc-provider.service.ts | 47 +++++++++---- .../services/oidc-provider-config.service.ts | 54 ++++++++------- 14 files changed, 122 insertions(+), 92 deletions(-) diff --git a/back/apps/core-fca-low/src/services/core-fca-middleware.service.ts b/back/apps/core-fca-low/src/services/core-fca-middleware.service.ts index f6f12d809..6c9a1bd12 100644 --- a/back/apps/core-fca-low/src/services/core-fca-middleware.service.ts +++ b/back/apps/core-fca-low/src/services/core-fca-middleware.service.ts @@ -148,7 +148,7 @@ export class CoreFcaMiddlewareService { } } - protected async userinfoMiddleware(ctx) { + protected async userinfoMiddleware(ctx: any) { const { isSessionLoaded } = await this.loadSessionInAsyncLocalStorage(ctx); if (isSessionLoaded) { diff --git a/back/apps/core-fca-low/src/services/identity.sanitizer.ts b/back/apps/core-fca-low/src/services/identity.sanitizer.ts index cfed58194..7e9e57d8d 100644 --- a/back/apps/core-fca-low/src/services/identity.sanitizer.ts +++ b/back/apps/core-fca-low/src/services/identity.sanitizer.ts @@ -88,8 +88,8 @@ export class IdentitySanitizer { this.logger.error({ code: "identity-sanitizer-cached-organization-error", cachedOrganizationError: error, - cachedOrganizationErrorCause: error?.cause, - cachedOrganizationErrorType: error?.constructor?.name, + cachedOrganizationErrorCause: (error as any)?.cause, + cachedOrganizationErrorType: (error as any)?.constructor?.name, }); identityForSp.roles = []; } @@ -128,7 +128,9 @@ export class IdentitySanitizer { !(key in identityForSp) && !["aud", "exp", "iat", "iss"].includes(key) ) { - identityForSp.custom[key] = identityForSpWithExtraProperties[key]; + identityForSp.custom[key] = ( + identityForSpWithExtraProperties as unknown as Record + )[key]; } }); diff --git a/back/apps/core-fca-low/src/validators/is-phone-number-simple-validator.validator.ts b/back/apps/core-fca-low/src/validators/is-phone-number-simple-validator.validator.ts index 85ce1d1e4..b730e60a2 100644 --- a/back/apps/core-fca-low/src/validators/is-phone-number-simple-validator.validator.ts +++ b/back/apps/core-fca-low/src/validators/is-phone-number-simple-validator.validator.ts @@ -18,7 +18,7 @@ const phoneRegex = /^\+?(?:[0-9][ -]?){6,14}[0-9]$/; @Injectable() export class IsPhoneNumberSimpleValidatorConstraint implements ValidatorConstraintInterface { constructor(public readonly config: ConfigService) {} - validate(value: string): boolean { + validate(value: string | null | undefined): boolean { return typeof value === "string" && phoneRegex.test(value); } @@ -30,7 +30,7 @@ export class IsPhoneNumberSimpleValidatorConstraint implements ValidatorConstrai export function IsPhoneNumberSimpleValidator( validationOptions?: ValidationOptions, ) { - return function (object, propertyName: string) { + return function (object: any, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, diff --git a/back/apps/core-fca-low/src/validators/is-siret-validator.ts b/back/apps/core-fca-low/src/validators/is-siret-validator.ts index ce3461e41..c226bb9ac 100644 --- a/back/apps/core-fca-low/src/validators/is-siret-validator.ts +++ b/back/apps/core-fca-low/src/validators/is-siret-validator.ts @@ -55,7 +55,7 @@ export class IsSiretConstraint implements ValidatorConstraintInterface { } export function IsSiret(validationOptions?: ValidationOptions) { - return function (object: unknown, propertyName: string) { + return function (object: any, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, diff --git a/back/apps/csmr-rie/src/controllers/csmr-http-proxy.controller.ts b/back/apps/csmr-rie/src/controllers/csmr-http-proxy.controller.ts index 5c54e6828..a4496c47b 100644 --- a/back/apps/csmr-rie/src/controllers/csmr-http-proxy.controller.ts +++ b/back/apps/csmr-rie/src/controllers/csmr-http-proxy.controller.ts @@ -56,10 +56,11 @@ export class CsmrHttpProxyController { }, }; } catch (error) { + const err = error as any; const errorData = { - reason: `${error.message}${error?.cause?.message ? ` (${error.cause.message})` : ""}`, - name: error?.cause?.name || error.name, - code: error?.cause?.code || error.code, + reason: `${err.message}${err?.cause?.message ? ` (${err.cause.message})` : ""}`, + name: err?.cause?.name || err.name, + code: err?.cause?.code || err.code, }; this.logger.error({ errorData }); diff --git a/back/libs/api-entreprise/src/services/api-entreprise.service.ts b/back/libs/api-entreprise/src/services/api-entreprise.service.ts index 47ae7dc95..fa53fb1a1 100644 --- a/back/libs/api-entreprise/src/services/api-entreprise.service.ts +++ b/back/libs/api-entreprise/src/services/api-entreprise.service.ts @@ -18,8 +18,8 @@ export class ApiEntrepriseService { this.logger.error({ code: "api-entreprise-service-find-by-siret-error", apiEntrepriseFindError: error, - apiEntrepriseFindErrorCause: error?.cause, - apiEntrepriseFindErrorType: error?.constructor?.name, + apiEntrepriseFindErrorCause: (error as Error)?.cause, + apiEntrepriseFindErrorType: (error as Error)?.constructor?.name, }); throw error; } @@ -30,8 +30,8 @@ export class ApiEntrepriseService { this.logger.error({ code: "api-entreprise-service-organization-mapping-error", apiEntrepriseMappingError: error, - apiEntrepriseMappingErrorCause: error?.cause, - apiEntrepriseMappingErrorType: error?.constructor?.name, + apiEntrepriseMappingErrorCause: (error as Error)?.cause, + apiEntrepriseMappingErrorType: (error as Error)?.constructor?.name, }); throw error; } diff --git a/back/libs/config/src/config.module.ts b/back/libs/config/src/config.module.ts index 54da7bc1e..c45109743 100644 --- a/back/libs/config/src/config.module.ts +++ b/back/libs/config/src/config.module.ts @@ -4,7 +4,7 @@ import { ConfigService } from "./config.service"; @Module({}) @Global() export class ConfigModule { - static forRoot(service): DynamicModule { + static forRoot(service: any): DynamicModule { const provider = { provide: ConfigService, useValue: service, diff --git a/back/libs/config/src/config.service.ts b/back/libs/config/src/config.service.ts index e6b15184b..2b065548c 100644 --- a/back/libs/config/src/config.service.ts +++ b/back/libs/config/src/config.service.ts @@ -31,7 +31,7 @@ export class ConfigService { this.configuration = deepFreeze(config); } - private static validate(config, schema) { + private static validate(config: any, schema: any) { const object = plainToInstance(schema, config); const errors = validateSync(object, validationOptions); diff --git a/back/libs/mongoose/src/providers/mongoose.provider.ts b/back/libs/mongoose/src/providers/mongoose.provider.ts index c5da8725a..3c9614086 100644 --- a/back/libs/mongoose/src/providers/mongoose.provider.ts +++ b/back/libs/mongoose/src/providers/mongoose.provider.ts @@ -14,7 +14,7 @@ import { NestJsConnection } from "../interfaces"; export class MongooseProvider { static connectionFactory( logger: LoggerService, - eventBus, + eventBus: any, connection: NestJsConnection, ): NestJsConnection { eventBus.publish(new MongooseConnectionReconnectedEvent()); @@ -49,7 +49,7 @@ export class MongooseProvider { static buildMongoParams( logger: LoggerService, config: ConfigService, - eventBus, + eventBus: any, ): MongooseModuleOptions { const { user, diff --git a/back/libs/notifications/src/notifications.service.ts b/back/libs/notifications/src/notifications.service.ts index bc8a69541..a947d435e 100644 --- a/back/libs/notifications/src/notifications.service.ts +++ b/back/libs/notifications/src/notifications.service.ts @@ -6,11 +6,11 @@ import { NotificationInterface } from "./interfaces"; @Injectable() export class NotificationsService { - private listCache: NotificationInterface[]; + private listCache!: NotificationInterface[]; constructor( @InjectModel("Notifications") - private readonly notificationsModel, + private readonly notificationsModel: any, private readonly mongooseWatcher: MongooseCollectionOperationWatcherHelper, ) {} diff --git a/back/libs/oidc-client/src/oidc-client.module.ts b/back/libs/oidc-client/src/oidc-client.module.ts index b2aa627fb..844b29eb9 100644 --- a/back/libs/oidc-client/src/oidc-client.module.ts +++ b/back/libs/oidc-client/src/oidc-client.module.ts @@ -10,7 +10,7 @@ import { IDENTITY_PROVIDER_SERVICE } from "./tokens"; export class OidcClientModule { static register( identityProvider: Type, - identityProviderModule, + identityProviderModule: any, ): DynamicModule { return { module: OidcClientModule, diff --git a/back/libs/oidc-client/src/services/oidc-client.service.ts b/back/libs/oidc-client/src/services/oidc-client.service.ts index 390930cad..f1225cc82 100644 --- a/back/libs/oidc-client/src/services/oidc-client.service.ts +++ b/back/libs/oidc-client/src/services/oidc-client.service.ts @@ -87,7 +87,7 @@ export class OidcClientService { private readonly session: SessionService, ) {} - static objToUrlParams(obj) { + static objToUrlParams(obj: any) { return new URLSearchParams( chain(obj) .omitBy((v) => v === undefined || v === null || v === "") @@ -96,7 +96,7 @@ export class OidcClientService { ); } - static getCurrentUrl = (req) => + static getCurrentUrl = (req: any) => new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`); private async fetchThroughTheHyyyperbridge( @@ -105,8 +105,8 @@ export class OidcClientService { ): Promise { const message = { url, - headers: options.headers, - method: options.method, + headers: options!.headers, + method: options!.method, data: options?.body?.toString(), }; @@ -123,7 +123,7 @@ export class OidcClientService { try { rawHyyyperbridgeEnveloppe = await lastValueFrom(order); } catch (error) { - throw new HyyyperbridgeRabbitmqException(error); + throw new HyyyperbridgeRabbitmqException(error as Error); } const hyyyperbridgeEnveloppe = plainToInstance< @@ -191,7 +191,7 @@ export class OidcClientService { const updatedOptions = { ...options, headers: { - ...options.headers, + ...options!.headers, "accept-encoding": "identity", }, }; @@ -243,11 +243,11 @@ export class OidcClientService { config[customFetch] = this.fetch.bind( this, enableHyyyperbridge && idp.useTheHyyyperbridge, - ); + ) as any; } else { try { config = await discovery( - new URL(idp.discoveryUrl), + new URL(idp.discoveryUrl!), idp.federationClientMetadata.client_id, idp.federationClientMetadata, ClientSecretPost(idp.federationClientMetadata.client_secret), @@ -256,20 +256,21 @@ export class OidcClientService { [customFetch]: this.fetch.bind( this, enableHyyyperbridge && idp.useTheHyyyperbridge, - ), + ) as any, }, ); } catch (error) { - if (error.cause instanceof Response) { + const _err = error as any; + if (_err.cause instanceof Response) { /* istanbul ignore next */ - const body = await error.cause.text().catch(() => "unreadable body"); + const body = await _err.cause.text().catch(() => "unreadable body"); this.logger.error({ code: "oidc-client-discovery-http-error", reponseError: { - status: error.cause.status, - statusText: error.cause.statusText, - headers: Object.fromEntries(error.cause.headers?.entries()), - url: error.cause.url, + status: _err.cause.status, + statusText: _err.cause.statusText, + headers: Object.fromEntries(_err.cause.headers?.entries()), + url: _err.cause.url, body, }, }); @@ -277,7 +278,7 @@ export class OidcClientService { const errorParams = this.getOidcClientErrorParams(); throw new OidcClientIssuerDiscoveryFailedException( { ...errorParams, contactEmail: idp.supportEmail, idpName: idp.name }, - error, + error as Error, ); } } @@ -363,16 +364,17 @@ export class OidcClientService { { sp_id: spId, sp_name: spName }, ); } catch (error) { - if (error.cause instanceof Response) { + const _err = error as any; + if (_err.cause instanceof Response) { /* istanbul ignore next */ - const body = await error.cause.text().catch(() => "unreadable body"); + const body = await _err.cause.text().catch(() => "unreadable body"); this.logger.error({ code: "oidc-client-token-http-error", reponseError: { - status: error.cause.status, - statusText: error.cause.statusText, - headers: Object.fromEntries(error.cause.headers?.entries()), - url: error.cause.url, + status: _err.cause.status, + statusText: _err.cause.statusText, + headers: Object.fromEntries(_err.cause.headers?.entries()), + url: _err.cause.url, body, }, }); @@ -390,11 +392,11 @@ export class OidcClientService { throw new OidcClientTokenFailedException( { contactEmail: idp.supportEmail, idpName: idp.name }, - error, + error as Error, ); } - const claims = tokens.claims(); + const claims = tokens.claims()!; this.logger.info({ code: `oidc-client-info:get-token`, @@ -425,7 +427,8 @@ export class OidcClientService { // and map them to equivalent eidas levels const proConnectAcrs = map( token.claims.acrs, - (level) => this.entraIdAcrValuesMapping[level], + (level) => + (this.entraIdAcrValuesMapping as Record)[level], ).filter(Boolean); const proConnectHighestAcr = this.prioritizedAcrValues.find((level) => proConnectAcrs.includes(level), @@ -472,23 +475,24 @@ export class OidcClientService { return plainIdpIdentity; } catch (error) { - if (error.cause instanceof Response) { + const _err = error as any; + if (_err.cause instanceof Response) { /* istanbul ignore next */ - const body = await error.cause.text().catch(() => "unreadable body"); + const body = await _err.cause.text().catch(() => "unreadable body"); this.logger.error({ code: "oidc-client-userinfo-http-error", reponseError: { - status: error.cause.status, - statusText: error.cause.statusText, - headers: Object.fromEntries(error.cause.headers?.entries()), - url: error.cause.url, + status: _err.cause.status, + statusText: _err.cause.statusText, + headers: Object.fromEntries(_err.cause.headers?.entries()), + url: _err.cause.url, body, }, }); } throw new OidcClientUserinfoFailedException( { contactEmail: idp.supportEmail, idpName: idp.name }, - error, + error as Error, ); } } diff --git a/back/libs/oidc-provider/src/oidc-provider.service.ts b/back/libs/oidc-provider/src/oidc-provider.service.ts index 65b7bfc7d..92bb3e057 100644 --- a/back/libs/oidc-provider/src/oidc-provider.service.ts +++ b/back/libs/oidc-provider/src/oidc-provider.service.ts @@ -30,9 +30,9 @@ export const COOKIES = ["_session", "_interaction", "_interaction_resume"]; @Injectable() export class OidcProviderService { private ProviderProxy = Provider; - private provider: Provider; - private callback: ReturnType; - private configuration; + private provider!: Provider; + private callback!: ReturnType; + private configuration: any; constructor( readonly logger: LoggerService, @@ -53,7 +53,7 @@ export class OidcProviderService { try { this.provider = new this.ProviderProxy(issuer, { ...configuration, - httpOptions: this.getHttpOptions.bind(this), + httpOptions: this.getHttpOptions.bind(this) as any, }); this.provider.proxy = true; this.callback = this.provider.callback(); @@ -130,7 +130,7 @@ export class OidcProviderService { return options; } - async getInteraction(req, res): Promise { + async getInteraction(req: any, res: any): Promise { const interactionDetails = await this.provider.interactionDetails(req, res); return interactionDetails as ExtendedInteraction; @@ -143,20 +143,20 @@ export class OidcProviderService { amr, acr, }: { - amr: InteractionResults["login"]["amr"]; - acr: InteractionResults["login"]["acr"]; + amr: NonNullable["amr"]; + acr: NonNullable["acr"]; }, ) { const { spIdentity } = this.sessionService.get("User"); const sessionId = this.sessionService.getId(); - await this.sessionService.setAlias(spIdentity.sub, sessionId); + await this.sessionService.setAlias(spIdentity!.sub, sessionId); const result = { login: { amr, acr, - accountId: spIdentity.sub, + accountId: spIdentity!.sub, ts: Math.floor(Date.now() / 1000), remember: false, }, @@ -183,7 +183,12 @@ export class OidcProviderService { } private async runMiddlewareBeforePattern( - { step, path, pattern, ctx }, + { + step, + path, + pattern, + ctx, + }: { step: any; path: any; pattern: any; ctx: any }, middleware: Function, ) { // run middleware BEFORE pattern occurs @@ -193,7 +198,13 @@ export class OidcProviderService { } private async runMiddlewareAfterPattern( - { step, route, path, pattern, ctx }, + { + step, + route, + path, + pattern, + ctx, + }: { step: any; route: any; path: any; pattern: any; ctx: any }, middleware: Function, ) { // run middleware AFTER pattern occurred @@ -205,7 +216,17 @@ export class OidcProviderService { } } - private shouldRunAfterPattern({ step, route, path, pattern }) { + private shouldRunAfterPattern({ + step, + route, + path, + pattern, + }: { + step: any; + route: any; + path: any; + pattern: any; + }) { return ( step === OidcProviderMiddlewareStep.AFTER && /** @@ -220,7 +241,7 @@ export class OidcProviderService { ); } - private isInError(ctx) { + private isInError(ctx: any) { return ctx["oidc"]?.isError === true; } diff --git a/back/libs/oidc-provider/src/services/oidc-provider-config.service.ts b/back/libs/oidc-provider/src/services/oidc-provider-config.service.ts index 893754aeb..b602c0421 100644 --- a/back/libs/oidc-provider/src/services/oidc-provider-config.service.ts +++ b/back/libs/oidc-provider/src/services/oidc-provider-config.service.ts @@ -241,9 +241,10 @@ export class OidcProviderConfigService { return grant; }; - logoutSource: Configuration["features"]["rpInitiatedLogout"]["logoutSource"] = - (ctx, form) => { - ctx.body = ` + logoutSource: NonNullable< + NonNullable["rpInitiatedLogout"] + >["logoutSource"] = (ctx: any, form: any) => { + ctx.body = ` Déconnexion @@ -260,44 +261,45 @@ export class OidcProviderConfigService { `; - }; + }; - postLogoutSuccessSource: Configuration["features"]["rpInitiatedLogout"]["postLogoutSuccessSource"] = - (ctx) => { - // This line magically avoids error 500: ERR_HTTP_HEADERS_SENT - // TODO investigate why. - ctx.body = ""; + postLogoutSuccessSource: NonNullable< + NonNullable["rpInitiatedLogout"] + >["postLogoutSuccessSource"] = (ctx: any) => { + // This line magically avoids error 500: ERR_HTTP_HEADERS_SENT + // TODO investigate why. + ctx.body = ""; - const res = ctx.res as unknown as Response; - ctx.type = "html"; - // the render function is magically available in the koa context - // as oidc-provider servers is mounted behind the nest server. - const errorPageParams: ErrorPageParams = { - exceptionDisplay: { - title: "Déconnexion", - description: - "Vous êtes bien déconnecté, vous pouvez fermer votre navigateur.", - illustration: "connexion", - }, - error: {}, - }; - ctx.body = res.render("error", errorPageParams); + const res = ctx.res as unknown as Response; + ctx.type = "html"; + // the render function is magically available in the koa context + // as oidc-provider servers is mounted behind the nest server. + const errorPageParams: ErrorPageParams = { + exceptionDisplay: { + title: "Déconnexion", + description: + "Vous êtes bien déconnecté, vous pouvez fermer votre navigateur.", + illustration: "connexion", + }, + error: {}, }; + ctx.body = res.render("error", errorPageParams); + }; findAccount: Configuration["findAccount"] = async ( _ctx: KoaContextWithOIDC, sub: string, ) => { const sessionId = await this.sessionService.getAlias(sub); - await this.sessionService.initCache(sessionId); + await this.sessionService.initCache(sessionId!); const { spIdentity } = this.sessionService.get("User"); return { - accountId: spIdentity.sub, + accountId: spIdentity!.sub, async claims() { - return { ...spIdentity }; + return { sub: spIdentity!.sub, ...spIdentity } as any; }, }; }; From 3f64fd62e1d78ae96909342c7ace907e69d79a38 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 16:33:51 +0200 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=90=9B=20(back):=20remaining=20ts=20s?= =?UTF-8?q?trict=20type=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Batch all remaining strict-mode compat fixes across apps and libs: null/undefined type casts, non-null assertions, parameter types, schema property assertions, optional chain narrowing, glob migration. --- .../src/controllers/oidc-client.controller.ts | 2 +- .../src/decorators/user-session.decorator.ts | 6 +-- ...core-fca-invalid-email-domain.exception.ts | 2 +- .../services/core-fca-controller.service.ts | 2 +- .../src/services/core-fca.service.ts | 4 +- .../src/services/identity.sanitizer.spec.ts | 16 +++---- back/apps/csmr-rie/src/config/app.ts | 4 +- back/apps/csmr-rie/src/config/rie-broker.ts | 4 +- .../src/dto/csmr-http-proxy.config.ts | 6 +-- back/apps/mock-data-provider/src/main.ts | 14 +++--- .../src/main.ts | 4 +- .../oidc-provider-support/configuration.ts | 13 +++--- .../src/user-data.ts | 2 +- .../src/decrypt.ts | 2 +- .../mock-service-provider-fca-low/src/main.ts | 31 ++++++------- .../src/schemas/account-fca.schema.ts | 18 ++++---- .../src/dto/api-entreprise.config.ts | 10 ++--- .../src/async-local-storage.service.spec.ts | 4 +- .../src/async-local-storage.service.ts | 4 +- .../async-local-storage.middleware.spec.ts | 4 +- .../async-local-storage.middleware.ts | 4 +- .../src/schemas/cached-organization.schema.ts | 37 +++++++++------- .../libs/common/src/helpers/dto-validation.ts | 2 +- back/libs/common/src/helpers/parse-boolean.ts | 5 ++- .../common/src/helpers/parse-json-property.ts | 4 +- .../src/cli/export-env/markdown-generator.ts | 21 ++++++--- .../config/src/cli/export-env/runner.spec.ts | 11 +++-- back/libs/config/src/cli/export-env/runner.ts | 18 +++++--- back/libs/config/src/config.service.spec.ts | 8 ++-- .../src/cryptography.service.spec.ts | 18 ++++---- .../cryptography/src/cryptography.service.ts | 6 ++- .../src/dto/cryptography-config.ts | 2 +- .../src/services/email-validator.service.ts | 9 +--- .../src/cli/export-exceptions/runner.spec.ts | 11 +++-- .../src/cli/export-exceptions/runner.ts | 29 ++++++------ .../src/exceptions/base.exception.ts | 4 +- .../enriched-display-base.exception.ts | 2 +- .../filters/fc-web-html-exception.filter.ts | 4 +- .../src/filters/http-exception.filter.ts | 3 +- .../helpers/exception-display.helper.spec.ts | 6 ++- .../identity-provider-adapter-mongo-config.ts | 4 +- ...dentity-provider-adapter-mongo.dto.spec.ts | 2 +- ...ity-provider-adapter-mongo.service.spec.ts | 4 +- ...identity-provider-adapter-mongo.service.ts | 16 ++++--- .../identity-provider-adapter-mongo.schema.ts | 44 +++++++++---------- .../src/services/logger-session.service.ts | 6 +-- back/libs/logger/src/logger.module.ts | 2 +- .../logger/src/services/logger.service.ts | 28 ++++++------ .../mongoose/src/mongoose.module.e2e.spec.ts | 6 +-- back/libs/mongoose/src/mongoose.module.ts | 9 ++-- .../src/providers/mongoose.provider.spec.ts | 2 +- .../oidc-acr/src/oidc-acr.service.spec.ts | 10 ++--- back/libs/oidc-acr/src/oidc-acr.service.ts | 6 +-- .../hyyyperbridge-csmr.exception.ts | 12 ++--- .../oidc-provider-redis-adapter.spec.ts | 7 ++- .../adapters/oidc-provider-redis.adapter.ts | 41 +++++++++-------- .../src/oidc-provider.service.spec.ts | 8 ++-- .../oidc-provider-config.service.spec.ts | 14 +++--- back/libs/rabbitmq/src/dto/rabbitmq.config.ts | 8 ++-- .../libs/rabbitmq/src/rabbitmq.module.spec.ts | 6 +-- back/libs/redis/src/dto/redis.config.ts | 22 +++++----- back/libs/redis/src/services/redis.service.ts | 2 +- .../service-provider-adapter-mongo.schema.ts | 24 +++++----- ...ice-provider-adapter-mongo.service.spec.ts | 16 +++---- .../service-provider-adapter-mongo.service.ts | 12 ++--- back/libs/session/src/dto/session.config.ts | 30 ++++++------- .../session-commit.interceptor.ts | 4 +- .../session-backend-storage.service.spec.ts | 2 +- .../session-backend-storage.service.ts | 9 ++-- .../src/services/session-lifecycle.service.ts | 2 +- .../services/session-local-storage.service.ts | 10 +++-- .../session/src/services/session.service.ts | 2 +- back/tsconfig.json | 2 + 73 files changed, 397 insertions(+), 331 deletions(-) diff --git a/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts b/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts index f93dd969a..8882cbfde 100644 --- a/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts +++ b/back/apps/core-fca-low/src/controllers/oidc-client.controller.ts @@ -17,7 +17,7 @@ import { UsePipes, ValidationPipe, } from "@nestjs/common"; -import { type Request, type Response } from "express"; +import type { Request, Response } from "express"; import { isEmpty } from "lodash"; import { UserSessionDecorator } from "../decorators"; import { diff --git a/back/apps/core-fca-low/src/decorators/user-session.decorator.ts b/back/apps/core-fca-low/src/decorators/user-session.decorator.ts index de827c306..49cdc184d 100644 --- a/back/apps/core-fca-low/src/decorators/user-session.decorator.ts +++ b/back/apps/core-fca-low/src/decorators/user-session.decorator.ts @@ -18,7 +18,7 @@ export const UserSessionDecoratorFactory = async ( const res = ctx.switchToHttp().getResponse(); const boundSessionService = { - get: sessionService.get.bind(sessionService, "User"), + get: (() => sessionService.get("User")) as () => UserSession, set: sessionService.set.bind(sessionService, "User"), commit: sessionService.commit.bind(sessionService), duplicate: () => { @@ -26,12 +26,12 @@ export const UserSessionDecoratorFactory = async ( const cleanedData = plainToInstance(CoreFcaSession, data, { excludeExtraneousValues: true, }); - sessionService.set.bind(sessionService, cleanedData); + sessionService.set.bind(sessionService, cleanedData as unknown as string); return sessionService.duplicate.bind(sessionService, res)(); }, clear: sessionService.clear.bind(sessionService), destroy: sessionService.destroy.bind(sessionService, res), - } as ISessionService; + } as unknown as ISessionService; const sessionData = boundSessionService.get(); diff --git a/back/apps/core-fca-low/src/exceptions/core-fca-invalid-email-domain.exception.ts b/back/apps/core-fca-low/src/exceptions/core-fca-invalid-email-domain.exception.ts index 49ef37250..e086afeda 100644 --- a/back/apps/core-fca-low/src/exceptions/core-fca-invalid-email-domain.exception.ts +++ b/back/apps/core-fca-low/src/exceptions/core-fca-invalid-email-domain.exception.ts @@ -15,7 +15,7 @@ export class CoreFcaInvalidEmailDomainException extends CoreFcaBaseException { constructor(idpName: string, email: string, contact: string) { super(); - const emailDomain = email?.split("@").pop().toLowerCase(); + const emailDomain = email?.split("@").pop()!.toLowerCase(); this.description = `Le domaine « ${emailDomain} » que vous utilisez ne fait pas partie des domaines autorisés pour ${idpName}.`; diff --git a/back/apps/core-fca-low/src/services/core-fca-controller.service.ts b/back/apps/core-fca-low/src/services/core-fca-controller.service.ts index a0cc11fc0..ef512a0dc 100644 --- a/back/apps/core-fca-low/src/services/core-fca-controller.service.ts +++ b/back/apps/core-fca-low/src/services/core-fca-controller.service.ts @@ -61,7 +61,7 @@ export class CoreFcaControllerService { this.logger.warn({ code: "email_not_safe_to_send", emailSuggestion: suggestion, - emailSuggestionFqdn: suggestion?.split("@").pop().toLowerCase(), + emailSuggestionFqdn: suggestion?.split("@").pop()!.toLowerCase(), }); return res.redirect(url); } diff --git a/back/apps/core-fca-low/src/services/core-fca.service.ts b/back/apps/core-fca-low/src/services/core-fca.service.ts index 975014aa8..0d3c89359 100644 --- a/back/apps/core-fca-low/src/services/core-fca.service.ts +++ b/back/apps/core-fca-low/src/services/core-fca.service.ts @@ -81,10 +81,10 @@ export class CoreFcaService { async ensureIdpCanServeThisEmail( idpId: string, email: string, - ): Promise { + ): Promise { const identityProvider = await this.identityProvider.getById(idpId); - const emailFqdn = this.identityProvider.getFqdnFromEmail(email); + const emailFqdn = this.identityProvider.getFqdnFromEmail(email)!; if (identityProvider.fqdns?.includes(emailFqdn)) { return; diff --git a/back/apps/core-fca-low/src/services/identity.sanitizer.spec.ts b/back/apps/core-fca-low/src/services/identity.sanitizer.spec.ts index a800115aa..f462f03c1 100644 --- a/back/apps/core-fca-low/src/services/identity.sanitizer.spec.ts +++ b/back/apps/core-fca-low/src/services/identity.sanitizer.spec.ts @@ -24,17 +24,17 @@ describe("IdentitySanitizer", () => { beforeEach(() => { identityProvider = new IdentityProviderAdapterMongoService( - null, - null, - null, + null as any, + null as any, + null as any, logger, - null, + null as any, ); cachedOrganizationService = new CachedOrganizationService( - null, - null, - null, - null, + null as any, + null as any, + null as any, + null as any, ); cachedOrganizationService.computeRoles = jest.fn(); cachedOrganizationService.getCachedOrganizationBySiret = jest.fn(); diff --git a/back/apps/csmr-rie/src/config/app.ts b/back/apps/csmr-rie/src/config/app.ts index e2b39d052..ba283a88f 100644 --- a/back/apps/csmr-rie/src/config/app.ts +++ b/back/apps/csmr-rie/src/config/app.ts @@ -1,7 +1,9 @@ import { AppRmqConfig } from "@fc/app"; +import { ConfigParser } from "@fc/config"; +const env = new ConfigParser(process.env, "APP"); const appRmqConfig: AppRmqConfig = { - name: process.env.APP_NAME, + name: env.string("NAME"), }; export default appRmqConfig; diff --git a/back/apps/csmr-rie/src/config/rie-broker.ts b/back/apps/csmr-rie/src/config/rie-broker.ts index e19450392..0714bf3d9 100644 --- a/back/apps/csmr-rie/src/config/rie-broker.ts +++ b/back/apps/csmr-rie/src/config/rie-broker.ts @@ -5,14 +5,14 @@ const env = new ConfigParser(process.env, "RieBroker"); const rieBrokerConfig: RabbitmqConfig = { urls: env.json("URLS"), - queue: env.string("QUEUE"), + queue: env.string("QUEUE")!, queueOptions: { durable: true, }, payloadEncoding: "base64", // Global request timeout used for any outgoing app requests. - requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10), + requestTimeout: parseInt(process.env.REQUEST_TIMEOUT!, 10), }; export default rieBrokerConfig; diff --git a/back/apps/csmr-rie/src/dto/csmr-http-proxy.config.ts b/back/apps/csmr-rie/src/dto/csmr-http-proxy.config.ts index 3ada6cf23..d2550589a 100644 --- a/back/apps/csmr-rie/src/dto/csmr-http-proxy.config.ts +++ b/back/apps/csmr-rie/src/dto/csmr-http-proxy.config.ts @@ -8,15 +8,15 @@ export class CsmrHttpProxyConfig { @IsObject() @ValidateNested() @Type(() => AppRmqConfig) - readonly App: AppRmqConfig; + readonly App!: AppRmqConfig; @IsObject() @ValidateNested() @Type(() => LoggerConfig) - readonly Logger: LoggerConfig; + readonly Logger!: LoggerConfig; @IsObject() @ValidateNested() @Type(() => RabbitmqConfig) - readonly HttpProxyBroker: RabbitmqConfig; + readonly HttpProxyBroker!: RabbitmqConfig; } diff --git a/back/apps/mock-data-provider/src/main.ts b/back/apps/mock-data-provider/src/main.ts index 48ced29bb..462787b47 100644 --- a/back/apps/mock-data-provider/src/main.ts +++ b/back/apps/mock-data-provider/src/main.ts @@ -15,7 +15,7 @@ const { PORT, } = process.env; -const port = parseInt(PORT, 10) || 3000; +const port = parseInt(PORT!, 10) || 3000; const jwks: JWK[] = rawJwks ? JSON.parse(rawJwks) : []; let keys: CryptoKey[]; let publicJwks: JsonWebKey[]; @@ -24,15 +24,15 @@ const app = express(); const getProviderConfig = async () => { const config = await client.discovery( - new URL(DataProviderAdapterCore_ISSUER), - DataProviderAdapterCore_CLIENT_ID, + new URL(DataProviderAdapterCore_ISSUER!), + DataProviderAdapterCore_CLIENT_ID!, { introspection_signed_response_alg: signAlg, }, - client.ClientSecretPost(DataProviderAdapterCore_CLIENT_SECRET), + client.ClientSecretPost(DataProviderAdapterCore_CLIENT_SECRET!), ); - client.enableDecryptingResponses(config, [encryptEnc], ...keys); + client.enableDecryptingResponses(config, [encryptEnc!], ...keys); return config; }; @@ -43,7 +43,7 @@ app.get("/api/v1/jwks", (req, res, _next) => { app.get("/api/v1/data", async (req, res, next) => { try { const authorizationHeader = req.headers.authorization; - const rawAccessToken = authorizationHeader.split(" ")[1]; + const rawAccessToken = authorizationHeader!.split(" ")[1]; const accessToken = Buffer.from(rawAccessToken, "base64").toString("utf-8"); const config = await getProviderConfig(); @@ -66,7 +66,7 @@ app.use((req, res, _next) => { }); }); -app.use((err, req, res, _next) => { +app.use((err: any, req: any, res: any, _next: any) => { console.error(err); res.status(err.status || 500).json({ diff --git a/back/apps/mock-identity-provider-fca-low/src/main.ts b/back/apps/mock-identity-provider-fca-low/src/main.ts index 34799261a..22a25305a 100644 --- a/back/apps/mock-identity-provider-fca-low/src/main.ts +++ b/back/apps/mock-identity-provider-fca-low/src/main.ts @@ -2,8 +2,10 @@ import express, { urlencoded } from "express"; import { get } from "lodash"; import { strict as assert } from "node:assert"; import path from "node:path"; +// @ts-expect-error import Provider from "oidc-provider-v8"; import configuration from "./oidc-provider-support/configuration"; +// @ts-expect-error import MemoryAdapter from "./oidc-provider-support/memory_adapter.js"; import { createUser, getDefaultUser, parseFormDataValue } from "./user-data"; @@ -69,7 +71,7 @@ app.get("/interaction/:uid", async (req, res, next) => { } }); -async function normalLogin(req, res) { +async function normalLogin(req: any, res: any) { const { prompt: { name }, } = await provider.interactionDetails(req, res); diff --git a/back/apps/mock-identity-provider-fca-low/src/oidc-provider-support/configuration.ts b/back/apps/mock-identity-provider-fca-low/src/oidc-provider-support/configuration.ts index 1bdfea9a2..39adbd0f0 100644 --- a/back/apps/mock-identity-provider-fca-low/src/oidc-provider-support/configuration.ts +++ b/back/apps/mock-identity-provider-fca-low/src/oidc-provider-support/configuration.ts @@ -1,3 +1,4 @@ +// @ts-expect-error import policy from "../oidc-provider-support/policy"; import { findUserById } from "../user-data"; @@ -54,8 +55,8 @@ export default { { client_id, client_secret, - redirect_uris: JSON.parse(stringifiedRedirectUris), - post_logout_redirect_uris: JSON.parse(stringifiedPostLogoutRedirectUris), + redirect_uris: JSON.parse(stringifiedRedirectUris!), + post_logout_redirect_uris: JSON.parse(stringifiedPostLogoutRedirectUris!), scope, id_token_signed_response_alg, userinfo_signed_response_alg, @@ -84,7 +85,7 @@ export default { rpInitiatedLogout: { enabled: true, // disable logout confirmation screen - logoutSource: (ctx, form) => { + logoutSource: (ctx: any, form: any) => { const csrfToken = /name="xsrf" value="([a-f0-9]*)"/.exec(form)![1]; ctx.type = "html"; @@ -99,7 +100,7 @@ export default { }, }, }, - findAccount: (_ctx, id) => { + findAccount: (_ctx: any, id: any) => { const user = findUserById(id); return { @@ -108,7 +109,7 @@ export default { }; }, interactions: { - url(_ctx, interaction) { + url(_ctx: any, interaction: any) { return `/interaction/${interaction.uid}`; }, policy, @@ -137,7 +138,7 @@ export default { }, ], }, - loadExistingGrant: async (ctx) => { + loadExistingGrant: async (ctx: any) => { // We want to skip the consent // inspired from https://github.com/panva/node-oidc-provider/blob/main/recipes/skip_consent.md // We updated the function to ensure it always return a grant. diff --git a/back/apps/mock-identity-provider-fca-low/src/user-data.ts b/back/apps/mock-identity-provider-fca-low/src/user-data.ts index 41c81cf2f..cb705503c 100644 --- a/back/apps/mock-identity-provider-fca-low/src/user-data.ts +++ b/back/apps/mock-identity-provider-fca-low/src/user-data.ts @@ -49,7 +49,7 @@ export const getDefaultUser = () => { const userStorage = new QuickLRU({ maxSize: 1000 }); -export const createUser = (body) => { +export const createUser = (body: any) => { const { email, given_name, usual_name, siret, sub, phone_number } = body; const id = email + given_name + usual_name + siret + phone_number; // replace default property values, allowing substitution of a default value with an empty string diff --git a/back/apps/mock-service-provider-fca-low/src/decrypt.ts b/back/apps/mock-service-provider-fca-low/src/decrypt.ts index 4aa47fd66..e463dd1e2 100644 --- a/back/apps/mock-service-provider-fca-low/src/decrypt.ts +++ b/back/apps/mock-service-provider-fca-low/src/decrypt.ts @@ -22,7 +22,7 @@ export const decrypt = (cipher: string, cipherPass: string): any => { decipher.setAuthTag(tag); - const receivedPlaintext = decipher.update(ciphertext, null, "utf8"); + const receivedPlaintext = decipher.update(ciphertext, null as any, "utf8"); try { decipher.final(); diff --git a/back/apps/mock-service-provider-fca-low/src/main.ts b/back/apps/mock-service-provider-fca-low/src/main.ts index 3bfe5d15d..ff5985482 100644 --- a/back/apps/mock-service-provider-fca-low/src/main.ts +++ b/back/apps/mock-service-provider-fca-low/src/main.ts @@ -21,15 +21,15 @@ declare module "express-session" { } const HOST = `https://${process.env.FQDN}`; -const PORT = parseInt(process.env.PORT, 10) || 3000; +const PORT = parseInt(process.env.PORT!, 10) || 3000; const SITE_TITLE = process.env.APP_NAME; const STYLESHEET_URL = process.env.STYLESHEET_URL || "https://unpkg.com/bamboo.css"; const CALLBACK_URL = "/oidc-callback"; const PC_CLIENT_ID = process.env.IdentityProviderAdapterEnv_CLIENT_ID; const PC_CLIENT_SECRET = decrypt( - process.env.IdentityProviderAdapterEnv_CLIENT_SECRET, - process.env.IdentityProviderAdapterEnv_CLIENT_SECRET_CIPHER_PASS, + process.env.IdentityProviderAdapterEnv_CLIENT_SECRET!, + process.env.IdentityProviderAdapterEnv_CLIENT_SECRET_CIPHER_PASS!, ); const PC_PROVIDER = process.env.IdentityProviderAdapterEnv_DISCOVERY_URL; const PC_SCOPES = @@ -40,7 +40,7 @@ const PC_ID_TOKEN_SIGNED_RESPONSE_ALG = const PC_USERINFO_SIGNED_RESPONSE_ALG = process.env.IdentityProviderAdapterEnv_USERINFO_SIGNED_RESPONSE_ALG; const dataProviderConfigs: { name: string; url: string }[] = JSON.parse( - process.env.App_DATA_APIS, + process.env.App_DATA_APIS!, ); const ACR_VALUES_FOR_2FA = process.env.ACR_VALUES_FOR_2FA || @@ -59,7 +59,7 @@ app.use( ); app.enable("trust proxy"); -const objToUrlParams = (obj) => +const objToUrlParams = (obj: any) => new URLSearchParams( chain(obj) .omitBy((v) => !v) @@ -67,16 +67,17 @@ const objToUrlParams = (obj) => .value(), ); -const getCurrentUrl = (req) => +const getCurrentUrl = (req: any) => new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`); const getProviderConfig = async () => { const config = await client.discovery( - new URL(PC_PROVIDER), - PC_CLIENT_ID, + new URL(PC_PROVIDER!), + PC_CLIENT_ID!, { id_token_signed_response_alg: PC_ID_TOKEN_SIGNED_RESPONSE_ALG, - userinfo_signed_response_alg: PC_USERINFO_SIGNED_RESPONSE_ALG || null, + userinfo_signed_response_alg: + PC_USERINFO_SIGNED_RESPONSE_ALG || undefined, }, client.ClientSecretPost(PC_CLIENT_SECRET), ); @@ -111,7 +112,7 @@ app.get("/", (req, res, next) => { }); const getAuthorizationControllerFactory = (extraParams: any = {}) => { - return async (req, res, next) => { + return async (req: any, res: any, next: any) => { try { const config = await getProviderConfig(); const nonce = client.randomNonce(); @@ -170,10 +171,10 @@ app.get(CALLBACK_URL, async (req, res, next) => { pkceCodeVerifier: req.session.code_verifier, }); - req.session.nonce = null; - req.session.state = null; - req.session.code_verifier = null; - const claims = tokens.claims(); + req.session.nonce = undefined; + req.session.state = undefined; + req.session.code_verifier = undefined; + const claims = tokens.claims()!; req.session.userinfo = await client.fetchUserInfo( config, tokens.access_token, @@ -199,7 +200,7 @@ app.post( const config = await getProviderConfig(); const paramObject = { id_token_hint, - post_logout_redirect_uri: null, + post_logout_redirect_uri: null as string | null, }; if (req.body?.no_redirect !== "true") { paramObject.post_logout_redirect_uri = `${HOST}/`; diff --git a/back/libs/account-fca/src/schemas/account-fca.schema.ts b/back/libs/account-fca/src/schemas/account-fca.schema.ts index 66e96ef53..0ccba1306 100644 --- a/back/libs/account-fca/src/schemas/account-fca.schema.ts +++ b/back/libs/account-fca/src/schemas/account-fca.schema.ts @@ -8,13 +8,13 @@ import { v4 as uuid } from "uuid"; }) class IdpIdentityKey { @Prop({ type: String }) - idpSub: string; + idpSub!: string; @Prop({ type: String }) - idpUid: string; + idpUid!: string; @Prop({ type: String }) - idpMail: string; + idpMail!: string; } @Schema({ @@ -27,22 +27,22 @@ export class AccountFca extends Document { * Timestamping */ @Prop({ type: Date, default: Date.now }) - createdAt: Date; + createdAt!: Date; @Prop({ type: String, default: uuid }) declare id: string; @Prop({ type: Date, default: Date.now }) - updatedAt: Date; + updatedAt!: Date; @Prop({ type: Date, default: Date.now }) - lastConnection: Date; + lastConnection!: Date; /** * Unique sub generated from uuid */ @Prop({ type: String, unique: true }) - sub: string; + sub!: string; /** * List of identity keys for each associtated idp @@ -51,13 +51,13 @@ export class AccountFca extends Document { @Prop({ type: [IdpIdentityKey], }) - idpIdentityKeys: IdpIdentityKey[]; + idpIdentityKeys!: IdpIdentityKey[]; /** * Active === true means it is not blocked by AC */ @Prop({ type: Boolean, default: true }) - active: boolean; + active!: boolean; } const AccountFcaSchema = SchemaFactory.createForClass(AccountFca); diff --git a/back/libs/api-entreprise/src/dto/api-entreprise.config.ts b/back/libs/api-entreprise/src/dto/api-entreprise.config.ts index 97fa67ca1..69fd03ca8 100644 --- a/back/libs/api-entreprise/src/dto/api-entreprise.config.ts +++ b/back/libs/api-entreprise/src/dto/api-entreprise.config.ts @@ -2,21 +2,21 @@ import { IsBoolean, IsNumber, IsOptional, IsString } from "class-validator"; export class ApiEntrepriseConfig { @IsString() - readonly token: string; + readonly token!: string; @IsString() - readonly baseUrl: string; + readonly baseUrl!: string; @IsBoolean() @IsOptional() readonly shouldMockApi?: boolean; @IsBoolean() - readonly featureFetchOrganizationData: boolean; + readonly featureFetchOrganizationData!: boolean; @IsString() - readonly organizationSiret: string; + readonly organizationSiret!: string; @IsNumber() - readonly cachedTTL: number; + readonly cachedTTL!: number; } diff --git a/back/libs/async-local-storage/src/async-local-storage.service.spec.ts b/back/libs/async-local-storage/src/async-local-storage.service.spec.ts index a0bde53b4..d55743f0c 100644 --- a/back/libs/async-local-storage/src/async-local-storage.service.spec.ts +++ b/back/libs/async-local-storage/src/async-local-storage.service.spec.ts @@ -73,7 +73,7 @@ describe("AsyncLocalStorageService", () => { describe("mandatory", () => { it("should throw an AsyncLocalStorageNotFoundException if the storage is not found", () => { // Given - service["storage"] = undefined; + service["storage"] = undefined as any; // When / Then expect(() => service.mandatory).toThrowError( @@ -192,7 +192,7 @@ describe("AsyncLocalStorageService", () => { it("should return undefined if the storage is not found", () => { // Given - service["storage"] = undefined; + service["storage"] = undefined as any; // When const result = service["getStore"](); diff --git a/back/libs/async-local-storage/src/async-local-storage.service.ts b/back/libs/async-local-storage/src/async-local-storage.service.ts index 843e4e0be..cc5c9abc6 100644 --- a/back/libs/async-local-storage/src/async-local-storage.service.ts +++ b/back/libs/async-local-storage/src/async-local-storage.service.ts @@ -8,7 +8,7 @@ import { AsyncLocalStorageNotFoundException } from "./exceptions"; * Providing T will enforce the type of the data we want to store even with the `any` type. */ export class AsyncLocalStorageService> { - private storage: AsyncLocalStorage>; + private storage!: AsyncLocalStorage>; onModuleInit() { this.storage = new AsyncLocalStorage>(); @@ -47,7 +47,7 @@ export class AsyncLocalStorageService> { set(key: K, value: T[K]) { const currentStore = this.storage.getStore(); - currentStore.set(key as string, value); + currentStore!.set(key as string, value); } private getStore(): Map | undefined { diff --git a/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.spec.ts b/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.spec.ts index 059e3d9f3..4c26cc0cb 100644 --- a/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.spec.ts +++ b/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.spec.ts @@ -45,7 +45,7 @@ describe("AsyncLocalStorageMiddleware", () => { it("should call asyncLocalStorage.run", () => { // When - middleware.use(reqMock as any, null, nextMock); + middleware.use(reqMock as any, null as any, nextMock); // Then expect(asyncLocalStorageMock.run).toHaveBeenCalledTimes(1); @@ -56,7 +56,7 @@ describe("AsyncLocalStorageMiddleware", () => { it("should call next", () => { // Given - middleware.use(reqMock, null, nextMock); + middleware.use(reqMock, null as any, nextMock); const runCallback = asyncLocalStorageMock.run.mock.calls[0][0]; // When diff --git a/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.ts b/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.ts index 74078a15d..e38c4c0e4 100644 --- a/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.ts +++ b/back/libs/async-local-storage/src/middlewares/async-local-storage.middleware.ts @@ -5,7 +5,9 @@ import { AsyncLocalStorageService } from "../async-local-storage.service"; @Injectable() export class AsyncLocalStorageMiddleware implements NestMiddleware { constructor( - private readonly asyncLocalStorage: AsyncLocalStorageService, + private readonly asyncLocalStorage: AsyncLocalStorageService< + Record + >, ) {} use(_req: Request, _res: Response, next: NextFunction) { diff --git a/back/libs/cached-organization/src/schemas/cached-organization.schema.ts b/back/libs/cached-organization/src/schemas/cached-organization.schema.ts index 15eaa6048..ecaeb53c1 100644 --- a/back/libs/cached-organization/src/schemas/cached-organization.schema.ts +++ b/back/libs/cached-organization/src/schemas/cached-organization.schema.ts @@ -8,52 +8,55 @@ import { Document } from "mongoose"; }) export class CachedOrganization extends Document { @Prop({ type: String, unique: true, index: true }) - siret: string; + siret!: string; @Prop({ type: String }) - activitePrincipale: string; + activitePrincipale!: string; @Prop({ type: String }) - adresse: string; + adresse!: string; @Prop({ type: String }) - categorieJuridique: string; + categorieJuridique!: string; @Prop({ type: String }) - codeOfficielGeographique: string; + codeOfficielGeographique!: string; @Prop({ type: String }) - enseigne: string; + enseigne!: string; @Prop({ type: Boolean }) - estActive: boolean; + estActive!: boolean; @Prop({ type: Boolean }) - estDiffusible: boolean; + estDiffusible!: boolean; @Prop({ type: String }) - etatAdministratif: string; + etatAdministratif!: string; @Prop({ type: String }) - libelle: string; + libelle!: string; @Prop({ type: String }) - libelleActivitePrincipale: string; + libelleActivitePrincipale!: string; @Prop({ type: String }) - libelleCategorieJuridique: string; + libelleCategorieJuridique!: string; @Prop({ type: String }) - libelleTrancheEffectif: string; + libelleTrancheEffectif!: string; @Prop({ type: String }) - nomComplet: string; + nomComplet!: string; @Prop({ type: Boolean }) - siegeSocial: boolean; + siegeSocial!: boolean; @Prop({ type: String }) - statutDiffusion: "partiellement_diffusible" | "diffusible" | "non_diffusible"; + statutDiffusion!: + | "partiellement_diffusible" + | "diffusible" + | "non_diffusible"; @Prop({ type: String }) codePostal?: string; @@ -65,7 +68,7 @@ export class CachedOrganization extends Document { trancheEffectifsUniteLegale?: string; @Prop({ type: Date }) - updatedAt: Date; + updatedAt!: Date; } const CachedOrganizationSchema = diff --git a/back/libs/common/src/helpers/dto-validation.ts b/back/libs/common/src/helpers/dto-validation.ts index ed095e053..9b5ba5b97 100644 --- a/back/libs/common/src/helpers/dto-validation.ts +++ b/back/libs/common/src/helpers/dto-validation.ts @@ -84,7 +84,7 @@ export async function filteredByDto( const data = getTransformed(plain, dto, transformOptions); const errors = await validate(data, validatorOptions); if (errors.length) { - return { errors, result: null }; + return { errors, result: null as unknown as T }; } const result = instanceToPlain(data) as T; return { errors, result }; diff --git a/back/libs/common/src/helpers/parse-boolean.ts b/back/libs/common/src/helpers/parse-boolean.ts index 35af151ed..ae78722dd 100644 --- a/back/libs/common/src/helpers/parse-boolean.ts +++ b/back/libs/common/src/helpers/parse-boolean.ts @@ -13,8 +13,11 @@ const falsy = ["False", "false", "off", "0", false, 0]; * This helper function is used to cast data from process.env in config files. */ export function parseBoolean( - property: number | boolean | string, + property: number | boolean | string | undefined, ): boolean | undefined { + if (property === undefined) { + return undefined; + } if (truthy.includes(property)) { return true; } else if (falsy.includes(property)) { diff --git a/back/libs/common/src/helpers/parse-json-property.ts b/back/libs/common/src/helpers/parse-json-property.ts index 06643e077..c11831923 100644 --- a/back/libs/common/src/helpers/parse-json-property.ts +++ b/back/libs/common/src/helpers/parse-json-property.ts @@ -17,10 +17,10 @@ export function parseJsonProperty( } try { - return JSON.parse(input[propertyName]); + return JSON.parse((input as Record)[propertyName]); } catch { throw TypeError( - `property "${propertyName}" is not JSON parsable, value was: ${input[propertyName]}`, + `property "${propertyName}" is not JSON parsable, value was: ${(input as Record)[propertyName]}`, ); } } diff --git a/back/libs/config/src/cli/export-env/markdown-generator.ts b/back/libs/config/src/cli/export-env/markdown-generator.ts index 8d019dad8..f4307415b 100644 --- a/back/libs/config/src/cli/export-env/markdown-generator.ts +++ b/back/libs/config/src/cli/export-env/markdown-generator.ts @@ -1,5 +1,5 @@ export class MarkdownGenerator { - static generate(envMap: object): object[] { + static generate(envMap: Record): object[] { const sortedInstances = MarkdownGenerator.sortInstances(envMap); const markdown = sortedInstances.map( @@ -9,7 +9,9 @@ export class MarkdownGenerator { return markdown; } - static sortInstances(envMap: object): object[] { + static sortInstances( + envMap: Record, + ): { instanceName: any; envVars: any }[] { const sortedInstancesNames = Object.keys(envMap).sort(); return sortedInstancesNames.map((instanceName: string) => { @@ -28,17 +30,26 @@ export class MarkdownGenerator { }); } - static sortInstancesEnvVars(envVarsNames: string[], envVars: object): object { + static sortInstancesEnvVars( + envVarsNames: string[], + envVars: Record, + ): object { return envVarsNames.map((name) => ({ name, type: envVars[name], })); } - static generateMarkdownContent({ instanceName, envVars }): object { + static generateMarkdownContent({ + instanceName, + envVars, + }: { + instanceName: any; + envVars: any; + }): object { let content = ""; - envVars.forEach(({ name, type }) => { + envVars.forEach(({ name, type }: { name: any; type: any }) => { content += `| ${name} | ${type} |\n`; }); diff --git a/back/libs/config/src/cli/export-env/runner.spec.ts b/back/libs/config/src/cli/export-env/runner.spec.ts index 756af40fa..bfdb4598f 100644 --- a/back/libs/config/src/cli/export-env/runner.spec.ts +++ b/back/libs/config/src/cli/export-env/runner.spec.ts @@ -1,6 +1,5 @@ import { renderFile } from "ejs"; -import { readFile } from "fs/promises"; -import glob from "glob"; +import { glob, readFile } from "fs/promises"; import { format } from "prettier"; import { MarkdownGenerator } from "./markdown-generator"; import { Runner } from "./runner"; @@ -94,19 +93,19 @@ describe("Runner", () => { it("should find all path using globs", () => { // Given - jest.mocked(glob.sync).mockReturnValue(pathsMock); + jest.mocked(glob).mockReturnValue(pathsMock); // When Runner.getConfigFilesPath(); // Then - expect(glob.sync).toHaveBeenCalledTimes(1); - expect(glob.sync).toHaveBeenCalledWith(FILE_SEARCH_PATTERN); + expect(glob).toHaveBeenCalledTimes(1); + expect(glob).toHaveBeenCalledWith(FILE_SEARCH_PATTERN); }); it("should return the paths", () => { // Given - jest.mocked(glob.sync).mockReturnValue(pathsMock); + jest.mocked(glob).mockReturnValue(pathsMock); // When const result = Runner.getConfigFilesPath(); diff --git a/back/libs/config/src/cli/export-env/runner.ts b/back/libs/config/src/cli/export-env/runner.ts index 0f6fe3c91..6d5563190 100644 --- a/back/libs/config/src/cli/export-env/runner.ts +++ b/back/libs/config/src/cli/export-env/runner.ts @@ -1,6 +1,5 @@ import ejs from "ejs"; -import { readFile, writeFile } from "fs/promises"; -import glob from "glob"; +import { glob, readFile, writeFile } from "fs/promises"; import { format } from "prettier"; import { MarkdownGenerator } from "./markdown-generator"; @@ -16,7 +15,7 @@ export class Runner { static async run(): Promise { console.log("Generating documentation for env vars..."); - const paths = Runner.getConfigFilesPath(); + const paths = await Runner.getConfigFilesPath(); const configFiles = await Runner.loadConfigs(paths); const envVarsMap = Runner.buildEnvMap(configFiles); @@ -29,8 +28,12 @@ export class Runner { await writeFile(DEST_FILE, await format(page, { filepath: DEST_FILE })); } - static getConfigFilesPath(searchPattern = FILE_SEARCH_PATTERN): string[] { - const paths = glob.sync(searchPattern); + static async getConfigFilesPath(searchPattern = FILE_SEARCH_PATTERN) { + const paths = []; + for await (const path of glob(searchPattern)) { + paths.push(path); + } + return paths; } @@ -47,7 +50,10 @@ export class Runner { return envMap; } - static filesReducer(envMap, { path, file }) { + static filesReducer( + envMap: Record, + { path, file }: { path: string; file: string }, + ) { const instanceName = path.split("/")[1]; const configPrefix = file.match(CONFIG_PREFIX_REGEX)?.[1]; diff --git a/back/libs/config/src/config.service.spec.ts b/back/libs/config/src/config.service.spec.ts index 31b9655b9..fd0eddb40 100644 --- a/back/libs/config/src/config.service.spec.ts +++ b/back/libs/config/src/config.service.spec.ts @@ -12,7 +12,7 @@ import { UnknownConfigurationNameError } from "./errors"; class Schema { @IsNumber() - readonly foo: number; + readonly foo!: number; @IsObject() readonly I: any; @@ -68,7 +68,7 @@ describe("ConfigService", () => { }); describe("validate", () => { - let consoleError; + let consoleError: jest.SpyInstance; beforeEach(() => { consoleError = jest @@ -146,7 +146,9 @@ describe("ConfigService", () => { // Given const part = undefined; // Then - expect(() => service.get(part)).toThrow(UnknownConfigurationNameError); + expect(() => service.get(part as unknown as string)).toThrow( + UnknownConfigurationNameError, + ); }); it("should throw if path is empty", () => { diff --git a/back/libs/cryptography/src/cryptography.service.spec.ts b/back/libs/cryptography/src/cryptography.service.spec.ts index fe53e76ef..0d0c3f692 100644 --- a/back/libs/cryptography/src/cryptography.service.spec.ts +++ b/back/libs/cryptography/src/cryptography.service.spec.ts @@ -384,10 +384,10 @@ describe("CryptographyService", () => { // action try { service["decrypt"](mockEncryptKey, WRONG_CIPHER); - } catch (e) { + } catch (e: unknown) { // expect expect(e).toBeInstanceOf(Error); - expect(e.message).toBe("Authentication failed !"); + expect((e as Error).message).toBe("Authentication failed !"); } // expect @@ -401,10 +401,10 @@ describe("CryptographyService", () => { // action try { service["decrypt"](mockEncryptKey, WRONG_CIPHER); - } catch (e) { + } catch (e: unknown) { // expect expect(e).toBeInstanceOf(Error); - expect(e.message).toBe("Authentication failed !"); + expect((e as Error).message).toBe("Authentication failed !"); } // expect @@ -460,10 +460,10 @@ describe("CryptographyService", () => { // action try { service["decrypt"](mockEncryptKey, mockCipher); - } catch (e) { + } catch (e: unknown) { // expect expect(e).toBeInstanceOf(Error); - expect(e.message).toBe("Authentication failed !"); + expect((e as Error).message).toBe("Authentication failed !"); } // expect @@ -487,7 +487,7 @@ describe("CryptographyService", () => { // mocking a native function (_password, _salt, _iterations, _keylen, _digest, callback) => { - callback(undefined, mockDerivatedKey); + callback(null, mockDerivatedKey); }, ); @@ -504,7 +504,7 @@ describe("CryptographyService", () => { // mocking a native function (_password, _salt, _iterations, _keylen, _digest, callback) => { - callback(undefined, mockDerivatedKey); + callback(null, mockDerivatedKey); }, ); @@ -531,7 +531,7 @@ describe("CryptographyService", () => { // mocking a native function (_password, _salt, _iterations, _keylen, _digest, callback) => { - callback(failure, undefined); + callback(failure, null as unknown as Buffer); }, ); diff --git a/back/libs/cryptography/src/cryptography.service.ts b/back/libs/cryptography/src/cryptography.service.ts index 0c4496f42..4067dae95 100644 --- a/back/libs/cryptography/src/cryptography.service.ts +++ b/back/libs/cryptography/src/cryptography.service.ts @@ -126,7 +126,11 @@ export class CryptographyService { decipher.setAuthTag(tag); - const receivedPlaintext = decipher.update(ciphertext, null, "utf8"); + const receivedPlaintext = decipher.update( + ciphertext, + null as unknown as undefined, + "utf8", + ); try { decipher.final(); diff --git a/back/libs/cryptography/src/dto/cryptography-config.ts b/back/libs/cryptography/src/dto/cryptography-config.ts index 2fbf5f996..8f296f464 100644 --- a/back/libs/cryptography/src/dto/cryptography-config.ts +++ b/back/libs/cryptography/src/dto/cryptography-config.ts @@ -4,5 +4,5 @@ export class CryptographyConfig { @IsString() // 16 minimum entropy bites @IsByteLength(16) - readonly passwordSalt: string; + readonly passwordSalt!: string; } diff --git a/back/libs/email-validator/src/services/email-validator.service.ts b/back/libs/email-validator/src/services/email-validator.service.ts index 2ffea7101..fb61ea855 100644 --- a/back/libs/email-validator/src/services/email-validator.service.ts +++ b/back/libs/email-validator/src/services/email-validator.service.ts @@ -9,7 +9,7 @@ import { otherGouvDomains, } from "@proconnect-gouv/proconnect.core/data"; import { run as spellCheckEmail } from "@zootools/email-spell-checker"; -import { chain, uniq } from "lodash"; +import { uniq } from "lodash"; import { EmailValidatorConfig } from "../dto"; @Injectable() @@ -74,12 +74,7 @@ export class EmailValidatorService { private async getIdpDomains() { const idps = await this.identityProviderAdapterMongoService.getList(); - const domains = chain(idps) - .map((idp) => idp.fqdns) - .flatten() - .filter(Boolean) - .uniq() - .value(); + const domains = uniq(idps.flatMap((idp) => idp.fqdns ?? [])); return domains; } diff --git a/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts b/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts index 0f54cc67d..a8f276f96 100644 --- a/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts +++ b/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts @@ -1,7 +1,6 @@ import { HttpStatus } from "@nestjs/common"; import ejs from "ejs"; import fs from "fs"; -import glob from "glob"; import { format } from "prettier"; import { BaseException } from "../../exceptions"; import { ExceptionClass } from "../../types"; @@ -253,19 +252,19 @@ describe("Runner", () => { describe("renderFile", () => { // Given const file = "none.file"; - const dataMock = []; + const dataMock: unknown[] = []; const renderFileResult = [Symbol("renderFileResult")]; const renderFileMockErrorImplementation = ( _a: string, _b: unknown, - callback, - ) => callback("error"); + callback: (err: Error | null, str: unknown) => void, + ) => callback("error" as unknown as Error, undefined); const renderFileMockSuccesImplementation = ( _a: string, _b: unknown, - callback, + callback: (err: Error | null, str: unknown) => void, ) => callback(null, renderFileResult); it("should reject the promise caused by invalid params", async () => { @@ -341,7 +340,7 @@ describe("Runner", () => { describe("run", () => { // Given - const getExceptionsFilesPathResult = []; + const getExceptionsFilesPathResult: string[] = []; const loadExceptionsResult = [{ scope: 2 }, { scope: 4 }, { scope: 6 }]; const markdownGenerateResult = []; const renderFileResult = ""; diff --git a/back/libs/exceptions/src/cli/export-exceptions/runner.ts b/back/libs/exceptions/src/cli/export-exceptions/runner.ts index 2aa2e8030..49d20aee8 100644 --- a/back/libs/exceptions/src/cli/export-exceptions/runner.ts +++ b/back/libs/exceptions/src/cli/export-exceptions/runner.ts @@ -1,7 +1,7 @@ import { HttpStatus } from "@nestjs/common"; import ejs from "ejs"; import fs from "fs"; -import glob from "glob"; +import { glob } from "node:fs/promises"; import { pathToFileURL } from "node:url"; import { format } from "prettier"; import { BaseException } from "../../exceptions/base.exception"; @@ -39,7 +39,7 @@ export default class Runner { return typeof param === "number" && param >= 0; } - static hasValidString(param: string): boolean { + static hasValidString(param: unknown): boolean { return ( typeof param === "string" && param !== null && @@ -66,7 +66,8 @@ export default class Runner { path, Exception, }: PathAndException): PathAndInstantiatedException | null { - const { http_status_code, scope, code } = new Exception(); + const { http_status_code, scope, code } = + new (Exception as typeof BaseException)(); // Retrieve static error and error description props const hasValidScope = Runner.hasValidNumber(scope); @@ -84,7 +85,7 @@ export default class Runner { return { path, - Exception, + Exception: Exception as typeof BaseException, }; } @@ -104,8 +105,8 @@ export default class Runner { exception: Exception.name, http_status_code, path, - error, - error_description, + error: error ?? "", + error_description: error_description ?? "", }; return data; @@ -121,18 +122,20 @@ export default class Runner { return modules .map((module, index) => ({ path: paths[index], module })) .map(Runner.extractException) - .filter((Exception) => Boolean(Exception)) + .filter((item): item is PathAndException => Boolean(item)) .map(Runner.inflateException) - .filter(Boolean) + .filter((item): item is PathAndInstantiatedException => Boolean(item)) .map(Runner.buildException); } - static getExceptionsFilesPath(basePaths: string[], searchPattern: string) { + static async getExceptionsFilesPath( + basePaths: string[], + searchPattern: string, + ) { const paths: string[] = []; for (const basePath of basePaths) { const pattern = `${basePath}${searchPattern}`; - const relativePaths = glob.sync(pattern); - for (const relativePath of relativePaths) { + for await (const relativePath of glob(pattern)) { paths.push(relativePath); } } @@ -142,7 +145,7 @@ export default class Runner { static renderFile(file: string, data: object): Promise { return new Promise((resolve, reject) => { - ejs.renderFile(file, data, (err: Error, result: string) => { + ejs.renderFile(file, data, (err: Error | null, result: string) => { if (err) return reject(err); return resolve(result); }); @@ -151,7 +154,7 @@ export default class Runner { static async run(): Promise { console.log("Generating documentation for exceptions..."); - const paths = Runner.getExceptionsFilesPath( + const paths = await Runner.getExceptionsFilesPath( ["libs", "apps"], "/**/*.exception.ts", ); diff --git a/back/libs/exceptions/src/exceptions/base.exception.ts b/back/libs/exceptions/src/exceptions/base.exception.ts index 30b51410c..18cda378d 100644 --- a/back/libs/exceptions/src/exceptions/base.exception.ts +++ b/back/libs/exceptions/src/exceptions/base.exception.ts @@ -1,8 +1,8 @@ import { HttpStatus } from "@nestjs/common"; export class BaseException extends Error { - public code: number | string; - public scope: number; + public code!: number | string; + public scope!: number; public http_status_code: HttpStatus = HttpStatus.INTERNAL_SERVER_ERROR; public error?: string; public error_description?: string; diff --git a/back/libs/exceptions/src/exceptions/enriched-display-base.exception.ts b/back/libs/exceptions/src/exceptions/enriched-display-base.exception.ts index 29cf09b21..e683270f2 100644 --- a/back/libs/exceptions/src/exceptions/enriched-display-base.exception.ts +++ b/back/libs/exceptions/src/exceptions/enriched-display-base.exception.ts @@ -8,7 +8,7 @@ export class EnrichedDisplayBaseException extends BaseException { public displayContact = true; public contactMessage = "Vous pouvez nous signaler cette erreur en nous écrivant."; - public contactHref: string; + public contactHref!: string; public mainAction: "contact" | "goBack" = "goBack"; public additionalErrorLogs?: { label: string; value: string | undefined }[]; diff --git a/back/libs/exceptions/src/filters/fc-web-html-exception.filter.ts b/back/libs/exceptions/src/filters/fc-web-html-exception.filter.ts index b870f4e60..87d3ef7a9 100644 --- a/back/libs/exceptions/src/filters/fc-web-html-exception.filter.ts +++ b/back/libs/exceptions/src/filters/fc-web-html-exception.filter.ts @@ -86,8 +86,8 @@ export class FcWebHtmlExceptionFilter extends BaseExceptionFilter const { urlPrefix } = this.config.get("App"); const interactionErrorUrl = `${urlPrefix}${Routes.INTERACTION_ERROR.replace( ":uid", - interactionId, - )}?error=${encodeURIComponent(exception.error)}&error_description=${encodeURIComponent(exception.error_description)}`; + interactionId!, + )}?error=${encodeURIComponent(exception.error ?? "")}&error_description=${encodeURIComponent(exception.error_description ?? "")}`; const errorPageParams: ErrorPageParams = { error, diff --git a/back/libs/exceptions/src/filters/http-exception.filter.ts b/back/libs/exceptions/src/filters/http-exception.filter.ts index 412cfb635..86397203f 100644 --- a/back/libs/exceptions/src/filters/http-exception.filter.ts +++ b/back/libs/exceptions/src/filters/http-exception.filter.ts @@ -6,6 +6,7 @@ import { BadRequestException, Catch, HttpException, + HttpStatus, } from "@nestjs/common"; import { BaseExceptionFilter } from "@nestjs/core"; import { Response } from "express"; @@ -104,7 +105,7 @@ export class HttpExceptionFilter extends BaseExceptionFilter { const errorPageParams: ErrorPageParams = { exceptionDisplay: { - ...httpErrorDisplays[exception.getStatus()], + ...httpErrorDisplays[exception.getStatus() as HttpStatus], contactHref, }, error, diff --git a/back/libs/exceptions/src/helpers/exception-display.helper.spec.ts b/back/libs/exceptions/src/helpers/exception-display.helper.spec.ts index 2ff0b9748..b5b6e2505 100644 --- a/back/libs/exceptions/src/helpers/exception-display.helper.spec.ts +++ b/back/libs/exceptions/src/helpers/exception-display.helper.spec.ts @@ -13,7 +13,11 @@ describe("getDefaultContactHref", () => { it("should render href without params", () => { // When - const input = { code: null, id: null, message: null }; + const input = { code: null, id: null, message: null } as unknown as { + code: string; + id: string; + message: string; + }; const defaultContactHref = getDefaultContactHref(input); diff --git a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo-config.ts b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo-config.ts index 5f15e84db..9a054bb1d 100644 --- a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo-config.ts +++ b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo-config.ts @@ -2,8 +2,8 @@ import { IsBoolean, IsString } from "class-validator"; export class IdentityProviderAdapterMongoConfig { @IsString() - readonly clientSecretEncryptKey: string; + readonly clientSecretEncryptKey!: string; @IsBoolean() - readonly decryptClientSecretFeature: boolean; + readonly decryptClientSecretFeature!: boolean; } diff --git a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.spec.ts b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.spec.ts index 9a3d967d3..adf48ee3e 100644 --- a/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.spec.ts +++ b/back/libs/identity-provider-adapter-mongo/src/dto/identity-provider-adapter-mongo.dto.spec.ts @@ -93,7 +93,7 @@ describe("Identity Provider (Data Transfer Object)", () => { id_token_signed_response_alg: "HS512", userinfo_signed_response_alg: "HS512", }); - delete dto.jwksURL; + delete (dto as Record).jwksURL; // When | Action const result = await validateDto( diff --git a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.spec.ts b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.spec.ts index 00b108a7f..7d73aefb2 100644 --- a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.spec.ts +++ b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.spec.ts @@ -729,7 +729,9 @@ describe("IdentityProviderAdapterMongoService", () => { it("should return false if idp is not found", async () => { // Given - const validIdentityProviderMockWithoutActiveKey = { + const validIdentityProviderMockWithoutActiveKey: Partial< + typeof validIdentityProviderMock + > = { ...validIdentityProviderMock, }; delete validIdentityProviderMockWithoutActiveKey.active; diff --git a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts index 51a9f0e22..7602a660f 100644 --- a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts +++ b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts @@ -50,7 +50,7 @@ export const IDP_METADATA = [ @Injectable() export class IdentityProviderAdapterMongoService implements IIdentityProviderAdapter { - private listCache: IdentityProviderMetadata[]; + private listCache!: IdentityProviderMetadata[]; constructor( @InjectModel("IdentityProvider") @@ -112,7 +112,7 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda if (refreshCache || !this.listCache) { const allIdentityProviders = await this.findAllIdentityProvider(); this.listCache = allIdentityProviders.map((idp) => - this.legacyToOpenIdPropertyName(idp), + this.legacyToOpenIdPropertyName(idp as unknown as IdentityProvider), ); } @@ -127,7 +127,7 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda const provider = providers.find(({ uid }) => uid === id); - return provider; + return provider!; } async isActiveById(id: string): Promise { @@ -137,12 +137,12 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda } getFqdnFromEmail(email: string | undefined): string | undefined { - return email?.split("@").pop().toLowerCase(); + return email?.split("@").pop()!.toLowerCase(); } getIdpsByEmail(email: string): Promise { const fqdn = this.getFqdnFromEmail(email); - return this.getIdpsByFqdn(fqdn); + return this.getIdpsByFqdn(fqdn!); } async getIdpsByFqdn(fqdn: string): Promise { @@ -175,7 +175,9 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda }; Object.entries(mapping).forEach(([legacyName, oidcName]) => { - result[oidcName] = source[legacyName]; + (result as Record)[oidcName] = ( + source as unknown as Record + )[legacyName]; Reflect.deleteProperty(result, legacyName); }); @@ -221,7 +223,7 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda ); if (!decryptClientSecretFeature) { - return null; + return null as unknown as string; } return this.crypto.decrypt( diff --git a/back/libs/identity-provider-adapter-mongo/src/schemas/identity-provider-adapter-mongo.schema.ts b/back/libs/identity-provider-adapter-mongo/src/schemas/identity-provider-adapter-mongo.schema.ts index e9c221c53..f107e20f5 100644 --- a/back/libs/identity-provider-adapter-mongo/src/schemas/identity-provider-adapter-mongo.schema.ts +++ b/back/libs/identity-provider-adapter-mongo/src/schemas/identity-provider-adapter-mongo.schema.ts @@ -4,72 +4,72 @@ import { Document } from "mongoose"; @Schema({ collection: "provider", strict: true }) export class IdentityProvider extends Document { @Prop({ type: String }) - name: string; + name!: string; // Note that this will create the index if not present @Prop({ index: true, type: String }) - clientID: string; + clientID!: string; @Prop({ type: String }) - client_secret: string; + client_secret!: string; @Prop({ type: Boolean }) - discovery: boolean; + discovery!: boolean; @Prop({ type: String }) - discoveryUrl: string; + discoveryUrl!: string; @Prop({ type: [String] }) - response_types: string[]; + response_types!: string[]; @Prop({ type: String }) - id_token_signed_response_alg: string; + id_token_signed_response_alg!: string; @Prop({ type: String }) - token_endpoint_auth_method: string; + token_endpoint_auth_method!: string; @Prop({ type: String }) - revocation_endpoint_auth_method: string; + revocation_endpoint_auth_method!: string; @Prop({ type: String }) - id_token_encrypted_response_alg: string; + id_token_encrypted_response_alg!: string; @Prop({ type: String }) - id_token_encrypted_response_enc: string; + id_token_encrypted_response_enc!: string; @Prop({ type: String }) - uid: string; + uid!: string; @Prop({ type: String }) - userinfo_signed_response_alg: string; + userinfo_signed_response_alg!: string; @Prop({ type: String }) - userinfo_encrypted_response_alg: string; + userinfo_encrypted_response_alg!: string; @Prop({ type: String }) - userinfo_encrypted_response_enc: string; + userinfo_encrypted_response_enc!: string; @Prop({ type: String }) - siret: string; + siret!: string; @Prop({ type: String, required: false }) - supportEmail: string; + supportEmail!: string; @Prop({ type: Boolean }) - isRoutingEnabled: boolean; + isRoutingEnabled!: boolean; @Prop({ type: Boolean }) - isEntraID: boolean; + isEntraID!: boolean; @Prop({ type: [String] }) @Prop({ type: [String] }) - extraAcceptedEmailDomains: string[]; + extraAcceptedEmailDomains!: string[]; @Prop({ type: Boolean }) - isBlockingForUnlistedEmailDomainsEnabled: boolean; + isBlockingForUnlistedEmailDomainsEnabled!: boolean; @Prop({ type: Boolean }) - useTheHyyyperbridge: boolean; + useTheHyyyperbridge!: boolean; } export const IdentityProviderSchema = diff --git a/back/libs/logger-plugins/src/services/logger-session.service.ts b/back/libs/logger-plugins/src/services/logger-session.service.ts index 9b333eb3e..b1fe077ab 100644 --- a/back/libs/logger-plugins/src/services/logger-session.service.ts +++ b/back/libs/logger-plugins/src/services/logger-session.service.ts @@ -39,11 +39,11 @@ export class LoggerSessionService implements LoggerPluginServiceInterface { idpAcr, idpBelongingPopulation: idpIdentity?.belonging_population, idpEmail: idpIdentity?.email, - idpEmailFqdn: idpIdentity?.email?.split("@").pop().toLowerCase(), + idpEmailFqdn: idpIdentity?.email?.split("@").pop()!.toLowerCase(), idpId, idpLabel, idpLoginHint, - idpLoginHintFqdn: idpLoginHint?.split("@").pop().toLowerCase(), + idpLoginHintFqdn: idpLoginHint?.split("@").pop()!.toLowerCase(), idpName, idpOrganizationalUnit: idpIdentity?.organizational_unit, idpSiret: idpIdentity?.siret, @@ -55,7 +55,7 @@ export class LoggerSessionService implements LoggerPluginServiceInterface { spEssentialAcr, spId, spLoginHint, - spLoginHintFqdn: spLoginHint?.split("@").pop().toLowerCase(), + spLoginHintFqdn: spLoginHint?.split("@").pop()!.toLowerCase(), spName, spSiret: spIdentity?.siret, spSiretHint, diff --git a/back/libs/logger/src/logger.module.ts b/back/libs/logger/src/logger.module.ts index 843c217c9..826c1b62e 100644 --- a/back/libs/logger/src/logger.module.ts +++ b/back/libs/logger/src/logger.module.ts @@ -7,7 +7,7 @@ import { PLUGIN_SERVICES } from "./tokens"; @Module({}) export class LoggerModule { static forRoot(plugins: LoggerPluginInterface[] = []): DynamicModule { - const imports = []; + const imports: any[] = []; plugins.forEach((plugin) => { imports.push(...plugin.imports); diff --git a/back/libs/logger/src/services/logger.service.ts b/back/libs/logger/src/services/logger.service.ts index 9f432a3d2..381d05f35 100644 --- a/back/libs/logger/src/services/logger.service.ts +++ b/back/libs/logger/src/services/logger.service.ts @@ -21,7 +21,7 @@ export class LoggerService { [LogLevels.DEBUG]: 20, [LogLevels.TRACE]: 10, }; - private pino: Logger; + private pino!: Logger; constructor( private readonly config: ConfigService, @@ -35,38 +35,38 @@ export class LoggerService { * Below are the methods to wrap the pino logger levels functions. */ - [LogLevels.FATAL](msg: string, ...args: unknown[]); - [LogLevels.FATAL](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.FATAL](msg: string, ...args: unknown[]): void; + [LogLevels.FATAL](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.FATAL](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.FATAL, obj, msg, ...args); } - [LogLevels.ERROR](msg: string, ...args: unknown[]); - [LogLevels.ERROR](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.ERROR](msg: string, ...args: unknown[]): void; + [LogLevels.ERROR](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.ERROR](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.ERROR, obj, msg, ...args); } - [LogLevels.WARN](msg: string, ...args: unknown[]); - [LogLevels.WARN](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.WARN](msg: string, ...args: unknown[]): void; + [LogLevels.WARN](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.WARN](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.WARN, obj, msg, ...args); } - [LogLevels.INFO](msg: string, ...args: unknown[]); - [LogLevels.INFO](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.INFO](msg: string, ...args: unknown[]): void; + [LogLevels.INFO](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.INFO](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.INFO, obj, msg, ...args); } - [LogLevels.DEBUG](msg: string, ...args: unknown[]); - [LogLevels.DEBUG](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.DEBUG](msg: string, ...args: unknown[]): void; + [LogLevels.DEBUG](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.DEBUG](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.DEBUG, obj, msg, ...args); } - [LogLevels.TRACE](msg: string, ...args: unknown[]); - [LogLevels.TRACE](obj: unknown, msg?: string, ...args: unknown[]); + [LogLevels.TRACE](msg: string, ...args: unknown[]): void; + [LogLevels.TRACE](obj: unknown, msg?: string, ...args: unknown[]): void; [LogLevels.TRACE](obj: unknown, msg?: string, ...args: unknown[]): void { this.logWithContext(LogLevels.TRACE, obj, msg, ...args); } @@ -110,7 +110,7 @@ export class LoggerService { customLevels, useOnlyCustomLevels: true, formatters: { - level(label, number) { + level(label: string, number: number) { return { levelNumber: number, level: label }; }, }, diff --git a/back/libs/mongoose/src/mongoose.module.e2e.spec.ts b/back/libs/mongoose/src/mongoose.module.e2e.spec.ts index a4583bf49..b6af1412c 100644 --- a/back/libs/mongoose/src/mongoose.module.e2e.spec.ts +++ b/back/libs/mongoose/src/mongoose.module.e2e.spec.ts @@ -25,7 +25,7 @@ const configServiceMock = getConfigMock(); @Schema() class Cat extends Document { @Prop() - name: string; + name!: string; } const CatSchema = SchemaFactory.createForClass(Cat); @@ -67,7 +67,7 @@ describe("MongooseProvider with MongoMemoryReplSet", () => { watcherDebounceWaitDuration: 0, }, }, - get(path) { + get(path: string) { return get(this.configuration, path); }, }; @@ -129,7 +129,7 @@ describe("MongooseProvider with MongoMemoryReplSet", () => { watcherDebounceWaitDuration: 0, }, }, - get(path) { + get(path: string) { return get(this.configuration, path); }, }; diff --git a/back/libs/mongoose/src/mongoose.module.ts b/back/libs/mongoose/src/mongoose.module.ts index 94625c893..8248a91e6 100644 --- a/back/libs/mongoose/src/mongoose.module.ts +++ b/back/libs/mongoose/src/mongoose.module.ts @@ -29,7 +29,7 @@ export class MongooseModule { }); return { ...mongoose, - imports: [...mongoose.imports, CqrsModule], + imports: [...(mongoose.imports ?? []), CqrsModule], providers: [ EventBus, MongooseCollectionOperationWatcherHelper, @@ -46,10 +46,13 @@ export class MongooseModule { ...mongoose, imports: [CqrsModule], providers: [ - ...mongoose.providers, + ...(mongoose.providers ?? []), + MongooseCollectionOperationWatcherHelper, + ], + exports: [ + ...(mongoose.exports ?? []), MongooseCollectionOperationWatcherHelper, ], - exports: [...mongoose.exports, MongooseCollectionOperationWatcherHelper], }; } } diff --git a/back/libs/mongoose/src/providers/mongoose.provider.spec.ts b/back/libs/mongoose/src/providers/mongoose.provider.spec.ts index 7ada77de4..6e65d98b9 100644 --- a/back/libs/mongoose/src/providers/mongoose.provider.spec.ts +++ b/back/libs/mongoose/src/providers/mongoose.provider.spec.ts @@ -37,7 +37,7 @@ describe("MongooseProvider", () => { describe("buildMongoParams()", () => { it("should construct params with config options from connection name", () => { const params = MongooseProvider.buildMongoParams( - undefined, + undefined as any, { get: jest.fn().mockReturnValue({ user: "userValue", diff --git a/back/libs/oidc-acr/src/oidc-acr.service.spec.ts b/back/libs/oidc-acr/src/oidc-acr.service.spec.ts index 644615922..acfc6d802 100644 --- a/back/libs/oidc-acr/src/oidc-acr.service.spec.ts +++ b/back/libs/oidc-acr/src/oidc-acr.service.spec.ts @@ -139,7 +139,7 @@ describe("OidcAcrService", () => { name: "login", reasons: ["essential_acr"], }, - } as undefined as ExtendedInteraction; + } as unknown as ExtendedInteraction; // When const result = service["isEssentialAcrSatisfied"](interactionMock); @@ -155,7 +155,7 @@ describe("OidcAcrService", () => { name: "login", reasons: ["essential_acrs"], }, - } as undefined as ExtendedInteraction; + } as unknown as ExtendedInteraction; // When const result = service["isEssentialAcrSatisfied"](interactionMock); @@ -171,7 +171,7 @@ describe("OidcAcrService", () => { name: "interaction-check", reasons: ["other_reasons"], }, - } as undefined as ExtendedInteraction; + } as unknown as ExtendedInteraction; // When const result = service["isEssentialAcrSatisfied"](interactionMock); @@ -197,7 +197,7 @@ describe("OidcAcrService", () => { }, }, }, - } as undefined as ExtendedInteraction; + } as unknown as ExtendedInteraction; jest.spyOn(service, "getFilteredAcrValues").mockReturnValueOnce(["A"]); @@ -229,7 +229,7 @@ describe("OidcAcrService", () => { }, }, }, - } as undefined as ExtendedInteraction; + } as unknown as ExtendedInteraction; jest.spyOn(service, "getFilteredAcrValues").mockReturnValueOnce(["A"]); diff --git a/back/libs/oidc-acr/src/oidc-acr.service.ts b/back/libs/oidc-acr/src/oidc-acr.service.ts index 6f0cb107e..9dc4329e6 100644 --- a/back/libs/oidc-acr/src/oidc-acr.service.ts +++ b/back/libs/oidc-acr/src/oidc-acr.service.ts @@ -25,7 +25,7 @@ export class OidcAcrService { }: Pick): string | undefined { if ( !isEmpty(spEssentialAcr) && - !spEssentialAcr.split(" ").includes(idpAcr) + !(spEssentialAcr as string).split(" ").includes(idpAcr as string) ) { return undefined; } @@ -33,7 +33,7 @@ export class OidcAcrService { const { supportedAcrValues } = this.config.get("OidcProvider"); - if (!Array.from(supportedAcrValues).includes(idpAcr)) { + if (!Array.from(supportedAcrValues ?? []).includes(idpAcr as string)) { // If the IdP's ACR value is not supported, fallback to 'eidas1' // Note: Some IdPs, especially from Fonction Publique Territoriale, may use lower ACRs return "eidas1"; @@ -62,7 +62,7 @@ export class OidcAcrService { const { supportedAcrValues } = this.config.get("OidcProvider"); - return intersection(acrValuesAsArray, Array.from(supportedAcrValues)); + return intersection(acrValuesAsArray, Array.from(supportedAcrValues ?? [])); } isEssentialAcrSatisfied({ diff --git a/back/libs/oidc-client/src/exceptions/hyyyperbridge-csmr.exception.ts b/back/libs/oidc-client/src/exceptions/hyyyperbridge-csmr.exception.ts index f5920988a..37f48381c 100644 --- a/back/libs/oidc-client/src/exceptions/hyyyperbridge-csmr.exception.ts +++ b/back/libs/oidc-client/src/exceptions/hyyyperbridge-csmr.exception.ts @@ -8,15 +8,15 @@ export class HyyyperbridgeCsmrException extends HyyyperbridgeBaseException { public error_description = "authentication aborted due to a technical error on the authorization server"; - public reference: string; - public name: string; - public reason: string; + public reference!: string; + public name!: string; + public reason!: string; from(error: HyyyperbridgeErrorDto) { const { code: reference, name, reason } = error; - this.reference = reference; - this.name = name; - this.reason = reason; + this.reference = reference as string; + this.name = name as string; + this.reason = reason as string; return this; } } diff --git a/back/libs/oidc-provider/src/adapters/oidc-provider-redis-adapter.spec.ts b/back/libs/oidc-provider/src/adapters/oidc-provider-redis-adapter.spec.ts index 4c3968323..d59c4ade8 100644 --- a/back/libs/oidc-provider/src/adapters/oidc-provider-redis-adapter.spec.ts +++ b/back/libs/oidc-provider/src/adapters/oidc-provider-redis-adapter.spec.ts @@ -13,7 +13,7 @@ import { } from "./oidc-provider-redis.adapter"; describe("OidcProviderRedisAdapter", () => { - let adapter; + let adapter: any; const loggerMock = getLoggerMock() as unknown as LoggerService; const redisMock = getRedisServiceMock(); @@ -279,7 +279,10 @@ describe("OidcProviderRedisAdapter", () => { describe("saveKey", () => { it("should throw if JSON.stringiy fails", () => { // Given - const payload = { foo: "bar", circularRef: null }; + const payload: { foo: string; circularRef: any } = { + foo: "bar", + circularRef: null, + }; const keyMock = "foo"; payload.circularRef = payload; // Then diff --git a/back/libs/oidc-provider/src/adapters/oidc-provider-redis.adapter.ts b/back/libs/oidc-provider/src/adapters/oidc-provider-redis.adapter.ts index 85805dc55..72e5db8a5 100644 --- a/back/libs/oidc-provider/src/adapters/oidc-provider-redis.adapter.ts +++ b/back/libs/oidc-provider/src/adapters/oidc-provider-redis.adapter.ts @@ -82,7 +82,7 @@ export class OidcProviderRedisAdapter implements Adapter { return boundConstructor; } - private grantKeyFor(id: string): string { + private grantKeyFor(id: string): string | null { if (!id) { return null; } @@ -90,7 +90,7 @@ export class OidcProviderRedisAdapter implements Adapter { return key; } - private userCodeKeyFor(userCode: string): string { + private userCodeKeyFor(userCode: string): string | null { if (!userCode) { return null; } @@ -98,7 +98,7 @@ export class OidcProviderRedisAdapter implements Adapter { return key; } - private uidKeyFor(uid: string): string { + private uidKeyFor(uid: string): string | null { if (!uid) { return null; } @@ -110,7 +110,7 @@ export class OidcProviderRedisAdapter implements Adapter { return `${OIDC_PROVIDER_REDIS_PREFIX}:${this.contextName}:${id}`; } - private parsedPayload(payload) { + private parsedPayload(payload: string) { try { return JSON.parse(payload); } catch { @@ -118,7 +118,7 @@ export class OidcProviderRedisAdapter implements Adapter { } } - private saveKey(multi, key, data) { + private saveKey(multi: any, key: any, data: any) { let dataFormated: string; try { @@ -141,7 +141,7 @@ export class OidcProviderRedisAdapter implements Adapter { } private async saveGrantId( - multi, + multi: any, grantId: string, key: string, expiresIn: number, @@ -160,10 +160,10 @@ export class OidcProviderRedisAdapter implements Adapter { } private addSetAndExpireOnMulti( - key: string, + key: string | null, id: string, expiresIn: number, - multi, + multi: any, ): void { if (key) { multi.set(key, id); @@ -216,7 +216,9 @@ export class OidcProviderRedisAdapter implements Adapter { return void 0; } - const wrappedData = typeof data === "string" ? { payload: data } : data; + const wrappedData = ( + typeof data === "string" ? { payload: data } : data + ) as { payload: string; [key: string]: string }; const { payload, ...rest } = wrappedData; const parsedPayload = this.parsedPayload(payload); @@ -236,13 +238,13 @@ export class OidcProviderRedisAdapter implements Adapter { } async findByUid(uid: string) { - const id = await this.redis.client.get(this.uidKeyFor(uid)); - return this.find(id); + const id = await this.redis.client.get(this.uidKeyFor(uid)!); + return this.find(id!); } async findByUserCode(userCode: string) { - const id = await this.redis.client.get(this.userCodeKeyFor(userCode)); - return this.find(id); + const id = await this.redis.client.get(this.userCodeKeyFor(userCode)!); + return this.find(id!); } async destroy(id: string) { @@ -253,12 +255,12 @@ export class OidcProviderRedisAdapter implements Adapter { async revokeByGrantId(grantId: string) { const multi = this.redis.client.multi(); const tokens = await this.redis.client.lrange( - this.grantKeyFor(grantId), + this.grantKeyFor(grantId)!, 0, -1, ); tokens.forEach((token: string) => multi.del(token)); - multi.del(this.grantKeyFor(grantId)); + multi.del(this.grantKeyFor(grantId)!); await multi.exec(); } @@ -281,7 +283,7 @@ export class OidcProviderRedisAdapter implements Adapter { if (ttl <= 0) { return { expire: -1, - payload: null, + payload: null as unknown as T, }; } @@ -305,10 +307,13 @@ export class OidcProviderRedisAdapter implements Adapter { ): Promise<{ ttl: number; value: string }> { const result = await this.redis.client.multi().ttl(key).get(key).exec(); - const [[, ttl], [, value]] = result; + const [[, ttl], [, value]] = result as [ + [unknown, number], + [unknown, string], + ]; if (typeof ttl !== "number" || typeof value !== "string") { - return { ttl: -1, value: null }; + return { ttl: -1, value: null as unknown as string }; } return { ttl, value }; diff --git a/back/libs/oidc-provider/src/oidc-provider.service.spec.ts b/back/libs/oidc-provider/src/oidc-provider.service.spec.ts index e994a2803..1f4e1efdb 100644 --- a/back/libs/oidc-provider/src/oidc-provider.service.spec.ts +++ b/back/libs/oidc-provider/src/oidc-provider.service.spec.ts @@ -59,8 +59,8 @@ describe("OidcProviderService", () => { const useSpy = jest.fn(); const providerMock = { - middlewares: [], - use: (middleware) => { + middlewares: [] as Function[], + use: (middleware: Function) => { providerMock.middlewares.push(middleware); useSpy(); }, @@ -125,10 +125,10 @@ describe("OidcProviderService", () => { oidcProviderConfigServiceMock.getConfig.mockImplementation(() => ({ paramsMock: "paramMocks", })); - service["getConfig"] = jest.fn().mockResolvedValue({ + (service as any)["getConfig"] = jest.fn().mockResolvedValue({ ...configOidcProviderMock, }); - service["registerMiddlewares"] = jest.fn(); + (service as any)["registerMiddlewares"] = jest.fn(); }); it("should create oidc-provider instance", () => { diff --git a/back/libs/oidc-provider/src/services/oidc-provider-config.service.spec.ts b/back/libs/oidc-provider/src/services/oidc-provider-config.service.spec.ts index 042f3428d..de9d6b46d 100644 --- a/back/libs/oidc-provider/src/services/oidc-provider-config.service.spec.ts +++ b/back/libs/oidc-provider/src/services/oidc-provider-config.service.spec.ts @@ -124,7 +124,7 @@ describe("OidcProviderConfigService", () => { } as unknown as KoaContextWithOIDC; // When - service["postLogoutSuccessSource"](ctx); + service["postLogoutSuccessSource"]!(ctx); // Then expect(renderMock).toHaveBeenCalledOnce(); @@ -134,7 +134,7 @@ describe("OidcProviderConfigService", () => { describe("logoutSource", () => { it("should render logout page", () => { // When - service["logoutSource"](ctxMock, form); + service["logoutSource"]!(ctxMock, form); // Then expect(ctxMock.body).toBeDefined(); @@ -158,7 +158,7 @@ describe("OidcProviderConfigService", () => { }); // When - const result = await service.findAccount(ctxMock, sub); + const result = await service.findAccount!(ctxMock, sub); // Then expect(sessionServiceMock.getAlias).toHaveBeenCalledWith(sub); @@ -168,7 +168,7 @@ describe("OidcProviderConfigService", () => { }); // Claims function test - const claims = await result.claims( + const claims = await result!.claims( "userinfo", "openid given_name family_name", {}, @@ -190,10 +190,12 @@ describe("OidcProviderConfigService", () => { const params = { error: "access_denied", error_description: "Not allowed", - } as unknown as Parameters[1]; + } as unknown as Parameters< + NonNullable + >[1]; // When - await service.renderError(ctx, params, new Error("boom")); + await service.renderError!(ctx, params, new Error("boom")); // Then expect(ctx).toHaveProperty("type", "html"); diff --git a/back/libs/rabbitmq/src/dto/rabbitmq.config.ts b/back/libs/rabbitmq/src/dto/rabbitmq.config.ts index e9f28610d..58a744260 100644 --- a/back/libs/rabbitmq/src/dto/rabbitmq.config.ts +++ b/back/libs/rabbitmq/src/dto/rabbitmq.config.ts @@ -7,10 +7,10 @@ import { IsArray, IsIn, IsNumber, IsOptional, IsString } from "class-validator"; export class RabbitmqConfig { @IsArray() // @IsUrl() - readonly urls: string[]; + readonly urls!: string[]; @IsString() - readonly queue: string; + readonly queue!: string; /** * @TODO #147 Validate options (hard coded) @@ -51,8 +51,8 @@ export class RabbitmqConfig { "hex", ]) @IsString() - readonly payloadEncoding: BufferEncoding; + readonly payloadEncoding!: BufferEncoding; @IsNumber() - readonly requestTimeout: number; + readonly requestTimeout!: number; } diff --git a/back/libs/rabbitmq/src/rabbitmq.module.spec.ts b/back/libs/rabbitmq/src/rabbitmq.module.spec.ts index 4cd78c115..b4445fd90 100644 --- a/back/libs/rabbitmq/src/rabbitmq.module.spec.ts +++ b/back/libs/rabbitmq/src/rabbitmq.module.spec.ts @@ -38,7 +38,7 @@ describe("RabbitmqModule", () => { const moduleNameMock = "Foobar"; const module = RabbitmqModule.registerFor(moduleNameMock); // When - const result = module.providers[0] as any; + const result = module.providers![0] as any; // Then expect(result).toHaveProperty("provide"); expect(result.provide).toBe("FoobarBroker"); @@ -48,7 +48,7 @@ describe("RabbitmqModule", () => { const moduleNameMock = "Foobar"; const module = RabbitmqModule.registerFor(moduleNameMock); // When - const result = module.providers[0] as any; + const result = module.providers![0] as any; // Then expect(result).toHaveProperty("useFactory"); expect(result.useFactory).toBeInstanceOf(Function); @@ -60,7 +60,7 @@ describe("RabbitmqModule", () => { return {} as ClientProxy; }); const module = RabbitmqModule.registerFor(moduleNameMock); - const provider = module.providers[0] as any; + const provider = module.providers![0] as any; // When provider.useFactory(loggerMock, configServiceMock); // Then diff --git a/back/libs/redis/src/dto/redis.config.ts b/back/libs/redis/src/dto/redis.config.ts index 4341f20f2..2caa6b708 100644 --- a/back/libs/redis/src/dto/redis.config.ts +++ b/back/libs/redis/src/dto/redis.config.ts @@ -12,33 +12,33 @@ import { class TlsConfig { @IsString() - readonly ca: string; + readonly ca!: string; } export class RedisConfig { @IsString() @ValidateIf(({ sentinels }) => sentinels === undefined) - readonly host: string; + readonly host!: string; @Type(() => Number) @IsNumber() @ValidateIf(({ sentinels }) => sentinels === undefined) - readonly port: number; + readonly port!: number; @IsNumber() @Type(() => Number) - readonly db: number; + readonly db!: number; @IsString() @IsOptional() - readonly password: string; + readonly password!: string; @IsArray() @IsObject({ each: true }) @ValidateNested() @Type(() => Sentinel) @ValidateIf(({ host }) => host === undefined) - readonly sentinels: Sentinel[]; + readonly sentinels!: Sentinel[]; @IsObject() @IsOptional() @@ -53,23 +53,23 @@ export class RedisConfig { readonly sentinelTLS?: TlsConfig; @IsBoolean() - readonly enableTLSForSentinelMode: boolean; + readonly enableTLSForSentinelMode!: boolean; @IsString() @IsOptional() @ValidateIf(({ sentinels }) => sentinels !== undefined) - readonly sentinelPassword: string; + readonly sentinelPassword!: string; @IsString() @ValidateIf(({ sentinels }) => sentinels !== undefined) - readonly name: string; + readonly name!: string; } class Sentinel { @IsString() - readonly host: string; + readonly host!: string; @IsNumber() @Type(() => Number) - readonly port: number; + readonly port!: number; } diff --git a/back/libs/redis/src/services/redis.service.ts b/back/libs/redis/src/services/redis.service.ts index fb769269d..71c163b36 100644 --- a/back/libs/redis/src/services/redis.service.ts +++ b/back/libs/redis/src/services/redis.service.ts @@ -5,7 +5,7 @@ import { RedisConfig } from "../dto"; @Injectable() export class RedisService { - public client: Redis; + public client!: Redis; constructor(private readonly config: ConfigService) {} diff --git a/back/libs/service-provider-adapter-mongo/src/schemas/service-provider-adapter-mongo.schema.ts b/back/libs/service-provider-adapter-mongo/src/schemas/service-provider-adapter-mongo.schema.ts index 343715adb..e898e2d9a 100644 --- a/back/libs/service-provider-adapter-mongo/src/schemas/service-provider-adapter-mongo.schema.ts +++ b/back/libs/service-provider-adapter-mongo/src/schemas/service-provider-adapter-mongo.schema.ts @@ -4,41 +4,41 @@ import { Document } from "mongoose"; @Schema({ strict: true, collection: "client" }) export class ServiceProvider extends Document { @Prop({ type: String }) - name: string; + name!: string; @Prop({ type: Boolean }) - active: boolean; + active!: boolean; // Note that this will create the index if not present @Prop({ type: String, unique: true, index: true }) - key: string; + key!: string; @Prop({ type: String }) - client_id: string; + client_id!: string; @Prop({ type: String }) - client_secret: string; + client_secret!: string; @Prop({ type: [String] }) - scopes: string[]; + scopes!: string[]; @Prop({ type: [String] }) - redirect_uris: string[]; + redirect_uris!: string[]; @Prop({ type: [String] }) - post_logout_redirect_uris: string[]; + post_logout_redirect_uris!: string[]; @Prop({ type: String }) - id_token_signed_response_alg: string; + id_token_signed_response_alg!: string; @Prop({ type: String }) - userinfo_signed_response_alg: string; + userinfo_signed_response_alg!: string; @Prop({ type: String }) - jwks_uri: string; + jwks_uri!: string; @Prop({ type: String }) - type: string; + type!: string; } export const ServiceProviderSchema = diff --git a/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.spec.ts b/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.spec.ts index 16d9b4266..1cd2bbc64 100644 --- a/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.spec.ts +++ b/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.spec.ts @@ -167,8 +167,8 @@ describe("ServiceProviderAdapterMongoService", () => { client_secret: "client_secret", scope: validServiceProviderMock.scopes.join(" "), }; - delete expected.key; - delete expected.scopes; + delete (expected as Record).key; + delete (expected as Record).scopes; service["decryptClientSecret"] = jest .fn() .mockReturnValueOnce(expected.client_secret); @@ -305,8 +305,8 @@ describe("ServiceProviderAdapterMongoService", () => { scope: "openid profile", }, ]; - delete expected[0].key; - delete expected[0].scopes; + delete (expected[0] as Record).key; + delete (expected[0] as Record).scopes; service["decryptClientSecret"] = jest .fn() .mockReturnValueOnce(expected[0].client_secret); @@ -348,8 +348,8 @@ describe("ServiceProviderAdapterMongoService", () => { scope: "openid profile", }, ]; - delete expected[0].key; - delete expected[0].scopes; + delete (expected[0] as Record).key; + delete (expected[0] as Record).scopes; service["decryptClientSecret"] = jest .fn() .mockReturnValueOnce(expected[0].client_secret); @@ -419,8 +419,8 @@ describe("ServiceProviderAdapterMongoService", () => { client_secret: "client_secret", scope: "openid profile", }; - delete expected.key; - delete expected.scopes; + delete (expected as Record).key; + delete (expected as Record).scopes; service["decryptClientSecret"] = jest .fn() .mockReturnValueOnce("client_secret"); diff --git a/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.ts b/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.ts index a4f5f724c..ce8fce1b6 100644 --- a/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.ts +++ b/back/libs/service-provider-adapter-mongo/src/service-provider-adapter-mongo.service.ts @@ -16,7 +16,7 @@ import { ServiceProvider } from "./schemas"; @Injectable() export class ServiceProviderAdapterMongoService implements IServiceProviderAdapter { - private listCache: ServiceProviderMetadata[]; + private listCache!: ServiceProviderMetadata[]; constructor( @InjectModel("ServiceProvider") @@ -79,7 +79,9 @@ export class ServiceProviderAdapterMongoService implements IServiceProviderAdapt if (refreshCache || !this.listCache) { const allServiceProviders = await this.findAllServiceProvider(); this.listCache = allServiceProviders.map((serviceProvider) => - this.legacyToOpenIdPropertyName(serviceProvider), + this.legacyToOpenIdPropertyName( + serviceProvider as unknown as ServiceProvider, + ), ); } @@ -93,7 +95,7 @@ export class ServiceProviderAdapterMongoService implements IServiceProviderAdapt const list = await this.getList(refreshCache); const serviceProvider: ServiceProviderMetadata = list.find( ({ client_id: dbId }) => dbId === spId, - ); + ) as ServiceProviderMetadata; return serviceProvider; } @@ -112,8 +114,8 @@ export class ServiceProviderAdapterMongoService implements IServiceProviderAdapt scope, }; - delete result.key; - delete result.scopes; + delete (result as Record).key; + delete (result as Record).scopes; return result as ServiceProviderMetadata; } diff --git a/back/libs/session/src/dto/session.config.ts b/back/libs/session/src/dto/session.config.ts index ce50dfdb2..dcf6aa762 100644 --- a/back/libs/session/src/dto/session.config.ts +++ b/back/libs/session/src/dto/session.config.ts @@ -21,17 +21,17 @@ import { type TemplateExposedType } from "../types"; export class CookieOptions { @IsBoolean() - readonly signed: boolean; + readonly signed!: boolean; @IsString() @IsIn(["strict", "lax", "none"]) - readonly sameSite: "none" | "lax" | "strict"; + readonly sameSite!: "none" | "lax" | "strict"; @IsBoolean() - readonly httpOnly: boolean; + readonly httpOnly!: boolean; @IsBoolean() - readonly secure: boolean; + readonly secure!: boolean; @IsNumber() @IsOptional() @@ -46,45 +46,45 @@ export class SessionConfig { */ @IsString() @Length(32, 32) - readonly encryptionKey: string; + readonly encryptionKey!: string; @IsString() @MinLength(2) - readonly prefix: string; + readonly prefix!: string; @ValidateNested() @Type(() => CookieOptions) - readonly cookieOptions: CookieOptions; + readonly cookieOptions!: CookieOptions; @IsString() - readonly sessionCookieName: string; + readonly sessionCookieName!: string; @IsArray() - readonly cookieSecrets: string[]; + readonly cookieSecrets!: string[]; @IsNumber() @IsPositive() - readonly lifetime: number; + readonly lifetime!: number; @IsNumber() @Min(32) - readonly sessionIdLength: number; + readonly sessionIdLength!: number; @IsArray() @IsStringOrRegExp({ each: true }) - readonly middlewareIncludedRoutes: (string | RouteInfo)[]; + readonly middlewareIncludedRoutes!: (string | RouteInfo)[]; @IsArray() @IsStringOrRegExp({ each: true }) - readonly middlewareExcludedRoutes: (string | RouteInfo)[]; + readonly middlewareExcludedRoutes!: (string | RouteInfo)[]; @IsObject() @IsOptional() readonly templateExposed?: TemplateExposedType; @IsBoolean() - readonly slidingExpiration: boolean; + readonly slidingExpiration!: boolean; @IsObject() - readonly schema: Class; + readonly schema!: Class; } diff --git a/back/libs/session/src/interceptors/session-commit.interceptor.ts b/back/libs/session/src/interceptors/session-commit.interceptor.ts index 5a69aa161..777b365a1 100644 --- a/back/libs/session/src/interceptors/session-commit.interceptor.ts +++ b/back/libs/session/src/interceptors/session-commit.interceptor.ts @@ -73,6 +73,8 @@ export class SessionCommitInterceptor implements NestInterceptor { } private getCleanedUpRoutes(routes: (string | RouteInfo)[]): string[] { - return routes.map((route: string) => route.replace("$", "")); + return routes.map((route: string | RouteInfo) => + (route as string).replace("$", ""), + ); } } diff --git a/back/libs/session/src/services/session-backend-storage.service.spec.ts b/back/libs/session/src/services/session-backend-storage.service.spec.ts index a972021b0..837bead06 100644 --- a/back/libs/session/src/services/session-backend-storage.service.spec.ts +++ b/back/libs/session/src/services/session-backend-storage.service.spec.ts @@ -107,7 +107,7 @@ describe("SessionBackendStorageService", () => { beforeEach(() => { service["getSessionKey"] = jest.fn().mockReturnValue(sessionKey); service["deserialize"] = jest.fn().mockReturnValue(deserializedData); - service["validate"] = jest.fn(); + (service as any)["validate"] = jest.fn(); }); it("should call getSessionKey()", async () => { diff --git a/back/libs/session/src/services/session-backend-storage.service.ts b/back/libs/session/src/services/session-backend-storage.service.ts index ffbf9aba9..085491d57 100644 --- a/back/libs/session/src/services/session-backend-storage.service.ts +++ b/back/libs/session/src/services/session-backend-storage.service.ts @@ -34,7 +34,7 @@ export class SessionBackendStorageService { let serializedSession: string; try { - serializedSession = await this.redis.client.get(sessionKey); + serializedSession = (await this.redis.client.get(sessionKey)) as string; } catch { throw new SessionStorageException(); } @@ -98,7 +98,7 @@ export class SessionBackendStorageService { * ioredis uses an old school asynchrone with callback convention, * the promise returns an array where the first element is the error or null on success. */ - const [error] = await multi.exec(); + const [error] = (await multi.exec()) ?? []; return !error; } @@ -162,7 +162,8 @@ export class SessionBackendStorageService { multi.set(alias, sessionId); multi.expire(alias, lifetime); - const result: RedisQueryResult[] = await multi.exec(); + const result: RedisQueryResult[] = + (await multi.exec()) as RedisQueryResult[]; return result; } @@ -177,6 +178,6 @@ export class SessionBackendStorageService { throw new SessionAliasNotFoundException(); } - return value; + return value as string; } } diff --git a/back/libs/session/src/services/session-lifecycle.service.ts b/back/libs/session/src/services/session-lifecycle.service.ts index 707a6d805..a8bb8c245 100644 --- a/back/libs/session/src/services/session-lifecycle.service.ts +++ b/back/libs/session/src/services/session-lifecycle.service.ts @@ -93,7 +93,7 @@ export class SessionLifecycleService { async refresh(req: Request, res: Response): Promise { const { lifetime } = this.config.get("Session"); - const sessionId = this.cookies.get(req); + const sessionId = this.cookies.get(req)!; await this.backendStorage.expire(sessionId, lifetime); diff --git a/back/libs/session/src/services/session-local-storage.service.ts b/back/libs/session/src/services/session-local-storage.service.ts index 7ccc6f409..fe91dc342 100644 --- a/back/libs/session/src/services/session-local-storage.service.ts +++ b/back/libs/session/src/services/session-local-storage.service.ts @@ -19,7 +19,7 @@ export class SessionLocalStorageService { if (!store) { return { data: {}, - id: undefined, + id: undefined as unknown as string, sync: false, }; } @@ -78,7 +78,7 @@ export class SessionLocalStorageService { */ private setByKey( moduleName: string, - session: object, + session: Record, key: string, data: unknown, ): void { @@ -93,7 +93,11 @@ export class SessionLocalStorageService { * Deep clones the input before assignation * to avoid later mutations to affect the session */ - private setModule(moduleName: string, session: object, data: object): void { + private setModule( + moduleName: string, + session: Record, + data: object, + ): void { session[moduleName] = { ...session[moduleName], ...cloneDeep(data), diff --git a/back/libs/session/src/services/session.service.ts b/back/libs/session/src/services/session.service.ts index 57f67c037..6c12b5342 100644 --- a/back/libs/session/src/services/session.service.ts +++ b/back/libs/session/src/services/session.service.ts @@ -24,7 +24,7 @@ export class SessionService { get(moduleName?: string): T; get(moduleName: string, key: keyof T): T[keyof T]; get(moduleName?: string, key?: keyof T): T | T[keyof T] { - return this.localStorage.get(moduleName, key); + return this.localStorage.get(moduleName!, key!); } set(moduleName: string, keyOrData: string | object, data?: unknown): void { diff --git a/back/tsconfig.json b/back/tsconfig.json index 80465ab7c..4188235fe 100644 --- a/back/tsconfig.json +++ b/back/tsconfig.json @@ -7,6 +7,8 @@ "outDir": "./dist", "types": ["node", "jest"], "baseUrl": "./", + "ignoreDeprecations": "6.0", + "skipLibCheck": true, "sourceMap": true, "declaration": true, "isolatedModules": true, From 8904edd4546968c0d6de4093dea040abad9098df Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Mon, 6 Jul 2026 16:51:27 +0200 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=9A=A8=20(back):=20fix=20TS6=20type?= =?UTF-8?q?=20errors=20across=203=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem** TS6 6.0 tightens `Object.entries()` on `unknown`, removes the `glob` global, disallows `symbol` as object index key, and changes overload resolution for `ejs.renderFile` — 9 type errors blocked the build. Additionally, lodash `chain()` silently handled `undefined` inputs but native `.flatMap()` throws, and the null→undefined change in `oidc-client.controller` broke its test expectation. **Proposal** - Cast `Object.entries` arg to `Record` and add index signature casts for `panvaFormatted` - Import `glob` from `node:fs/promises` and mock as async iterable - Replace `Symbol("sessionCookieName")` with a string literal - Annotate `markdownGenerateResult` as `string[]` - Use `as any` on ejs mock callback and generator mock where type boundaries don't risk correctness - Guard `getIdpDomains` with `idps ?? []` to preserve null-safety - Update oidc-client controller spec to expect `undefined` over `null` --- .../oidc-client.controller.spec.ts | 4 +-- .../src/services/email-validator.service.ts | 2 +- .../src/cli/export-exceptions/runner.spec.ts | 34 ++++++++++++++----- ...identity-provider-adapter-mongo.service.ts | 22 +++++++----- .../services/session-cookies.service.spec.ts | 2 +- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/back/apps/core-fca-low/src/controllers/oidc-client.controller.spec.ts b/back/apps/core-fca-low/src/controllers/oidc-client.controller.spec.ts index aae6552f1..516fe1461 100644 --- a/back/apps/core-fca-low/src/controllers/oidc-client.controller.spec.ts +++ b/back/apps/core-fca-low/src/controllers/oidc-client.controller.spec.ts @@ -284,8 +284,8 @@ describe("OidcClientController", () => { expect(userSession.get).toHaveBeenCalled(); // Expect nonce and state removal expect(userSession.set).toHaveBeenCalledWith({ - idpNonce: null, - idpState: null, + idpNonce: undefined, + idpState: undefined, }); expect(logger.track).toHaveBeenCalledWith("IDP_CALLEDBACK"); expect(oidcClient.getToken).toHaveBeenCalledWith({ diff --git a/back/libs/email-validator/src/services/email-validator.service.ts b/back/libs/email-validator/src/services/email-validator.service.ts index fb61ea855..54842f149 100644 --- a/back/libs/email-validator/src/services/email-validator.service.ts +++ b/back/libs/email-validator/src/services/email-validator.service.ts @@ -74,7 +74,7 @@ export class EmailValidatorService { private async getIdpDomains() { const idps = await this.identityProviderAdapterMongoService.getList(); - const domains = uniq(idps.flatMap((idp) => idp.fqdns ?? [])); + const domains = uniq((idps ?? []).flatMap((idp) => idp.fqdns ?? [])); return domains; } diff --git a/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts b/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts index a8f276f96..d2e460a68 100644 --- a/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts +++ b/back/libs/exceptions/src/cli/export-exceptions/runner.spec.ts @@ -1,6 +1,7 @@ import { HttpStatus } from "@nestjs/common"; import ejs from "ejs"; import fs from "fs"; +import { glob } from "node:fs/promises"; import { format } from "prettier"; import { BaseException } from "../../exceptions"; import { ExceptionClass } from "../../types"; @@ -15,6 +16,7 @@ jest.mock("ejs"); jest.mock("prettier", () => ({ format: jest.fn().mockResolvedValue(""), })); +jest.mock("node:fs/promises"); jest.mock("./markdown-generator"); describe("Runner", () => { @@ -271,7 +273,7 @@ describe("Runner", () => { // Given jest .spyOn(ejs, "renderFile") - .mockImplementationOnce(renderFileMockErrorImplementation); + .mockImplementationOnce(renderFileMockErrorImplementation as any); // Then await expect(Runner.renderFile(file, dataMock)).rejects.toEqual("error"); }); @@ -279,7 +281,7 @@ describe("Runner", () => { // Given jest .spyOn(ejs, "renderFile") - .mockImplementationOnce(renderFileMockSuccesImplementation); + .mockImplementationOnce(renderFileMockSuccesImplementation as any); // When const result = await Runner.renderFile(file, dataMock); // Then @@ -324,14 +326,28 @@ describe("Runner", () => { }); describe("getExceptionsFilesPath", () => { - it("should call return glob.sync result", () => { + it("should call and return glob result", async () => { // Given - jest - .spyOn(glob, "sync") - .mockReturnValue(["/my/file/is/here.exception.ts"]); + let called = false; + const asyncIterable = { + [Symbol.asyncIterator]: () => ({ + next: () => { + if (called) { + return Promise.resolve({ value: undefined, done: true }); + } + called = true; + return Promise.resolve({ + value: "/my/file/is/here.exception.ts", + done: false, + }); + }, + return: () => Promise.resolve({ value: undefined, done: true }), + }), + }; + (glob as jest.Mock).mockReturnValue(asyncIterable as any); const pattern = "/**/*.exception.ts"; // When - const result = Runner.getExceptionsFilesPath(["/"], pattern); + const result = await Runner.getExceptionsFilesPath(["/"], pattern); // Then expect(result).toEqual(["/my/file/is/here.exception.ts"]); @@ -342,12 +358,12 @@ describe("Runner", () => { // Given const getExceptionsFilesPathResult: string[] = []; const loadExceptionsResult = [{ scope: 2 }, { scope: 4 }, { scope: 6 }]; - const markdownGenerateResult = []; + const markdownGenerateResult: string[] = []; const renderFileResult = ""; const generatorSpy = jest.spyOn(MarkdownGenerator, "generate"); beforeEach(() => { - generatorSpy.mockImplementation(() => markdownGenerateResult); + generatorSpy.mockImplementation(() => markdownGenerateResult as any); mockedFormat.mockResolvedValue(renderFileResult); jest.spyOn(fs, "writeFileSync").mockImplementation(() => {}); jest.spyOn(console, "log").mockImplementation(() => {}); diff --git a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts index 7602a660f..de51b8a7a 100644 --- a/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts +++ b/back/libs/identity-provider-adapter-mongo/src/identity-provider-adapter-mongo.service.ts @@ -198,15 +198,19 @@ export class IdentityProviderAdapterMongoService implements IIdentityProviderAda federationServerMetadata: {} as FederationServerMetadata, }; - Object.entries(result).forEach(([key, value]) => { - if (CLIENT_METADATA.includes(key as (typeof CLIENT_METADATA)[number])) { - panvaFormatted.federationClientMetadata[key] = value; - } else if (IDP_METADATA.includes(key as (typeof IDP_METADATA)[number])) { - panvaFormatted.federationServerMetadata[key] = value; - } else { - panvaFormatted[key] = value; - } - }); + Object.entries(result as Record).forEach( + ([key, value]) => { + if (CLIENT_METADATA.includes(key as (typeof CLIENT_METADATA)[number])) { + panvaFormatted.federationClientMetadata[key] = value as any; + } else if ( + IDP_METADATA.includes(key as (typeof IDP_METADATA)[number]) + ) { + panvaFormatted.federationServerMetadata[key] = value as any; + } else { + (panvaFormatted as Record)[key] = value; + } + }, + ); return panvaFormatted as IdentityProviderMetadata; } diff --git a/back/libs/session/src/services/session-cookies.service.spec.ts b/back/libs/session/src/services/session-cookies.service.spec.ts index 7231bb433..f6f687923 100644 --- a/back/libs/session/src/services/session-cookies.service.spec.ts +++ b/back/libs/session/src/services/session-cookies.service.spec.ts @@ -13,7 +13,7 @@ describe("SessionCookiesService", () => { const configMock = getConfigMock(); const configDataMock = { cookieOptions: { foo: "bar" }, - sessionCookieName: Symbol("sessionCookieName"), + sessionCookieName: "sessionCookieName", }; const sessionId = "sessionId";