diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx index 069452d3..b686f157 100644 --- a/src/components/settings/SecurityTab.tsx +++ b/src/components/settings/SecurityTab.tsx @@ -23,20 +23,15 @@ import type { UserIdentity, OAuthProvider } from '@/types/identity'; import { toast as sonnerToast } from '@/components/ui/sonner'; import { supabase } from '@/integrations/supabase/client'; -interface DeviceInfo { - browser?: string; - userAgent?: string; - os?: string; - device?: string; -} - -interface UserSession { +interface AuthSession { id: string; - device_info: DeviceInfo | null; - last_activity: string; created_at: string; - expires_at: string; - session_token: string; + updated_at: string; + refreshed_at: string | null; + user_agent: string | null; + ip: unknown; + not_after: string | null; + aal: 'aal1' | 'aal2' | 'aal3' | null; } export function SecurityTab() { @@ -49,7 +44,7 @@ export function SecurityTab() { const [disconnectingProvider, setDisconnectingProvider] = useState(null); const [hasPassword, setHasPassword] = useState(false); const [addingPassword, setAddingPassword] = useState(false); - const [sessions, setSessions] = useState([]); + const [sessions, setSessions] = useState([]); const [loadingSessions, setLoadingSessions] = useState(true); // Load user identities on mount @@ -183,33 +178,23 @@ export function SecurityTab() { const fetchSessions = async () => { if (!user) return; - const { data, error } = await supabase - .from('user_sessions') - .select('*') - .eq('user_id', user.id) - .order('last_activity', { ascending: false }); + const { data, error } = await supabase.rpc('get_my_sessions'); if (error) { console.error('Error fetching sessions:', error); + toast({ + title: 'Error', + description: 'Failed to load sessions', + variant: 'destructive' + }); } else { - const typedSessions: UserSession[] = (data || []).map(session => ({ - id: session.id, - device_info: session.device_info as DeviceInfo | null, - last_activity: session.last_activity, - created_at: session.created_at, - expires_at: session.expires_at, - session_token: session.session_token - })); - setSessions(typedSessions); + setSessions(data || []); } setLoadingSessions(false); }; const revokeSession = async (sessionId: string) => { - const { error } = await supabase - .from('user_sessions') - .delete() - .eq('id', sessionId); + const { error } = await supabase.rpc('revoke_my_session', { session_id: sessionId }); if (error) { toast({ @@ -226,13 +211,30 @@ export function SecurityTab() { } }; - const getDeviceIcon = (deviceInfo: DeviceInfo | null) => { - const ua = deviceInfo?.userAgent?.toLowerCase() || ''; - if (ua.includes('mobile')) return ; - if (ua.includes('tablet')) return ; + const getDeviceIcon = (userAgent: string | null) => { + if (!userAgent) return ; + + const ua = userAgent.toLowerCase(); + if (ua.includes('mobile') || ua.includes('android') || ua.includes('iphone')) { + return ; + } + if (ua.includes('tablet') || ua.includes('ipad')) { + return ; + } return ; }; + const getBrowserName = (userAgent: string | null) => { + if (!userAgent) return 'Unknown Browser'; + + const ua = userAgent.toLowerCase(); + if (ua.includes('firefox')) return 'Firefox'; + if (ua.includes('chrome') && !ua.includes('edg')) return 'Chrome'; + if (ua.includes('safari') && !ua.includes('chrome')) return 'Safari'; + if (ua.includes('edg')) return 'Edge'; + return 'Unknown Browser'; + }; + // Get connected accounts with identity data const connectedAccounts = [ { @@ -415,17 +417,21 @@ export function SecurityTab() { {sessions.map((session) => (
- {getDeviceIcon(session.device_info)} + {getDeviceIcon(session.user_agent)}

- {session.device_info?.browser || 'Unknown Browser'} + {getBrowserName(session.user_agent)}

- Last active: {format(new Date(session.last_activity), 'PPpp')} -

-

- Expires: {format(new Date(session.expires_at), 'PPpp')} + {session.ip && `${session.ip} • `} + Last active: {format(new Date(session.refreshed_at || session.created_at), 'PPpp')} + {session.aal === 'aal2' && ' • MFA'}

+ {session.not_after && ( +

+ Expires: {format(new Date(session.not_after), 'PPpp')} +

+ )}