From ebcd35b85d2d1c5b32c7304ddab6c2630cccdd09 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Tue, 11 Feb 2025 11:46:46 -0800 Subject: [PATCH 1/5] use base64 encoded private key for apns --- src/services/NotificationService.ts | 7 ++++--- test/services/NotificationServiceTests.test.ts | 15 +++------------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/services/NotificationService.ts b/src/services/NotificationService.ts index 6fee796..7953d91 100644 --- a/src/services/NotificationService.ts +++ b/src/services/NotificationService.ts @@ -52,9 +52,10 @@ export class NotificationService { const keyId = process.env.APNS_KEY_ID; const teamId = process.env.APNS_TEAM_ID; - const privateKeyPath = process.env.APNS_KEY_PATH; - if (!privateKeyPath) return; - const privateKey = fs.readFileSync(privateKeyPath); + + const privateKeyBase64 = process.env.APNS_PRIVATE_KEY; + if (!privateKeyBase64) return; + const privateKey = Buffer.from(privateKeyBase64, 'base64').toString('utf-8'); const tokenHeader = { alg: "ES256", diff --git a/test/services/NotificationServiceTests.test.ts b/test/services/NotificationServiceTests.test.ts index 9ef66c6..a3ec0fc 100644 --- a/test/services/NotificationServiceTests.test.ts +++ b/test/services/NotificationServiceTests.test.ts @@ -1,21 +1,14 @@ import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { NotificationService } from "../../src/services/NotificationService"; import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; -import fs from "fs"; import http2 from "http2"; import { IEta, IShuttle, IStop } from "../../src/entities/entities"; import { addMockShuttleToRepository, addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; import EventEmitter = require("node:events"); -jest.mock("fs"); jest.mock("http2"); -const sampleKey = `-----BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgsrmSAZIagOfCP8sB -Wi2CBXG1Oo7v1bispIZCwIr4RDegCgYIKoZIzj0DAQehRANCAATZHxV2wQJLMBq+ -ya+yfGi3g2ZUv6hrfe+j08ytekPHjXS0qzJoVELzKHa6EL9YAoZDXBtB6h+fGhXe -SOcONbaf ------END PRIVATE KEY-----` +const sampleKeyBase64 = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR1RBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJIa3dkd0lCQVFRZ3NybVNBWklhZ09mQ1A4c0IKV2kyQ0JYRzFPbzd2MWJpc3BJWkN3SXI0UkRlZ0NnWUlLb1pJemowREFRZWhSQU5DQUFUWkh4VjJ3UUpMTUJxKwp5YSt5ZkdpM2cyWlV2NmhyZmUrajA4eXRla1BIalhTMHF6Sm9WRUx6S0hhNkVMOVlBb1pEWEJ0QjZoK2ZHaFhlClNPY09OYmFmCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"; /** * Wait for a condition to become true until the timeout @@ -75,11 +68,9 @@ describe("NotificationService", () => { ...process.env, APNS_KEY_ID: "1", APNS_TEAM_ID: "1", - APNS_KEY_PATH: "./dummy-path.p8", - APNS_BUNDLE_ID: "dev.bchen.ProjectInter" + APNS_BUNDLE_ID: "dev.bchen.ProjectInter", + APNS_PRIVATE_KEY: sampleKeyBase64, }; - - (fs.readFileSync as jest.Mock).mockReturnValue(sampleKey); }); beforeEach(() => { From d80df1de23ae2b4df9424ae6306afa529c77ade3 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Tue, 11 Feb 2025 11:47:25 -0800 Subject: [PATCH 2/5] add key to example env --- .env.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 92650db..15ba8cb 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,6 @@ APNS_KEY_ID= APNS_TEAM_ID= APNS_BUNDLE_ID= -APNS_KEY_PATH= + +# base64-encoded APNs private key +APNS_PRIVATE_KEY= From bf1290bbc88dadb9172d4605542d962c70c3bdfa Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Tue, 11 Feb 2025 11:55:33 -0800 Subject: [PATCH 3/5] update environment with APNS_IS_PRODUCTION key --- .env.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.example b/.env.example index 15ba8cb..2e0ac7f 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ +# Set to "1" for true +APNS_IS_PRODUCTION= + APNS_KEY_ID= APNS_TEAM_ID= APNS_BUNDLE_ID= From a74a6c995a8416e6664f416a676d8da50d70e09e Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Tue, 11 Feb 2025 11:58:13 -0800 Subject: [PATCH 4/5] update implementation and test for getAPNsFullUrlToUse --- src/services/NotificationService.ts | 6 +++--- test/services/NotificationServiceTests.test.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/services/NotificationService.ts b/src/services/NotificationService.ts index 7953d91..3ee05b5 100644 --- a/src/services/NotificationService.ts +++ b/src/services/NotificationService.ts @@ -155,9 +155,9 @@ export class NotificationService { const devBaseUrl = "https://api.development.push.apple.com" const prodBaseUrl = "https://api.push.apple.com" - let hostToUse = prodBaseUrl; - if (process.env.NODE_ENV !== "production") { - hostToUse = devBaseUrl; + let hostToUse = devBaseUrl; + if (process.env.APNS_IS_PRODUCTION === "1") { + hostToUse = prodBaseUrl; } const path = "/3/device/" + deviceId; diff --git a/test/services/NotificationServiceTests.test.ts b/test/services/NotificationServiceTests.test.ts index a3ec0fc..7f3cfcf 100644 --- a/test/services/NotificationServiceTests.test.ts +++ b/test/services/NotificationServiceTests.test.ts @@ -189,8 +189,8 @@ describe("NotificationService", () => { }); describe('getAPNsFullUrlToUse', () => { - it('should return the production URL when NODE_ENV is set to "production"', () => { - process.env.NODE_ENV = 'production'; + it('should return the production URL when APNS_IS_PRODUCTION is set to "1"', () => { + process.env.APNS_IS_PRODUCTION = "1"; const deviceId = 'testDeviceId'; const result = NotificationService.getAPNsFullUrlToUse(deviceId); @@ -200,8 +200,8 @@ describe("NotificationService", () => { expect(path).toBe(`/3/device/${deviceId}`); }); - it('should return the sandbox URL when NODE_ENV is not set to "production"', () => { - process.env.NODE_ENV = 'development'; + it('should return the sandbox URL when APNS_IS_PRODUCTION is set to something other than 1', () => { + process.env.APNS_IS_PRODUCTION = "0"; const deviceId = 'testDeviceId'; const result = NotificationService.getAPNsFullUrlToUse(deviceId); From 2d4e20673940416fdb2b5de7c6ac0fc5e7d45eca Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Tue, 11 Feb 2025 12:05:27 -0800 Subject: [PATCH 5/5] lower seconds threshold for notification to fire --- src/services/NotificationService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/NotificationService.ts b/src/services/NotificationService.ts index 3ee05b5..c562986 100644 --- a/src/services/NotificationService.ts +++ b/src/services/NotificationService.ts @@ -18,7 +18,7 @@ interface APNsUrl { } export class NotificationService { - public readonly secondsThresholdForNotificationToFire = 300; + public readonly secondsThresholdForNotificationToFire = 180; private apnsToken: string | undefined = undefined;