feat(security & admin): update firestore and storage rules with admin token check and enable admin deletion in app
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -111,7 +110,8 @@ class _PostListScreenState extends State<PostListScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currentUser = FirebaseAuth.instance.currentUser;
|
||||
final auth = Provider.of<AuthService>(context);
|
||||
final currentUser = auth.user;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@@ -240,6 +240,7 @@ class _PostListScreenState extends State<PostListScreen> {
|
||||
final isSelected = _selectedItems.containsKey(item.id);
|
||||
final isAuthor =
|
||||
currentUser != null && item.authorUid == currentUser.uid;
|
||||
final canDelete = isAuthor || auth.isAdmin;
|
||||
final formattedDate =
|
||||
DateFormat('dd.MM.yyyy').format(item.createdDate);
|
||||
|
||||
@@ -367,7 +368,7 @@ class _PostListScreenState extends State<PostListScreen> {
|
||||
),
|
||||
);
|
||||
|
||||
if (isAuthor) {
|
||||
if (canDelete) {
|
||||
return Dismissible(
|
||||
key: Key(item.id),
|
||||
direction: DismissDirection.endToStart,
|
||||
|
||||
@@ -20,6 +20,8 @@ class AuthService extends ChangeNotifier {
|
||||
|
||||
String? _cachedFirstName;
|
||||
String? _cachedLastName;
|
||||
bool _isAdmin = false;
|
||||
bool get isAdmin => _isAdmin;
|
||||
|
||||
String get firstName {
|
||||
if (_cachedFirstName != null && _cachedFirstName!.isNotEmpty) {
|
||||
@@ -45,14 +47,28 @@ class AuthService extends ChangeNotifier {
|
||||
_initAuth();
|
||||
}
|
||||
|
||||
Future<void> _checkAdminClaim(User? user) async {
|
||||
if (user != null && !user.isAnonymous) {
|
||||
try {
|
||||
final tokenResult = await user.getIdTokenResult();
|
||||
_isAdmin = tokenResult.claims?['admin'] == true;
|
||||
} catch (_) {
|
||||
_isAdmin = false;
|
||||
}
|
||||
} else {
|
||||
_isAdmin = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initAuth() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_isCommunityUnlocked = prefs.getBool(_prefKeyUnlocked) ?? false;
|
||||
_cachedFirstName = prefs.getString('user_first_name');
|
||||
_cachedLastName = prefs.getString('user_last_name');
|
||||
|
||||
_auth.authStateChanges().listen((User? user) {
|
||||
_auth.authStateChanges().listen((User? user) async {
|
||||
_user = user;
|
||||
await _checkAdminClaim(user);
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
@@ -152,10 +168,11 @@ class AuthService extends ChangeNotifier {
|
||||
/// Check if user's email is verified
|
||||
bool get isEmailVerified => _user?.emailVerified ?? false;
|
||||
|
||||
/// Reload current user from Firebase to refresh emailVerified status
|
||||
/// Reload current user from Firebase to refresh emailVerified status and admin claim
|
||||
Future<void> reloadUser() async {
|
||||
await _user?.reload();
|
||||
_user = _auth.currentUser;
|
||||
await _checkAdminClaim(_user);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -209,6 +226,7 @@ class AuthService extends ChangeNotifier {
|
||||
await prefs.remove('user_last_name');
|
||||
_cachedFirstName = null;
|
||||
_cachedLastName = null;
|
||||
_isAdmin = false;
|
||||
await _auth.signOut();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
|
||||
Reference in New Issue
Block a user