Repository navigation
Expand file tree
/
Copy pathfirestore.rules
More file actions
86 lines (76 loc) · 2.97 KB
/
Copy pathfirestore.rules
File metadata and controls
86 lines (76 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// ===============================================================
// Assumed Data Model
// ===============================================================
//
// Collection: users/{userId}
// Fields:
// - uid: string (required, immutable)
// - email: string (required)
// - displayName: string
// - role: string (enum: 'admin', 'analyst')
// - createdAt: timestamp
//
// Collection: reports/{reportId}
// Fields:
// - analystId: string (required, immutable)
// - analystName: string
// - imageUrl: string (required)
// - location: map { lat: number, lng: number } (required)
// - contaminationLevel: string (enum: 'safe', 'moderate', 'unsafe')
// - aiResult: map { confidence: number, detections: list, ... }
// - status: string (enum: 'pending', 'verified', 'rejected')
// - createdAt: timestamp
//
// ===============================================================
// Helper Functions
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
function getUserData() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
}
function isAdmin() {
return isAuthenticated() && (
getUserData().role == 'admin' ||
(request.auth.token.email == "shjanabdul2@gmail.com" && request.auth.token.email_verified == true)
);
}
function isAnalyst() {
return isAuthenticated() && getUserData().role == 'analyst';
}
// Validation Functions
function isValidUser(data) {
return data.keys().hasAll(['uid', 'email', 'role']) &&
data.uid is string &&
data.email is string &&
data.role in ['admin', 'analyst'];
}
function isValidReport(data) {
return data.keys().hasAll(['analystId', 'imageUrl', 'location', 'contaminationLevel', 'status', 'createdAt']) &&
data.analystId == request.auth.uid &&
data.location.lat is number &&
data.location.lng is number &&
data.contaminationLevel in ['safe', 'moderate', 'unsafe'] &&
data.status in ['pending', 'verified', 'rejected'];
}
// User Rules
match /users/{userId} {
allow read: if isAuthenticated();
allow create: if isOwner(userId) && isValidUser(request.resource.data) && (request.resource.data.role == 'analyst' || isAdmin());
allow update: if (isOwner(userId) && request.resource.data.role == resource.data.role) || isAdmin();
}
// Report Rules
match /reports/{reportId} {
allow read: if isAuthenticated();
allow create: if isAuthenticated() && isValidReport(request.resource.data);
allow update: if isAdmin(); // Only admins can verify reports
allow delete: if isAdmin();
}
}
}