teqo/src/lib/deviceLabel.ts
Francisco Ignácio Fontoura Solla 763f64080a Deliver B40: biometric login for /campanha.
WebAuthn platform passkeys: opt-in enrollment after a password login, a
password-less sign-in that mints the same 14-day campaign-token, and
revocation from the profile. The session is minted through Payload's public
pieces (checkLoginPermission, addSessionToUser, getFieldsToSign, jwtSign)
inside a transaction with an advisory lock, so a passkey login neither
bypasses a lockout nor evicts the account's other sessions. The rpID is
derived from NEXT_PUBLIC_SITE_URL and resolves to null when the request host
disagrees, so previews never offer a ceremony the browser would refuse.
2026-07-28 10:59:23 -03:00

30 lines
1.1 KiB
TypeScript

/**
* A short, human name for the device behind a user-agent string, used to
* pre-fill the passkey label so enrolling is one tap and no typing (B40).
*
* Deliberately coarse: this is a suggestion the person can overwrite, and it
* has to read like something they would say out loud ("iPhone", "Android"),
* not like a fingerprint of their browser. It is resolved on the server from
* the request header so the input has its value on first paint.
*/
const PATTERNS: ReadonlyArray<[RegExp, string]> = [
[/iPhone/i, 'iPhone'],
[/iPad/i, 'iPad'],
[/Android/i, 'Android'],
[/Macintosh|Mac OS X/i, 'Mac'],
[/Windows/i, 'Windows'],
[/CrOS/i, 'Chromebook'],
[/Linux/i, 'Linux'],
]
const FALLBACK_DEVICE_LABEL = 'Este aparelho'
export const deviceLabelFromUserAgent = (userAgent: string | null | undefined): string => {
if (!userAgent) return FALLBACK_DEVICE_LABEL
// iPadOS reports itself as a Macintosh with touch points, which the header
// alone cannot distinguish — "Mac" is the honest answer from here.
const match = PATTERNS.find(([pattern]) => pattern.test(userAgent))
return match ? match[1] : FALLBACK_DEVICE_LABEL
}