Skip to content

feat(notifications): encrypt rich alerts from paired servers - #42

Merged
NicholasZolton merged 1 commit into
mainfrom
NicholasZolton/encrypted-paired-notifications
Oct 10, 2026
Merged

NicholasZolton merged 1 commit into
mainfrom
NicholasZolton/encrypted-paired-notifications

Conversation

@NicholasZolton

Copy link
Copy Markdown
Owner

Summary

Paired Android notifications currently hide useful thread titles and status behind generic alerts. Rich notifications should work without T3 Connect, but their content must not reach Google in plaintext.

This reuses Connect's notification policy and Android presentation for direct paired delivery. Servers encrypt each payload for the phone's registration key; Android decrypts natively, including after process exit, and merges activity from independently paired environments. Existing session authorization, opt-out, retry deduplication, ordering, and foreground-thread suppression remain in place.

Test plan

  • Focused TypeScript notification, encryption, registration, shared-policy, and relay compatibility tests.
  • Scoped server, mobile, and relay typechecks; TypeScript lint and formatting.
  • Android notification tests across API 24, 26, 33, and 36; module compilation and Android lint.
  • Changed Kotlin files pass ktlint and detekt; git diff --check.
  • Physical-phone encrypted delivery and cold-start notification taps after rollout.

Rollout note

Update both sending servers and the Android binary. Enabled registrations refresh automatically when the app opens; updated servers refuse keyless registrations and never fall back to rich plaintext. Preserve the Android package, private signing identity, app data, and existing Firebase configuration.

UI evidence

Before/after screenshots omitted with Nicholas's approval because agent device access is disabled. Physical-phone delivery previously verified only the generic implementation, not this encrypted upgrade.

brave-tulip-laurel

Copilot AI balanced review requested due to automatic review settings October 10, 2026 19:21
@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Oct 10, 2026
@NicholasZolton
NicholasZolton merged commit 357f5b3 into main Oct 10, 2026
8 of 23 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Shared FCM collapsing, overlapping-source aggregation, and duplicated preference controls can lose or misrepresent notifications.

3 open findings
What changed in this PR

Adds end-to-end encrypted rich Android notifications for directly paired servers while sharing T3 Connect’s alert policy and native presentation.

Changes:

  • Encrypts server payloads using P-256 ECDH, HKDF, and AES-GCM.
  • Adds native decryption, persistent keys, multi-environment activity aggregation, and settings.
  • Shares notification policy code and expands migration, interoperability, and Android tests.
File Description
wiki/​paired-notifications.md Updates the compatibility decision.
wiki/​log.md Records the policy change.
packages/​shared/​src/​agentActivityPolicy.test.ts Tests shared alert policy.
packages/​shared/​src/​agentActivityPayloads.ts Generalizes notification payload helpers.
packages/​shared/​src/​agentActivityAndroid.ts Shares Android payload generation.
packages/​shared/​src/​agentActivityAlerts.ts Adds explicit transition return types.
packages/​shared/​src/​agentActivityAggregate.ts Adjusts shared aggregate typing and sorting.
packages/​shared/​package.json Exports shared activity modules.
packages/​contracts/​src/​environmentHttp.ts Adds encryption keys, preferences, and capability status.
infra/​relay/​src/​agentActivity/​FcmDeliveries.ts Uses shared Android notification policy.
infra/​relay/​src/​agentActivity/​FcmDeliveries.test.ts Updates shared-policy tests.
infra/​relay/​src/​agentActivity/​ApnsDeliveryQueue.ts Uses generalized payload sanitization.
infra/​relay/​src/​agentActivity/​ApnsDeliveries.ts Uses shared alert and payload helpers.
infra/​relay/​src/​agentActivity/​AgentActivityPublisher.ts Uses shared aggregation helpers.
infra/​relay/​scripts/​android-push-watch.ts Uses shared Android payload utilities.
docs/​user/​mobile-notifications.md Documents encrypted rich notifications.
docs/​operations/​android-notifications.md Documents encryption and rollout operations.
apps/​server/​src/​notifications/​runtime.ts Wires notification encryption.
apps/​server/​src/​notifications/​PairedNotifications.ts Produces encrypted rich activity deliveries.
apps/​server/​src/​notifications/​PairedNotifications.test.ts Tests encrypted server delivery behavior.
apps/​server/​src/​notifications/​notificationTestUtils.ts Adds independent encryption test utilities.
apps/​server/​src/​notifications/​NotificationStore.ts Migrates persisted notification state.
apps/​server/​src/​notifications/​NotificationEncryption.ts Implements payload encryption.
apps/​server/​src/​notifications/​NotificationEncryption.test.ts Tests confidentiality and interoperability.
apps/​mobile/​src/​features/​settings/​PairedNotificationSettings.tsx Adds paired activity settings.
apps/​mobile/​src/​features/​agent-awareness/​registrationPayload.ts Shares awareness preference construction.
apps/​mobile/​src/​features/​agent-awareness/​pairedNotifications.ts Registers keys and encrypted capability.
apps/​mobile/​src/​features/​agent-awareness/​pairedNotifications.test.ts Tests encrypted mobile registration.
apps/​mobile/​src/​features/​agent-awareness/​androidNotifications.ts Extends the native module bridge.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​test/​resources/​paired-notification-v1.json Adds an encryption fixture.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​test/​java/​expo/​modules/​t3agentnotifications/​PairedNotificationCryptoTest.kt Tests native decryption.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​test/​java/​expo/​modules/​t3agentnotifications/​PairedAgentNotificationsTest.kt Tests paired presentation and aggregation.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​test/​java/​expo/​modules/​t3agentnotifications/​AgentNotificationsTest.kt Refactors shared notification tests.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​test/​java/​expo/​modules/​t3agentnotifications/​AgentNotificationFixture.kt Extracts Android test setup.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​main/​java/​expo/​modules/​t3agentnotifications/​T3AgentNotificationsModule.kt Exposes key and configuration APIs.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​main/​java/​expo/​modules/​t3agentnotifications/​PairedNotificationKeys.kt Manages wrapped registration keys.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​main/​java/​expo/​modules/​t3agentnotifications/​PairedNotificationCrypto.kt Decrypts authenticated envelopes.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​main/​java/​expo/​modules/​t3agentnotifications/​AgentNotifications.kt Integrates paired native presentation.
apps/​mobile/​modules/​t3-agent-notifications/​android/​src/​main/​java/​expo/​modules/​t3agentnotifications/​AgentActivitySnapshots.kt Merges activity sources locally.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +58 to +62
ordered
.flatMap(::activityRows)
.sortedBy { priority(ActivityPhase.forStatus(it.status)) }
.take(5)
val activeCount = sources.sumOf {
Comment on lines +147 to +148
onValueChange={(enabled) => {
void save({ liveActivitiesEnabled: enabled }).catch(() => {
: entry,
),
};
alert: alert !== null,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants