diff --git a/.env.example b/.env.example index 92650db..2e0ac7f 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,9 @@ +# Set to "1" for true +APNS_IS_PRODUCTION= + APNS_KEY_ID= APNS_TEAM_ID= APNS_BUNDLE_ID= -APNS_KEY_PATH= + +# base64-encoded APNs private key +APNS_PRIVATE_KEY= diff --git a/src/services/NotificationService.ts b/src/services/NotificationService.ts index 6fee796..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; @@ -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", @@ -154,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 9ef66c6..7f3cfcf 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(() => { @@ -198,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); @@ -209,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);