diff --git a/src/routes/account.tsx b/src/routes/account.tsx index d0fb90b..4307f86 100644 --- a/src/routes/account.tsx +++ b/src/routes/account.tsx @@ -1214,7 +1214,9 @@ function ActiveSessions(props: { userId: string }) { }; const formatDate = (dateStr: string) => { - return new Date(dateStr).toLocaleString(undefined, { + // Database stores UTC time, convert to local timezone + const date = new Date(dateStr + (dateStr.includes("Z") ? "" : "Z")); + return date.toLocaleString(undefined, { year: "numeric", month: "short", day: "numeric", @@ -1266,6 +1268,15 @@ function ActiveSessions(props: { userId: string }) {
Expires: {formatDate(session.expiresAt)} + {session.rememberMe !== undefined && ( + + ( + {session.rememberMe + ? "Remember me" + : "Session-only"} + ) + + )}
diff --git a/src/routes/login/index.tsx b/src/routes/login/index.tsx index ebc9ea4..89495cd 100644 --- a/src/routes/login/index.tsx +++ b/src/routes/login/index.tsx @@ -547,7 +547,12 @@ export default function LoginPage() {
- +
Remember Me
diff --git a/src/server/api/routers/user.ts b/src/server/api/routers/user.ts index b2706aa..b8325df 100644 --- a/src/server/api/routers/user.ts +++ b/src/server/api/routers/user.ts @@ -430,17 +430,27 @@ export const userRouter = createTRPCRouter({ // Get current session to mark it const currentSession = await getAuthSession(ctx.event as any); - return res.rows.map((row: any) => ({ - sessionId: row.id, - tokenFamily: row.token_family, - createdAt: row.created_at, - expiresAt: row.expires_at, - lastActiveAt: row.last_active_at, - rotationCount: row.rotation_count, - clientIp: row.ip_address, - userAgent: row.user_agent, - isCurrent: currentSession?.sessionId === row.id - })); + return res.rows.map((row: any) => { + // Infer rememberMe from expires_at duration + // If expires_at is > 2 days from creation, it's a remember-me session + const createdAt = new Date(row.created_at); + const expiresAt = new Date(row.expires_at); + const durationMs = expiresAt.getTime() - createdAt.getTime(); + const rememberMe = durationMs > 2 * 24 * 60 * 60 * 1000; // > 2 days + + return { + sessionId: row.id, + tokenFamily: row.token_family, + createdAt: row.created_at, + expiresAt: row.expires_at, + lastActiveAt: row.last_active_at, + rotationCount: row.rotation_count, + clientIp: row.ip_address, + userAgent: row.user_agent, + rememberMe, + isCurrent: currentSession?.sessionId === row.id + }; + }); }), revokeSession: publicProcedure