b9f3a2ca0b
Replace the single `user.refreshToken` column with a proper Session
table so users can have multiple concurrent sessions (phone, laptop,
etc.), each with their own refresh token, expiry, label, and
remember-me flag.
- Add Session model (id, userId, tokenHash, label, userAgent,
ipAddress, rememberMe, lastUsedAt, expiresAt).
- Drop `User.refreshToken` and `User.refreshTokenExpiresAt`.
- authService: new createSession/validateSession/rotateSession/
revokeSession/listUserSessions helpers; remove refresh-token-on-user
functions.
- sessionCookies helper now issues a session_id cookie alongside
access_token and refresh_token; rotateSessionCookies keeps the same
session id on refresh.
- Login form adds a "Keep me signed in for 30 days" checkbox;
TTL is 7d by default, 30d with remember-me.
- User-Agent parsed into a friendly label ("Chrome on Windows") for
the upcoming sessions page.
- hooks.server.ts, refresh endpoint, logout, register, oauth callback,
and onboarding all switched to the new session API.
29 lines
1.0 KiB
TypeScript
29 lines
1.0 KiB
TypeScript
/**
|
|
* Parse a User-Agent header into a short, human-readable label like
|
|
* "Chrome on Windows" or "Safari on iOS". Intentionally heuristic — not
|
|
* a replacement for a full UA parser.
|
|
*/
|
|
export function parseUserAgentLabel(userAgent: string | null | undefined): string {
|
|
if (!userAgent) return 'Unknown device';
|
|
|
|
const ua = userAgent;
|
|
|
|
let browser = 'Browser';
|
|
if (/Edg\//.test(ua)) browser = 'Edge';
|
|
else if (/OPR\//.test(ua) || /Opera/.test(ua)) browser = 'Opera';
|
|
else if (/Firefox\//.test(ua)) browser = 'Firefox';
|
|
else if (/Chrome\//.test(ua)) browser = 'Chrome';
|
|
else if (/Safari\//.test(ua)) browser = 'Safari';
|
|
else if (/curl\//i.test(ua)) browser = 'curl';
|
|
else if (/PostmanRuntime/.test(ua)) browser = 'Postman';
|
|
|
|
let os = 'Unknown OS';
|
|
if (/Windows NT/.test(ua)) os = 'Windows';
|
|
else if (/Mac OS X|Macintosh/.test(ua)) os = 'macOS';
|
|
else if (/Android/.test(ua)) os = 'Android';
|
|
else if (/iPhone|iPad|iPod/.test(ua)) os = 'iOS';
|
|
else if (/Linux/.test(ua)) os = 'Linux';
|
|
|
|
return `${browser} on ${os}`;
|
|
}
|