diff --git a/lib/utils/lock_enforcer.dart b/lib/utils/lock_enforcer.dart index add129ee..8b543970 100644 --- a/lib/utils/lock_enforcer.dart +++ b/lib/utils/lock_enforcer.dart @@ -3,21 +3,38 @@ import 'package:supabase_flutter/supabase_flutter.dart'; /// Call after sign-in and on app start to enforce app-level profile lock. /// If the user's `profiles.is_locked` flag is true, this signs out the user. Future enforceLockForCurrentUser(SupabaseClient supabase) async { - final user = supabase.auth.currentUser; - if (user == null) return; + final current = supabase.auth.currentUser; + if (current == null) return; try { - final record = await supabase - .from('profiles') - .select('is_locked') - .eq('id', user.id) - .maybeSingle(); + // Fetch the authoritative user record from the auth API and inspect + // `banned_until`. This is the canonical source after an admin `set_lock`. + final resp = await supabase.auth.getUser(); + final user = resp.user; + if (user == null) return; - if (record == null) return; - if (record['is_locked'] == true) { + dynamic bannedRaw; + try { + // Support multiple SDK shapes: `bannedUntil`, `banned_until`, or rawData + bannedRaw = + (user as dynamic).bannedUntil ?? + (user as dynamic).rawData?['banned_until'] ?? + (user as dynamic).banned_until; + } catch (_) { + bannedRaw = null; + } + + DateTime? bannedUntil; + if (bannedRaw is String) { + bannedUntil = DateTime.tryParse(bannedRaw); + } else if (bannedRaw is DateTime) { + bannedUntil = bannedRaw; + } + + if (bannedUntil != null && bannedUntil.isAfter(DateTime.now())) { await supabase.auth.signOut(); } } catch (_) { - // swallow; enforcement is a best-effort client-side check + // swallow; enforcement is best-effort on the client } }