-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirestore.rules
More file actions
129 lines (111 loc) · 5.79 KB
/
firestore.rules
File metadata and controls
129 lines (111 loc) · 5.79 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
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper function to check if user is authenticated
function isAuthenticated() {
return request.auth != null;
}
// Helper function to check if user is admin
function isAdmin() {
return isAuthenticated() &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
// Helper function to check if user is admin or agent
function isAdminOrAgent() {
return isAuthenticated() &&
(get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin' ||
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'agent');
}
// Helper function to check if user is agent (not admin)
function isAgent() {
return isAuthenticated() &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'agent';
}
// Helper function to check if user owns the document
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
// Users collection
match /users/{userId} {
// Anyone can read user documents (for public profiles)
// This allows viewing agent profiles on listing pages
allow read: if true;
// Users can only create/update their own document
allow create: if isOwner(userId);
allow update: if isOwner(userId);
// Only allow role changes by existing admins (prevent self-promotion)
allow update: if isAdmin();
// No deletion of user documents
allow delete: if false;
}
// Listings collection
match /listings/{listingId} {
// Anyone can read listings (public access for website)
// The service layer filters to only show active listings
allow read: if true;
// CRITICAL: Admins and agents can create listings, but agents MUST have status='pending' and pendingApproval=true
allow create: if isAdminOrAgent() &&
request.resource.data.createdBy == request.auth.uid &&
request.resource.data.title is string &&
request.resource.data.description is string &&
request.resource.data.price is number &&
request.resource.data.price > 0 &&
request.resource.data.location is map &&
// If agent, force status='pending' and pendingApproval=true
((isAgent() &&
request.resource.data.status == 'pending' &&
request.resource.data.pendingApproval == true) ||
// If admin, allow any valid status
(!isAgent() &&
request.resource.data.status in ['active', 'sold', 'pending', 'rented', 'pledged']));
// CRITICAL: Admin and agent can update, but with different permissions
allow update: if isAdminOrAgent() &&
(
// CASE 1: Admin can update ANY listing (for approval/rejection)
isAdmin() ||
// CASE 2: Agent can only update their own listings, with restrictions
(isAgent() && resource.data.createdBy == request.auth.uid &&
// CONDITION 1: Agent requesting deletion (pendingDelete=true)
(request.resource.data.pendingDelete == true &&
request.resource.data.pendingApproval == true) ||
// CONDITION 2: Agent updating normally (not requesting deletion)
(request.resource.data.pendingDelete != true &&
request.resource.data.pendingDelete != 'true' &&
// Status must stay pending or unchanged (cannot activate)
(request.resource.data.status == 'pending' ||
request.resource.data.status == resource.data.status) &&
// pendingApproval must be true (cannot remove it)
(request.resource.data.pendingApproval == true ||
request.resource.data.pendingApproval == 'true')))
);
// CRITICAL: Only admins can actually delete. Agents must use update to set pendingDelete=true
// This prevents agents from bypassing the approval system
// Admin can delete ANY listing (for rejection purposes)
allow delete: if isAdmin();
}
// Projects collection
match /projects/{projectId} {
// Anyone can read projects (public access for website)
allow read: if true;
// Admins and agents can create projects
allow create: if isAdminOrAgent() &&
request.resource.data.createdBy == request.auth.uid &&
request.resource.data.name is string &&
request.resource.data.description is string &&
request.resource.data.developer is string &&
request.resource.data.developedBy is string &&
request.resource.data.location is map &&
request.resource.data.status in ['upcoming', 'under-construction', 'completed', 'sold-out'];
// Admin and agent who created the project can update it
allow update: if isAdminOrAgent() &&
resource.data.createdBy == request.auth.uid;
// Admin and agent who created the project can delete it
allow delete: if isAdminOrAgent() &&
resource.data.createdBy == request.auth.uid;
}
// Deny all other database access
match /{document=**} {
allow read, write: if false;
}
}
}