diff --git a/src/notifications/senders/AppleNotificationSender.ts b/src/notifications/senders/AppleNotificationSender.ts index e69de29..c4a551d 100644 --- a/src/notifications/senders/AppleNotificationSender.ts +++ b/src/notifications/senders/AppleNotificationSender.ts @@ -0,0 +1,73 @@ +import jwt from "jsonwebtoken"; + +interface APNsUrl { + fullUrl: string; + path: string; + host: string; +} + +class AppleNotificationSender { + private apnsToken: string | undefined = undefined; + private _lastRefreshedTimeMs: number | undefined = undefined; + + private lastReloadedTimeForAPNsIsTooRecent() { + const thirtyMinutesMs = 1800000; + return this._lastRefreshedTimeMs && Date.now() - this._lastRefreshedTimeMs < thirtyMinutesMs; + } + + private reloadAPNsTokenIfTimePassed() { + if (this.lastReloadedTimeForAPNsIsTooRecent()) { + return; + } + + const keyId = process.env.APNS_KEY_ID; + const teamId = process.env.APNS_TEAM_ID; + + const privateKeyBase64 = process.env.APNS_PRIVATE_KEY; + if (!privateKeyBase64) return; + const privateKey = Buffer.from(privateKeyBase64, 'base64').toString('utf-8'); + + const tokenHeader = { + alg: "ES256", + "kid": keyId, + }; + + const nowMs = Date.now(); + const claimsPayload = { + "iss": teamId, + "iat": Math.ceil(nowMs / 1000), // APNs requires number of seconds since Epoch + }; + + this.apnsToken = jwt.sign(claimsPayload, privateKey, { + algorithm: "ES256", + header: tokenHeader + }); + this._lastRefreshedTimeMs = nowMs; + } + + public sendNotificationImmediately(notification: any) { + // TODO Send the notification + } + + public static getAPNsFullUrlToUse(deviceId: string): APNsUrl { + // Construct the fetch request + const devBaseUrl = "https://api.development.push.apple.com" + const prodBaseUrl = "https://api.push.apple.com" + + let hostToUse = devBaseUrl; + if (process.env.APNS_IS_PRODUCTION === "1") { + hostToUse = prodBaseUrl; + } + + const path = "/3/device/" + deviceId; + const fullUrl = hostToUse + path; + + const constructedObject = { + fullUrl, + host: hostToUse, + path, + } + return constructedObject; + } + +}