From 81ce5d0db3252dc8d7c754e1cba64f51240a1bde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 00:08:08 +0000 Subject: [PATCH 1/8] chore(deps): update dependency jose to v5 --- packages-backend/express/package.json | 2 +- pnpm-lock.yaml | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages-backend/express/package.json b/packages-backend/express/package.json index 41e939b0bd..54751860e6 100644 --- a/packages-backend/express/package.json +++ b/packages-backend/express/package.json @@ -29,7 +29,7 @@ "devDependencies": { "@tsconfig/node16": "^16.1.1", "@types/jsonwebtoken": "^9.0.2", - "jose": "2.0.7", + "jose": "5.3.0", "msw": "0.49.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 708202f747..d4ef1866c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1245,8 +1245,8 @@ importers: specifier: ^9.0.2 version: 9.0.2 jose: - specifier: 2.0.7 - version: 2.0.7 + specifier: 5.3.0 + version: 5.3.0 msw: specifier: 0.49.3 version: 0.49.3(typescript@5.0.4) @@ -6863,7 +6863,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.5 - '@babel/helper-module-imports': 7.24.3 + '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 babel-plugin-polyfill-corejs2: 0.4.5(@babel/core@7.24.5) babel-plugin-polyfill-corejs3: 0.8.3(@babel/core@7.24.5) @@ -7545,7 +7545,7 @@ packages: dependencies: '@babel/core': 7.23.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 + '@babel/helper-validator-option': 7.22.15 '@babel/plugin-transform-react-display-name': 7.22.5(@babel/core@7.23.0) '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.23.0) '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.23.0) @@ -7560,7 +7560,7 @@ packages: dependencies: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 + '@babel/helper-validator-option': 7.22.15 '@babel/plugin-transform-react-display-name': 7.22.5(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.24.5) @@ -8917,7 +8917,7 @@ packages: peerDependencies: react: 17.x dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.24.4 '@babel/runtime-corejs3': 7.22.15 '@commercetools-uikit/accessible-button': 19.2.0(@types/react@17.0.80)(react-dom@17.0.2)(react@17.0.2) '@commercetools-uikit/design-system': 19.2.0(@types/react@17.0.80)(react-dom@17.0.2) @@ -13635,6 +13635,7 @@ packages: /@panva/asn1.js@1.0.0: resolution: {integrity: sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==} engines: {node: '>=10.13.0'} + dev: false /@peculiar/asn1-schema@2.3.6: resolution: {integrity: sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==} @@ -23175,11 +23176,16 @@ packages: engines: {node: '>=10.13.0 < 13 || >=13.7.0'} dependencies: '@panva/asn1.js': 1.0.0 + dev: false /jose@4.13.2: resolution: {integrity: sha512-GMUKtV+l05F6NY/06nM7rucHM6Ktvw6sxnyRqINBNWS/hCM/bBk7kanOEckRP8xtC/jzuGfTRVZvkjjuy+g4dA==} dev: false + /jose@5.3.0: + resolution: {integrity: sha512-IChe9AtAE79ru084ow8jzkN2lNrG3Ntfiv65Cvj9uOCE2m5LNsdHG+9EbxWxAoWRF9TgDOqLN5jm08++owDVRg==} + dev: true + /js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} From 3955bc1c1e55cb0e7620468551ad221f17d90880 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:44:28 +0000 Subject: [PATCH 2/8] chore(deps): update dependency jose to v5 --- packages-backend/express/package.json | 2 +- pnpm-lock.yaml | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages-backend/express/package.json b/packages-backend/express/package.json index 41e939b0bd..0d9a6fec89 100644 --- a/packages-backend/express/package.json +++ b/packages-backend/express/package.json @@ -29,7 +29,7 @@ "devDependencies": { "@tsconfig/node16": "^16.1.1", "@types/jsonwebtoken": "^9.0.2", - "jose": "2.0.7", + "jose": "5.4.0", "msw": "0.49.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e95bea3d2..8f0b5d293c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1245,8 +1245,8 @@ importers: specifier: ^9.0.2 version: 9.0.2 jose: - specifier: 2.0.7 - version: 2.0.7 + specifier: 5.4.0 + version: 5.4.0 msw: specifier: 0.49.3 version: 0.49.3(typescript@5.0.4) @@ -13880,6 +13880,7 @@ packages: /@panva/asn1.js@1.0.0: resolution: {integrity: sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==} engines: {node: '>=10.13.0'} + dev: false /@peculiar/asn1-schema@2.3.6: resolution: {integrity: sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==} @@ -23430,11 +23431,16 @@ packages: engines: {node: '>=10.13.0 < 13 || >=13.7.0'} dependencies: '@panva/asn1.js': 1.0.0 + dev: false /jose@4.13.2: resolution: {integrity: sha512-GMUKtV+l05F6NY/06nM7rucHM6Ktvw6sxnyRqINBNWS/hCM/bBk7kanOEckRP8xtC/jzuGfTRVZvkjjuy+g4dA==} dev: false + /jose@5.4.0: + resolution: {integrity: sha512-6rpxTHPAQyWMb9A35BroFl1Sp0ST3DpPcm5EVIxZxdH+e0Hv9fwhyB3XLKFUcHNpdSDnETmBfuPPTTlYz5+USw==} + dev: true + /js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} From 5bf99e5c524df5cafaa421acddb184cd39032eda Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Tue, 4 Jun 2024 18:34:03 +0200 Subject: [PATCH 3/8] refactor(express): updates to make the new jose dependency version work --- .../src/middlewares/fixtures/jwt-token.ts | 60 +++-- .../middlewares/session-middleware.spec.ts | 208 +++++++++--------- packages/jest-preset-mc-app/jest-preset.js | 4 + .../module-exports-resolver.js | 1 + 4 files changed, 157 insertions(+), 116 deletions(-) diff --git a/packages-backend/express/src/middlewares/fixtures/jwt-token.ts b/packages-backend/express/src/middlewares/fixtures/jwt-token.ts index ac0b9a6e40..fccb25c8ba 100644 --- a/packages-backend/express/src/middlewares/fixtures/jwt-token.ts +++ b/packages-backend/express/src/middlewares/fixtures/jwt-token.ts @@ -1,19 +1,49 @@ -import { JWT, JWK, JWKS } from 'jose'; +import { + exportJWK, + generateKeyPair, + type KeyLike, + SignJWT, + type JWK, +} from 'jose'; -const keyRS256 = JWK.generateSync('RSA', 2048, { use: 'sig', alg: 'RS256' }); +let keyRS256: KeyLike; +let jwksStore: { keys: JWK[] }; -const jwksStore = new JWKS.KeyStore([keyRS256]); +async function initialize() { + // Generate RSA key pair with 2048 bits for the RS256 algorithm + const { publicKey, privateKey } = await generateKeyPair('RS256', { + modulusLength: 2048, + }); + keyRS256 = privateKey; -const createToken = (options: { issuer: string; audience: string }) => - JWT.sign( - { - sub: 'user-id', - iss: options.issuer, - aud: options.audience, - [`${options.issuer}/claims/project_key`]: 'project-key', - }, - keyRS256, - { algorithm: 'RS256' } - ); + // Export the public key to JWK format + const publicJWK: JWK = await exportJWK(publicKey); -export { jwksStore, createToken }; + // Add the necessary properties for the JWKS + publicJWK.use = 'sig'; // Signature + publicJWK.alg = 'RS256'; // Algorithm + publicJWK.kid = 'example-key-id'; // Key ID + + jwksStore = { + keys: [publicJWK], + }; +} + +const createToken = (options: { issuer: string; audience: string }) => { + if (!keyRS256) { + throw new Error( + 'Key not initialized. Please call the "initialize" function first.' + ); + } + + return new SignJWT({ + [`${options.issuer}/claims/project_key`]: 'project-key', + }) + .setAudience(options.audience) + .setIssuer(options.issuer) + .setProtectedHeader({ alg: 'RS256' }) + .setSubject('user-id') + .sign(keyRS256); +}; + +export { initialize, jwksStore, createToken }; diff --git a/packages-backend/express/src/middlewares/session-middleware.spec.ts b/packages-backend/express/src/middlewares/session-middleware.spec.ts index 953b28be9e..5dd900b667 100644 --- a/packages-backend/express/src/middlewares/session-middleware.spec.ts +++ b/packages-backend/express/src/middlewares/session-middleware.spec.ts @@ -31,11 +31,12 @@ function waitForSessionMiddleware( afterEach(() => { mockServer.resetHandlers(); }); -beforeAll(() => +beforeAll(async () => { + await fixtureJWTToken.initialize(); mockServer.listen({ onUnhandledRequest: 'error', - }) -); + }); +}); afterAll(() => mockServer.close()); describe.each` @@ -53,12 +54,12 @@ describe.each` beforeEach(() => { mockServer.use( rest.get(`${issuer}/.well-known/jwks.json`, (_req, res, ctx) => - res(ctx.json(fixtureJWTToken.jwksStore.toJWKS())) + res(ctx.json(fixtureJWTToken.jwksStore)) ) ); }); - function setupTest(options?: { + async function setupTest(options?: { middlewareOptions?: Record; requestOptions?: Record; }) { @@ -67,13 +68,14 @@ describe.each` issuer: cloudIdentifier, ...options?.middlewareOptions, }); + const token = await fixtureJWTToken.createToken({ + issuer, + audience: 'http://test-server/foo/bar', + }); const fakeRequest = { method: 'GET', headers: { - authorization: `Bearer ${fixtureJWTToken.createToken({ - issuer, - audience: 'http://test-server/foo/bar', - })}`, + authorization: `Bearer ${token}`, // The following headers are validated as they are expected to be present // in the incoming request. // To ensure we can correctly read the header values no matter if the @@ -92,7 +94,8 @@ describe.each` } it('should verify the token and attach the session info to the request', async () => { - const { sessionMiddleware, fakeRequest, fakeResponse } = setupTest(); + const { sessionMiddleware, fakeRequest, fakeResponse } = + await setupTest(); await waitForSessionMiddleware( sessionMiddleware, @@ -108,7 +111,7 @@ describe.each` }); it('should resolve the original url externally when a resolver is provided (using lambda v2)', async () => { - const { sessionMiddleware, fakeRequest, fakeResponse } = setupTest({ + const { sessionMiddleware, fakeRequest, fakeResponse } = await setupTest({ middlewareOptions: { getRequestUrl: (request: TMockAWSLambdaRequestV2) => { return `${request.rawPath}${ @@ -137,7 +140,7 @@ describe.each` }); it('should fail if incoming request does not contain expected URL params and no urlProvider is provided', async () => { - const { sessionMiddleware, fakeRequest, fakeResponse } = setupTest({ + const { sessionMiddleware, fakeRequest, fakeResponse } = await setupTest({ requestOptions: { originalUrl: undefined, rawPath: '/foo/bar', @@ -155,7 +158,7 @@ describe.each` }); it('should fail if the resolved request URI does not have a leading "/"', async () => { - const { sessionMiddleware, fakeRequest, fakeResponse } = setupTest({ + const { sessionMiddleware, fakeRequest, fakeResponse } = await setupTest({ middlewareOptions: { getRequestUrl: () => `foo/bar`, // <-- missing leading "/" }, @@ -170,12 +173,13 @@ describe.each` if (!cloudIdentifier.startsWith('http')) { it('should infer cloud identifier from custom HTTP header instead of given "mcApiUrl"', async () => { - const { sessionMiddleware, fakeRequest, fakeResponse } = setupTest({ - middlewareOptions: { - issuer: 'https://mc-api.another-ct-test.com', // This value should not matter - inferIssuer: true, - }, - }); + const { sessionMiddleware, fakeRequest, fakeResponse } = + await setupTest({ + middlewareOptions: { + issuer: 'https://mc-api.another-ct-test.com', // This value should not matter + inferIssuer: true, + }, + }); await waitForSessionMiddleware( sessionMiddleware, @@ -193,85 +197,87 @@ describe.each` } ); -describe('when audience is missing', () => { - it('should throw a validation error', () => { - // @ts-ignore - expect(() => createSessionMiddleware({})).toThrow( - 'Missing required option "audience"' - ); - }); -}); -describe('when issuer is missing', () => { - it('should throw a validation error', () => { - expect(() => - // @ts-ignore - createSessionMiddleware({ audience: 'http://test-server' }) - ).toThrow('Missing required option "issuer"'); - }); -}); -describe('when issuer is not a valid URL', () => { - it('should throw a validation error', () => { - expect(() => - createSessionMiddleware({ - audience: 'http://test-server', - issuer: 'invalid url', - }) - ).toThrow('Invalid issuer URL'); - }); -}); -describe('when "X-MC-API-Cloud-Identifier" is missing', () => { - it('should throw a validation error', async () => { - const fakeRequest = { - method: 'GET', - headers: { - authorization: `Bearer ${fixtureJWTToken.createToken({ - issuer: CLOUD_IDENTIFIERS.GCP_EU, - audience: 'http://test-server/foo/bar', - })}`, - 'x-mc-api-forward-to-version': 'v2', - }, - originalUrl: '/foo/bar', - }; - const fakeResponse = {}; - const sessionAuthVerifier = createSessionAuthVerifier({ - audience: 'http://test-server', - issuer: CLOUD_IDENTIFIERS.GCP_EU, - }); - await expect( - // @ts-ignore - sessionAuthVerifier(fakeRequest, fakeResponse) - ).rejects.toMatchObject({ - message: expect.stringContaining( - 'Missing "X-MC-API-Cloud-Identifier" header' - ), - }); - }); -}); -describe('when "X-MC-API-Forward-To-Version" is missing', () => { - it('should throw a validation error', async () => { - const fakeRequest = { - method: 'GET', - headers: { - authorization: `Bearer ${fixtureJWTToken.createToken({ - issuer: CLOUD_IDENTIFIERS.GCP_EU, - audience: 'http://test-server/foo/bar', - })}`, - 'x-mc-api-cloud-identifier': CLOUD_IDENTIFIERS.GCP_EU, - }, - originalUrl: '/foo/bar', - }; - const fakeResponse = {}; - const sessionAuthVerifier = createSessionAuthVerifier({ - audience: 'http://test-server', - issuer: CLOUD_IDENTIFIERS.GCP_EU, - }); - await expect( - // @ts-ignore - sessionAuthVerifier(fakeRequest, fakeResponse) - ).rejects.toMatchObject({ - message: expect.stringContaining( - 'Missing "X-MC-API-Forward-To-Version" header' - ), - }); - }); -}); +// describe('when audience is missing', () => { +// it('should throw a validation error', () => { +// // @ts-ignore +// expect(() => createSessionMiddleware({})).toThrow( +// 'Missing required option "audience"' +// ); +// }); +// }); +// describe('when issuer is missing', () => { +// it('should throw a validation error', () => { +// expect(() => +// // @ts-ignore +// createSessionMiddleware({ audience: 'http://test-server' }) +// ).toThrow('Missing required option "issuer"'); +// }); +// }); +// describe('when issuer is not a valid URL', () => { +// it('should throw a validation error', () => { +// expect(() => +// createSessionMiddleware({ +// audience: 'http://test-server', +// issuer: 'invalid url', +// }) +// ).toThrow('Invalid issuer URL'); +// }); +// }); +// describe('when "X-MC-API-Cloud-Identifier" is missing', () => { +// it('should throw a validation error', async () => { +// const token = await fixtureJWTToken.createToken({ +// issuer: CLOUD_IDENTIFIERS.GCP_EU, +// audience: 'http://test-server/foo/bar', +// }); +// const fakeRequest = { +// method: 'GET', +// headers: { +// authorization: `Bearer ${token}`, +// 'x-mc-api-forward-to-version': 'v2', +// }, +// originalUrl: '/foo/bar', +// }; +// const fakeResponse = {}; +// const sessionAuthVerifier = createSessionAuthVerifier({ +// audience: 'http://test-server', +// issuer: CLOUD_IDENTIFIERS.GCP_EU, +// }); +// await expect( +// // @ts-ignore +// sessionAuthVerifier(fakeRequest, fakeResponse) +// ).rejects.toMatchObject({ +// message: expect.stringContaining( +// 'Missing "X-MC-API-Cloud-Identifier" header' +// ), +// }); +// }); +// }); +// describe('when "X-MC-API-Forward-To-Version" is missing', () => { +// it('should throw a validation error', async () => { +// const token = await fixtureJWTToken.createToken({ +// issuer: CLOUD_IDENTIFIERS.GCP_EU, +// audience: 'http://test-server/foo/bar', +// }); +// const fakeRequest = { +// method: 'GET', +// headers: { +// authorization: `Bearer ${token}`, +// 'x-mc-api-cloud-identifier': CLOUD_IDENTIFIERS.GCP_EU, +// }, +// originalUrl: '/foo/bar', +// }; +// const fakeResponse = {}; +// const sessionAuthVerifier = createSessionAuthVerifier({ +// audience: 'http://test-server', +// issuer: CLOUD_IDENTIFIERS.GCP_EU, +// }); +// await expect( +// // @ts-ignore +// sessionAuthVerifier(fakeRequest, fakeResponse) +// ).rejects.toMatchObject({ +// message: expect.stringContaining( +// 'Missing "X-MC-API-Forward-To-Version" header' +// ), +// }); +// }); +// }); diff --git a/packages/jest-preset-mc-app/jest-preset.js b/packages/jest-preset-mc-app/jest-preset.js index 1bb1e080e6..96c0634eb9 100644 --- a/packages/jest-preset-mc-app/jest-preset.js +++ b/packages/jest-preset-mc-app/jest-preset.js @@ -24,6 +24,10 @@ module.exports = { 'process.env': { NODE_ENV: 'test', }, + // This is required for the `jose` library to work in the test environment. + // We use it in the packages-backend/express package. + // Reference: https://github.com/jestjs/jest/issues/4422#issuecomment-770274099 + Uint8Array: Uint8Array, }, moduleFileExtensions: ['js', 'mjs', 'cjs', 'jsx', 'json'], moduleDirectories: ['src', 'node_modules'], diff --git a/packages/jest-preset-mc-app/module-exports-resolver.js b/packages/jest-preset-mc-app/module-exports-resolver.js index edfa7ec834..8e32d49a5e 100644 --- a/packages/jest-preset-mc-app/module-exports-resolver.js +++ b/packages/jest-preset-mc-app/module-exports-resolver.js @@ -2,6 +2,7 @@ const modulesWithFaultyExports = [ '@react-hook/resize-observer', '@react-hook/passive-layout-effect', '@react-hook/latest', + 'jose', ]; // https://jestjs.io/docs/configuration#resolver-string From e5d049cb44c72bc1e30e8d614f287e69c931b982 Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Tue, 4 Jun 2024 18:52:57 +0200 Subject: [PATCH 4/8] refactor: remove unused imports --- .../express/src/middlewares/session-middleware.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages-backend/express/src/middlewares/session-middleware.spec.ts b/packages-backend/express/src/middlewares/session-middleware.spec.ts index 5dd900b667..16948fdff0 100644 --- a/packages-backend/express/src/middlewares/session-middleware.spec.ts +++ b/packages-backend/express/src/middlewares/session-middleware.spec.ts @@ -1,8 +1,6 @@ import { rest } from 'msw'; import type { Handler } from 'express'; import { setupServer } from 'msw/node'; -import { createSessionAuthVerifier } from '../auth'; -import { CLOUD_IDENTIFIERS } from '../constants'; import { TBaseRequest } from '../types'; import * as fixtureJWTToken from './fixtures/jwt-token'; import createSessionMiddleware from './session-middleware'; From 9f6151d577b0cd20a99a2492ef2ca8f145c4b8cb Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Tue, 4 Jun 2024 18:56:02 +0200 Subject: [PATCH 5/8] fix(express): fix tests --- .../middlewares/session-middleware.spec.ts | 170 +++++++++--------- 1 file changed, 86 insertions(+), 84 deletions(-) diff --git a/packages-backend/express/src/middlewares/session-middleware.spec.ts b/packages-backend/express/src/middlewares/session-middleware.spec.ts index 16948fdff0..cb3421688b 100644 --- a/packages-backend/express/src/middlewares/session-middleware.spec.ts +++ b/packages-backend/express/src/middlewares/session-middleware.spec.ts @@ -1,6 +1,8 @@ import { rest } from 'msw'; import type { Handler } from 'express'; import { setupServer } from 'msw/node'; +import { createSessionAuthVerifier } from '../auth'; +import { CLOUD_IDENTIFIERS } from '../constants'; import { TBaseRequest } from '../types'; import * as fixtureJWTToken from './fixtures/jwt-token'; import createSessionMiddleware from './session-middleware'; @@ -195,87 +197,87 @@ describe.each` } ); -// describe('when audience is missing', () => { -// it('should throw a validation error', () => { -// // @ts-ignore -// expect(() => createSessionMiddleware({})).toThrow( -// 'Missing required option "audience"' -// ); -// }); -// }); -// describe('when issuer is missing', () => { -// it('should throw a validation error', () => { -// expect(() => -// // @ts-ignore -// createSessionMiddleware({ audience: 'http://test-server' }) -// ).toThrow('Missing required option "issuer"'); -// }); -// }); -// describe('when issuer is not a valid URL', () => { -// it('should throw a validation error', () => { -// expect(() => -// createSessionMiddleware({ -// audience: 'http://test-server', -// issuer: 'invalid url', -// }) -// ).toThrow('Invalid issuer URL'); -// }); -// }); -// describe('when "X-MC-API-Cloud-Identifier" is missing', () => { -// it('should throw a validation error', async () => { -// const token = await fixtureJWTToken.createToken({ -// issuer: CLOUD_IDENTIFIERS.GCP_EU, -// audience: 'http://test-server/foo/bar', -// }); -// const fakeRequest = { -// method: 'GET', -// headers: { -// authorization: `Bearer ${token}`, -// 'x-mc-api-forward-to-version': 'v2', -// }, -// originalUrl: '/foo/bar', -// }; -// const fakeResponse = {}; -// const sessionAuthVerifier = createSessionAuthVerifier({ -// audience: 'http://test-server', -// issuer: CLOUD_IDENTIFIERS.GCP_EU, -// }); -// await expect( -// // @ts-ignore -// sessionAuthVerifier(fakeRequest, fakeResponse) -// ).rejects.toMatchObject({ -// message: expect.stringContaining( -// 'Missing "X-MC-API-Cloud-Identifier" header' -// ), -// }); -// }); -// }); -// describe('when "X-MC-API-Forward-To-Version" is missing', () => { -// it('should throw a validation error', async () => { -// const token = await fixtureJWTToken.createToken({ -// issuer: CLOUD_IDENTIFIERS.GCP_EU, -// audience: 'http://test-server/foo/bar', -// }); -// const fakeRequest = { -// method: 'GET', -// headers: { -// authorization: `Bearer ${token}`, -// 'x-mc-api-cloud-identifier': CLOUD_IDENTIFIERS.GCP_EU, -// }, -// originalUrl: '/foo/bar', -// }; -// const fakeResponse = {}; -// const sessionAuthVerifier = createSessionAuthVerifier({ -// audience: 'http://test-server', -// issuer: CLOUD_IDENTIFIERS.GCP_EU, -// }); -// await expect( -// // @ts-ignore -// sessionAuthVerifier(fakeRequest, fakeResponse) -// ).rejects.toMatchObject({ -// message: expect.stringContaining( -// 'Missing "X-MC-API-Forward-To-Version" header' -// ), -// }); -// }); -// }); +describe('when audience is missing', () => { + it('should throw a validation error', () => { + // @ts-ignore + expect(() => createSessionMiddleware({})).toThrow( + 'Missing required option "audience"' + ); + }); +}); +describe('when issuer is missing', () => { + it('should throw a validation error', () => { + expect(() => + // @ts-ignore + createSessionMiddleware({ audience: 'http://test-server' }) + ).toThrow('Missing required option "issuer"'); + }); +}); +describe('when issuer is not a valid URL', () => { + it('should throw a validation error', () => { + expect(() => + createSessionMiddleware({ + audience: 'http://test-server', + issuer: 'invalid url', + }) + ).toThrow('Invalid issuer URL'); + }); +}); +describe('when "X-MC-API-Cloud-Identifier" is missing', () => { + it('should throw a validation error', async () => { + const token = await fixtureJWTToken.createToken({ + issuer: CLOUD_IDENTIFIERS.GCP_EU, + audience: 'http://test-server/foo/bar', + }); + const fakeRequest = { + method: 'GET', + headers: { + authorization: `Bearer ${token}`, + 'x-mc-api-forward-to-version': 'v2', + }, + originalUrl: '/foo/bar', + }; + const fakeResponse = {}; + const sessionAuthVerifier = createSessionAuthVerifier({ + audience: 'http://test-server', + issuer: CLOUD_IDENTIFIERS.GCP_EU, + }); + await expect( + // @ts-ignore + sessionAuthVerifier(fakeRequest, fakeResponse) + ).rejects.toMatchObject({ + message: expect.stringContaining( + 'Missing "X-MC-API-Cloud-Identifier" header' + ), + }); + }); +}); +describe('when "X-MC-API-Forward-To-Version" is missing', () => { + it('should throw a validation error', async () => { + const token = await fixtureJWTToken.createToken({ + issuer: CLOUD_IDENTIFIERS.GCP_EU, + audience: 'http://test-server/foo/bar', + }); + const fakeRequest = { + method: 'GET', + headers: { + authorization: `Bearer ${token}`, + 'x-mc-api-cloud-identifier': CLOUD_IDENTIFIERS.GCP_EU, + }, + originalUrl: '/foo/bar', + }; + const fakeResponse = {}; + const sessionAuthVerifier = createSessionAuthVerifier({ + audience: 'http://test-server', + issuer: CLOUD_IDENTIFIERS.GCP_EU, + }); + await expect( + // @ts-ignore + sessionAuthVerifier(fakeRequest, fakeResponse) + ).rejects.toMatchObject({ + message: expect.stringContaining( + 'Missing "X-MC-API-Forward-To-Version" header' + ), + }); + }); +}); From 122a07f8ea299a6873bcfaf6b8e8b7170d76a3ee Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Wed, 5 Jun 2024 12:16:22 +0200 Subject: [PATCH 6/8] refactor: move new jest configuration attribute --- jest.test.config.js | 6 ++++++ packages/jest-preset-mc-app/jest-preset.js | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jest.test.config.js b/jest.test.config.js index 7af3316dc9..377d054a13 100644 --- a/jest.test.config.js +++ b/jest.test.config.js @@ -5,6 +5,12 @@ process.env.ENABLE_NEW_JSX_TRANSFORM = 'true'; */ module.exports = { preset: '@commercetools-frontend/jest-preset-mc-app/typescript', + globals: { + // This is required for the `jose` library to work in the test environment. + // We use it in the packages-backend/express package. + // Reference: https://github.com/jestjs/jest/issues/4422#issuecomment-770274099 + Uint8Array: Uint8Array, + }, moduleDirectories: [ 'application-templates', 'packages', diff --git a/packages/jest-preset-mc-app/jest-preset.js b/packages/jest-preset-mc-app/jest-preset.js index 96c0634eb9..1bb1e080e6 100644 --- a/packages/jest-preset-mc-app/jest-preset.js +++ b/packages/jest-preset-mc-app/jest-preset.js @@ -24,10 +24,6 @@ module.exports = { 'process.env': { NODE_ENV: 'test', }, - // This is required for the `jose` library to work in the test environment. - // We use it in the packages-backend/express package. - // Reference: https://github.com/jestjs/jest/issues/4422#issuecomment-770274099 - Uint8Array: Uint8Array, }, moduleFileExtensions: ['js', 'mjs', 'cjs', 'jsx', 'json'], moduleDirectories: ['src', 'node_modules'], From b928a145e6b4cd6d21a97b186bb613134901f9b5 Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Wed, 5 Jun 2024 16:39:00 +0200 Subject: [PATCH 7/8] ci: testing playground branch deployments --- playground/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/.env b/playground/.env index 12a40f8493..69dc35a3d6 100644 --- a/playground/.env +++ b/playground/.env @@ -1,5 +1,5 @@ CLOUD_IDENTIFIER="gcp-eu" -APP_URL="https://app-kit-playground.vercel.app" +APP_URL="${VERCEL_URL}" ECHO_SERVER_URL="https://app-kit-playground.vercel.app/api/echo" PLAYGROUND_API_AUDIENCE="https://app-kit-playground.vercel.app" HOST_GCP_STAGING="" From 342981995df081e401fade63f16e0bde40a5e62b Mon Sep 17 00:00:00 2001 From: Carlos Cortizas Date: Wed, 5 Jun 2024 16:41:40 +0200 Subject: [PATCH 8/8] ci: testing playground branch deployments --- playground/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/.env b/playground/.env index 69dc35a3d6..f2ed1c36ba 100644 --- a/playground/.env +++ b/playground/.env @@ -1,5 +1,5 @@ CLOUD_IDENTIFIER="gcp-eu" -APP_URL="${VERCEL_URL}" +APP_URL="https://${VERCEL_URL}" ECHO_SERVER_URL="https://app-kit-playground.vercel.app/api/echo" PLAYGROUND_API_AUDIENCE="https://app-kit-playground.vercel.app" HOST_GCP_STAGING=""