diff --git a/server/src/nest/notifications/push/push-subscription.helpers.ts b/server/src/nest/notifications/push/push-subscription.helpers.ts index 08ab050fc..4979ad3f7 100644 --- a/server/src/nest/notifications/push/push-subscription.helpers.ts +++ b/server/src/nest/notifications/push/push-subscription.helpers.ts @@ -20,6 +20,11 @@ export const PUSH_SERVICE_HOSTS: readonly string[] = [ 'push.services.mozilla.com', // Safari on macOS, and Home Screen apps on iOS and iPadOS 16.4+. 'web.push.apple.com', + // The TREK apps' push relay. The app subscribes with its own key pair, the + // server encrypts exactly as for a browser, and the relay hands the ciphertext + // to Apple or Google, so it never reads a notification. Only liketrek holds + // the apps' APNs and FCM keys, which is why every server goes through it. + 'push.liketrek.com', ]; /** Services that hand out per-region or per-cluster hosts under one domain. */ diff --git a/server/tests/unit/nest/notifications/push-subscriptions.service.test.ts b/server/tests/unit/nest/notifications/push-subscriptions.service.test.ts index 5226d3fad..f3506c190 100644 --- a/server/tests/unit/nest/notifications/push-subscriptions.service.test.ts +++ b/server/tests/unit/nest/notifications/push-subscriptions.service.test.ts @@ -80,6 +80,8 @@ describe('checkPushEndpoint / checkPushSubscription', () => { 'https://web.push.apple.com/QGx9', 'https://api.push.apple.com/3/device/x', 'https://wns2-par02p.notify.windows.com/w/?token=BQYAAA', + // The TREK apps' relay, which hands the ciphertext on to Apple or Google. + 'https://push.liketrek.com/v1/apns/production/abc123', ]) { expect(checkPushEndpoint(endpoint), endpoint).toBe('ok'); expect(isPushServiceEndpoint(endpoint)).toBe(true); @@ -117,6 +119,8 @@ describe('checkPushEndpoint / checkPushSubscription', () => { 'https://evilnotify.windows.com/x', 'https://.notify.windows.com/x', 'https://push.apple.com/x', + 'https://push.liketrek.com.evil.test/v1/apns/x', + 'https://evilpush.liketrek.com/v1/apns/x', ]) { expect(checkPushEndpoint(endpoint), endpoint).not.toBe('ok'); }