-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirestore.rules
More file actions
154 lines (130 loc) · 5.23 KB
/
firestore.rules
File metadata and controls
154 lines (130 loc) · 5.23 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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// --- Helper Functions ---
function isAuthenticated() {
return request.auth != null;
}
function getUserRole() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role;
}
function isApproved() {
let role = getUserRole();
return role != 'PENDING' && role != null;
}
function isManager() {
let role = getUserRole();
return role == 'MANAGER' || role == 'ADMINISTRATOR';
}
// --- Collection Rules ---
// 1. Users Collection
match /users/{userId} {
// Read: Managers/Employees/Self can see. Pending only see Self.
allow read: if isAuthenticated() && (
userId == request.auth.uid ||
isApproved()
);
// Create: Self-creation (Signup) or Manager
allow create: if isAuthenticated() && (request.auth.uid == userId || isManager());
// Update:
// Managers can update everything.
// Users can update their own profile EXCEPT their role (Privilege Escalation Prevention).
allow update: if isAuthenticated() && (
isManager() ||
(request.auth.uid == userId && request.resource.data.role == resource.data.role)
);
// Delete: Managers only
allow delete: if isAuthenticated() && isManager();
}
// Customers Collection (formerly Categories)
match /customers/{customerId} {
allow read: if isAuthenticated() && isApproved();
// Only Managers can manage customers
allow write: if isAuthenticated() && isManager();
}
// Products Collection (New)
match /products/{productId} {
// Everyone can read products (needed for Drivers in Route view)
allow read: if isAuthenticated() && isApproved();
// Only Managers can manage products
allow delete: if isAuthenticated() && isManager();
allow create, update: if isAuthenticated() && isManager()
&& request.resource.data.name is string
&& request.resource.data.category is string
&& request.resource.data.price is number && request.resource.data.price >= 0
&& request.resource.data.quantity is number;
}
// Vehicles Collection (Fleet Management)
match /vehicles/{vehicleId} {
// Everyone can read vehicles (needed for viewing fleet/assignments)
allow read: if isAuthenticated() && isApproved();
// Only Managers can manage vehicles
allow write: if isAuthenticated() && isManager();
// Maintenance Subcollection
match /maintenance/{recordId} {
allow read: if isAuthenticated() && isApproved();
allow write: if isAuthenticated() && isManager();
}
}
// 3. Todos (Tasks)
match /routes/{routeId} {
allow read: if isAuthenticated() && isApproved();
// Create: Managers only (Drivers should not be able to create routes manually)
allow create: if isAuthenticated() && isManager();
// Update:
// Managers can update everything.
// Assignees can update status/details BUT cannot reassign or change due date.
allow update: if isAuthenticated() && isApproved() && (
isManager() ||
(
resource.data.assignedTo == request.auth.uid &&
request.resource.data.assignedTo == resource.data.assignedTo &&
request.resource.data.dueDate == resource.data.dueDate
)
);
// Delete: Managers only
allow delete: if isAuthenticated() && isManager();
}
// 4. App Status (Audit Logs)
match /app_status/{docId} {
// Allow create for unauthenticated users (for login failure logs) but enforce schema
allow create: if true
&& request.resource.data.keys().hasAll(['type', 'timestamp', 'status'])
&& request.resource.data.type == 'LOGIN'
&& (request.resource.data.status == 'SUCCESS' || request.resource.data.status == 'FAILURE')
&& request.resource.data.size() < 20 // Prevent massive objects
&& request.resource.data.timestamp is timestamp
&& request.resource.data.timestamp > request.time - duration.value(60, 's'); // Simple "not too old" check to prevent backdating spam
allow read, update, delete: if isAuthenticated() && isManager();
}
// 5. App Issues
match /app_issues/{issueId} {
allow read: if isAuthenticated() && (
isManager() ||
resource.data.userId == request.auth.uid
);
allow create: if isAuthenticated();
allow update, delete: if isAuthenticated() && (
isManager() ||
resource.data.userId == request.auth.uid
);
}
// 6. System Config
// General read for all config docs (needed for Backup listing)
match /config/{docId} {
allow read: if isAuthenticated() && isApproved();
}
match /config/counters {
// Allow write for Task Creation (Managers only)
allow write: if isAuthenticated() && isManager();
}
match /config/settings {
// Allow write for System Settings (Managers only)
allow write: if isAuthenticated() && isManager();
}
match /config/seeding {
// Allow write for Seeding Options (Managers only)
allow write: if isAuthenticated() && isManager();
}
}
}