mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
650451bdf7
A fourth built-in channel next to email, webhook and ntfy. Browsers register per device, the server encrypts per RFC 8291 and signs per RFC 8292 with node:crypto and sends only to known push services through the SSRF guard. The event matrix decides per category what arrives by push; admins switch the channel on under Notifications. VAPID keys come from the environment or are generated once, only while neither stored row exists, and kept encrypted. A pair that does not decrypt or match is never overwritten and never swapped for another one: push stays off with an error in the log and every device stays registered until the key is fixed. The subject is VAPID_SUBJECT, then an https APP_URL, then the project URL. Only chat messages collapse into one notification per trip, and a replacement still alerts. A 403 removes a device only after three failures in a row; 404 and 410 remove it at once. Password change, reset and an admin setting a password drop the user's devices with the other credentials. The request log redacts subscriptions and endpoints, boot errors print *** for every secret variable, and logout forgets the device with a plain fetch so an expired session cannot redirect midway. Addresses discussion #894.
29 lines
1.1 KiB
TypeScript
29 lines
1.1 KiB
TypeScript
/**
|
|
* iPhone and iPad facts that more than one feature has to know about: file
|
|
* opening needs to know whether a new tab would leave the installed app, and
|
|
* Web Push needs to know whether it can work here at all.
|
|
*/
|
|
|
|
type NavigatorWithStandalone = Navigator & { standalone?: boolean }
|
|
|
|
/**
|
|
* True only on iOS and iPadOS while TREK runs as an app added to the Home
|
|
* Screen. `navigator.standalone` is Apple's own flag and exists nowhere else,
|
|
* so every other platform answers false.
|
|
*/
|
|
export function isIosStandalone(): boolean {
|
|
return typeof navigator !== 'undefined' && (navigator as NavigatorWithStandalone).standalone === true
|
|
}
|
|
|
|
/**
|
|
* True on iPhone, iPod touch and iPad. iPadOS 13 and later asks for the desktop
|
|
* site by default and then introduces itself as a Mac, so a Mac with a touch
|
|
* screen counts too: no real Mac has one.
|
|
*/
|
|
export function isIosDevice(): boolean {
|
|
if (typeof navigator === 'undefined') return false
|
|
const ua = navigator.userAgent || ''
|
|
if (/iPad|iPhone|iPod/.test(ua)) return true
|
|
return /Macintosh/.test(ua) && (navigator.maxTouchPoints ?? 0) > 1
|
|
}
|