From 30158cddc302e251ce2c0b628019aa6d992c0aa4 Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 6 Nov 2026 13:33:57 +0100 Subject: [PATCH] feat(push): accept the TREK apps' push relay as a push service The apps subscribe to Web Push like a browser, with their own key pair, but with an endpoint on liketrek's relay: only liketrek holds the apps' APNs and FCM keys. The server encrypts exactly as for a browser (RFC 8291), so the relay hands on ciphertext it cannot read and the device decrypts it. Lookalike hosts stay refused. --- .../src/nest/notifications/push/push-subscription.helpers.ts | 5 +++++ .../nest/notifications/push-subscriptions.service.test.ts | 4 ++++ 2 files changed, 9 insertions(+) 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'); }