feat(notifications): security, share and release notices, email digests; harden links (phases d, e) #11

Merged
KofTwentyTwo merged 2 commits from feature/notifications-de into develop 2026-10-13 15:21:20 +00:00
KofTwentyTwo commented 2026-10-13 15:15:31 +00:00 (Migrated from github.com)

Phases (d) and (e) of docs/NOTIFICATIONS.md, after #9 and #10.

d: automatic sources

  • AlertsNotices: newSignIn, apiKeyCreated, apiKeyExpiring (one per key, refreshed), permissionChanged (SECURITY, never mutable), shared (SHARE: notebook shares, record locks, approvals) and release (RELEASE to all users). Core has no sign-in or API key events today, so hosts call these from their authentication customizer and API key screens. A core hook is follow-up work (spec Q5).
  • Marketing and other announcements: admin-authored notifications, or sink().notify with an audience.
  • Alerts home: a link-only Notifications line for authors (scheduled, sent this week, drafts). The home stays the one dashboard.

e: email

  • NotificationEmailer in the delivery job: opt-in per user and category from My Notification Settings.
    • IMMEDIATE: at or above the minimum severity.
    • DAILY_DIGEST: one email at the user's digest hour, in their time zone (My Alert Settings), listing that day's unread notifications.
  • Inert without a messaging provider and From address.
  • ALERT notifications are not emailed here, because alert subscriptions already email them.
  • SECURITY emails carry the title and link only.
  • Recipient emailStatus: SENT, DIGESTED, SKIPPED or FAILED.

Security (open-redirect fix from the review)

  • NotificationService.safeLink refuses backslashes, whitespace and control characters, and a second leading /.
  • It allows only app paths with one leading slash, or https URLs with a host.
  • It is used when a notification is saved (the table customizer), on output, and in emails.
  • Tests cover //evil.com, /\evil.com, \\evil.com, javascript:, data: and http:.

Tests: NotificationEmailAndNoticesTest (immediate, severity floor, digest hour, digest contents, notices, no security body) with a capturing messaging provider. ./mvnw verify: 67 tests, coverage gate met, checkstyle 0 violations.

🤖 Generated with Claude Code

Phases (d) and (e) of docs/NOTIFICATIONS.md, after #9 and #10. **d: automatic sources** - `AlertsNotices`: `newSignIn`, `apiKeyCreated`, `apiKeyExpiring` (one per key, refreshed), `permissionChanged` (SECURITY, never mutable), `shared` (SHARE: notebook shares, record locks, approvals) and `release` (RELEASE to all users). Core has no sign-in or API key events today, so hosts call these from their authentication customizer and API key screens. A core hook is follow-up work (spec Q5). - Marketing and other announcements: admin-authored notifications, or `sink().notify` with an audience. - Alerts home: a link-only Notifications line for authors (scheduled, sent this week, drafts). The home stays the one dashboard. **e: email** - `NotificationEmailer` in the delivery job: opt-in per user and category from My Notification Settings. - IMMEDIATE: at or above the minimum severity. - DAILY_DIGEST: one email at the user's digest hour, in their time zone (My Alert Settings), listing that day's unread notifications. - Inert without a messaging provider and From address. - ALERT notifications are not emailed here, because alert subscriptions already email them. - SECURITY emails carry the title and link only. - Recipient `emailStatus`: SENT, DIGESTED, SKIPPED or FAILED. **Security (open-redirect fix from the review)** - `NotificationService.safeLink` refuses backslashes, whitespace and control characters, and a second leading `/`. - It allows only app paths with one leading slash, or https URLs with a host. - It is used when a notification is saved (the table customizer), on output, and in emails. - Tests cover `//evil.com`, `/\evil.com`, `\\evil.com`, `javascript:`, `data:` and `http:`. **Tests:** `NotificationEmailAndNoticesTest` (immediate, severity floor, digest hour, digest contents, notices, no security body) with a capturing messaging provider. `./mvnw verify`: 67 tests, coverage gate met, checkstyle 0 violations. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.