-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathfirestore.rules
More file actions
112 lines (92 loc) · 3.26 KB
/
firestore.rules
File metadata and controls
112 lines (92 loc) · 3.26 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
rules_version = '2';
// SECURITY MODEL
// --------------
// All writes go through API routes that use the Firebase Admin SDK. The
// Admin SDK bypasses these rules entirely, so the rules here only need to
// govern what the *client* SDK (lib/firebase.ts → getFirestore) can do.
//
// Currently the client SDK only READS — leaderboard widgets, profile pages,
// the network widget, etc. There are no client-side writes anywhere in the
// app. So the rule set is intentionally "read where needed, deny everything
// else." If you ever add a direct client write, write a specific rule for
// that collection instead of opening up the whole thing.
service cloud.firestore {
match /databases/{database}/documents {
function isAuthed() {
return request.auth != null;
}
// === Public reads (signed-out users can hit these) ===
// Leaderboard is shown on the homepage / Lead widget — public.
match /leaderboard/{email} {
allow read: if true;
allow write: if false;
}
// Topics + questions power /problems and /Explore — public reads.
match /topics/{tag} {
allow read: if true;
allow write: if false;
}
match /questions/{questionId} {
allow read: if true;
allow write: if false;
}
// === Authenticated reads ===
// Profiles are visible to any signed-in user (Network widget, /u/:email).
match /users/{email} {
allow read: if isAuthed();
allow write: if false;
}
// Quizzes — /Explore + /admin/quizzes.
match /quizzes/{quizId} {
allow read: if isAuthed();
allow write: if false;
}
// Follow graph reads — /Profile, /u/:email, FriendsSection.
match /follows/{pairId} {
allow read: if isAuthed();
allow write: if false;
}
// Clans + memberships + pointer.
match /clans/{clanId} {
allow read: if isAuthed();
allow write: if false;
match /members/{email} {
allow read: if isAuthed();
allow write: if false;
}
}
match /userClans/{email} {
allow read: if isAuthed();
allow write: if false;
}
// Conversations + messages — /community chat surface.
match /conversations/{convId} {
allow read: if isAuthed();
allow write: if false;
}
match /messages/{messageId} {
allow read: if isAuthed();
allow write: if false;
}
// === Owner-only reads ===
// Tasks are personal — only the owner should be able to read theirs.
// Compare against firebaseUid since tasks.userId is the Firebase UID.
match /tasks/{taskId} {
allow read: if isAuthed() && resource.data.userId == request.auth.uid;
allow write: if false;
}
// Submissions — owner-only via email match. The submissions list page
// (/submissions) reads via the REST API (Admin SDK) so this client-side
// rule only fires if someone hits Firestore directly.
match /submissions/{submissionId} {
allow read: if isAuthed() &&
request.auth.token.email != null &&
resource.data.userEmail == request.auth.token.email.lower();
allow write: if false;
}
// Default deny — anything not explicitly matched above is rejected.
match /{document=**} {
allow read, write: if false;
}
}
}