From 244e472285fa890e45664672852aa5991b81ef03 Mon Sep 17 00:00:00 2001 From: Daniel Brooks Date: Thu, 29 Aug 2024 13:22:14 -0700 Subject: [PATCH] test(braze): testing the ins and out of digest --- .../braze-content-proxy/src/main.ts | 31 +++++- packages/jwt-utils/README.md | 4 +- servers/braze-content-proxy/jest.config.js | 1 + servers/braze-content-proxy/jest.setup.js | 10 ++ .../src/routes/digest.integration.ts | 104 ++++++++++++++++++ .../braze-content-proxy/src/routes/digest.ts | 5 +- 6 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 servers/braze-content-proxy/jest.setup.js diff --git a/infrastructure/braze-content-proxy/src/main.ts b/infrastructure/braze-content-proxy/src/main.ts index 210b3a25e..65ae49dea 100644 --- a/infrastructure/braze-content-proxy/src/main.ts +++ b/infrastructure/braze-content-proxy/src/main.ts @@ -159,6 +159,7 @@ class BrazeContentProxy extends TerraformStack { }): PocketALBApplication { const { region, caller, secretsManagerKmsAlias, snsTopic, wafAcl } = dependencies; + const intMaskSecretArn = `arn:aws:secretsmanager:${region.name}:${caller.accountId}:secret:Shared/IntMask`; return new PocketALBApplication(this, 'application', { internal: false, @@ -200,7 +201,35 @@ class BrazeContentProxy extends TerraformStack { }, { name: 'BRAZE_PRIVATE_KEY', - valueFrom: `arn:aws:secretsmanager:${region.name}:${caller.accountId}:secret:${config.name}/${config.environment}/BRAZE_PRIVATE_KEY:`, + valueFrom: `arn:aws:secretsmanager:${region.name}:${caller.accountId}:secret:${config.name}/${config.environment}/PRIVATE_KEY:::`, + }, + { + name: 'CONTACT_HASH', + valueFrom: `${intMaskSecretArn}:contactHash::`, + }, + { + name: 'CHARACTER_MAP', + valueFrom: `${intMaskSecretArn}:characterMap::`, + }, + { + name: 'POSITION_MAP', + valueFrom: `${intMaskSecretArn}:positionMap::`, + }, + { + name: 'MD5_RANDOMIZER', + valueFrom: `${intMaskSecretArn}:md5Randomizer::`, + }, + { + name: 'LETTER_INDEX', + valueFrom: `${intMaskSecretArn}:letterIndex::`, + }, + { + name: 'SALT_1', + valueFrom: `${intMaskSecretArn}:salt1::`, + }, + { + name: 'SALT_2', + valueFrom: `${intMaskSecretArn}:salt2::`, }, ], }, diff --git a/packages/jwt-utils/README.md b/packages/jwt-utils/README.md index d916c026e..073d28925 100644 --- a/packages/jwt-utils/README.md +++ b/packages/jwt-utils/README.md @@ -1,3 +1,3 @@ -# Image Utils +# JWT Utils -We use this repository as a place to keep code we use across our backend services that implement anything to do with image urls +We use this repository as a place to keep code we use across our backend services that implement anything to do with JWTs diff --git a/servers/braze-content-proxy/jest.config.js b/servers/braze-content-proxy/jest.config.js index bc244bf75..a308c5d83 100644 --- a/servers/braze-content-proxy/jest.config.js +++ b/servers/braze-content-proxy/jest.config.js @@ -5,5 +5,6 @@ module.exports = { testPathIgnorePatterns: ['/dist/', '/lambda/'], testTimeout: 10000, displayName: 'braze-content-proxy', + setupFiles: ['./jest.setup.js'], setupFilesAfterEnv: ['jest-extended/all'], }; diff --git a/servers/braze-content-proxy/jest.setup.js b/servers/braze-content-proxy/jest.setup.js new file mode 100644 index 000000000..47f7b4d3a --- /dev/null +++ b/servers/braze-content-proxy/jest.setup.js @@ -0,0 +1,10 @@ +process.env.CHARACTER_MAP = + '[["A",0],["B",0],["C",0],["D",0],["E",0],["y",0],["F",1],["G",1],["H",1],["I",1],["J",1],["z",1],["K",2],["L",2],["M",2],["N",2],["O",2],["P",3],["Q",3],["R",3],["S",3],["T",3],["U",4],["V",4],["W",4],["X",4],["Y",4],["Z",5],["a",5],["b",5],["c",5],["d",5],["e",6],["f",6],["g",6],["h",6],["i",6],["j",7],["k",7],["l",7],["m",7],["n",7],["o",8],["p",8],["q",8],["r",8],["s",8],["t",9],["u",9],["v",9],["w",9],["x",9]]'; +process.env.POSITION_MAP = + '[[9,0],[12,1],[26,2],[59,3],[45,4],[56,5],[23,6],[42,7],[48,8],[18,9],[40,10],[10,11],[37,12],[32,13],[21,14],[16,15]]'; +process.env.MD5_RANDOMIZER = + '[["0",["g"]],["1",["g"]],["2",["h"]],["3",["a"]],["4",["a"]],["5",["3"]],["6",["1"]],["7",["1"]],["8",["7"]],["9",["k"]],["a",["v"]],["b",["X"]],["c",["i"]],["d",["f","T","q"]],["e",["o"]],["f",["O","h","b"]]]'; +process.env.LETTER_INDEX = + '[["a",0],["b",1],["c",2],["d",3],["e",4],["f",5],["0",6]]'; +process.env.SALT_1 = '123asdf'; +process.env.SALT_2 = 'asdaa47'; diff --git a/servers/braze-content-proxy/src/routes/digest.integration.ts b/servers/braze-content-proxy/src/routes/digest.integration.ts index 92db35fbe..92fd102af 100644 --- a/servers/braze-content-proxy/src/routes/digest.integration.ts +++ b/servers/braze-content-proxy/src/routes/digest.integration.ts @@ -3,16 +3,96 @@ import request from 'supertest'; import { Server } from 'http'; import { Application } from 'express'; import { startServer } from '../server'; +import nock, { cleanAll, restore } from 'nock'; +import { UserDigestQuery } from '../generated/graphql/types'; +import { ApolloQueryResult } from '@apollo/client/core'; describe(`get digest`, () => { let app: Application; let server: Server; + const testEncodedUserId = + 'fb792e6e9DE6E3ecI3Ca1CaE49A08497Bc36eA3eD5AacCd0Ba3b1056DbaB89d5'; + const validUrl = `/digest/${testEncodedUserId}?apikey=${config.aws.brazeApiKey}`; + + const fakeResponse: Omit< + ApolloQueryResult, + 'loading' | 'networkStatus' + > = { + data: { + user: { + savedItems: { + edges: [ + { + node: { + item: { + __typename: 'Item', + preview: { + title: 'Cool Item 1', + url: 'https://www.item1.com', + image: { + cachedImages: [ + { + id: 'thumbnail', + url: 'https://image1.com', + }, + ], + }, + }, + }, + }, + }, + { + node: { + item: { + __typename: 'Item', + preview: { + title: '', + url: 'https://item2.com', + image: null, + }, + }, + }, + }, + { + node: { + item: { + __typename: 'Item', + preview: { + title: 'Super Secret', + url: 'https://item3.com', + image: { + cachedImages: [ + { + id: 'thumbnail', + url: 'image2.com', + }, + ], + }, + }, + }, + }, + }, + { + node: { + item: { + __typename: 'PendingItem', + }, + }, + }, + ], + }, + }, + }, + }; + beforeAll(async () => { ({ app, server } = await startServer(0)); }); afterAll(async () => { server.close(); + cleanAll(); + restore(); }); beforeEach(() => { jest.clearAllMocks(); @@ -26,4 +106,28 @@ describe(`get digest`, () => { expect(response.body.error).not.toBeUndefined(); expect(response.body.error).toBe(config.app.INVALID_API_KEY_ERROR_MESSAGE); }); + + it('should return correct data when valid query params are provided', async () => { + nock(config.clientApi.uri).post('/').reply(200, fakeResponse); + + const response = await request(app).get(validUrl); + + expect(response.statusCode).toBe(200); + expect(response.body).toEqual([ + { + imageUrl: 'https://image1.com', + title: 'Cool Item 1', + url: 'https://www.item1.com', + }, + { + title: '', + url: 'https://item2.com', + }, + { + imageUrl: 'image2.com', + title: 'Super Secret', + url: 'https://item3.com', + }, + ]); + }); }); diff --git a/servers/braze-content-proxy/src/routes/digest.ts b/servers/braze-content-proxy/src/routes/digest.ts index 29701379c..9cdf8d1c7 100644 --- a/servers/braze-content-proxy/src/routes/digest.ts +++ b/servers/braze-content-proxy/src/routes/digest.ts @@ -35,7 +35,10 @@ export async function getUserDigest(userId: string) { function transformToBrazePayload( response: ApolloQueryResult, ): BrazeSavedItem[] { - const edges = response.data.user.savedItems.edges; + const edges = response.data.user?.savedItems?.edges; + if (!edges) { + return []; + } const savedItems: BrazeSavedItem[] = edges .filter((edge) => edge.node.item.__typename == 'Item') .map((edge) => {