-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirestore.rules
More file actions
133 lines (122 loc) · 6.53 KB
/
firestore.rules
File metadata and controls
133 lines (122 loc) · 6.53 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
/**
* @fileoverview Firestore Security Rules for CodeTube application.
*
* Core Philosophy:
* This ruleset enforces a strict user-ownership model for private data
* (courses and chapters stored under `/users/{userId}`). Public courses
* in the top-level `/courses` collection are readable by anyone,
* but only editable by the owner.
*
* Data Structure:
* - /users/{userId}: Stores user profiles, accessible only to the user.
* - /users/{userId}/courses/{courseId}: Stores private course data, accessible only to the user.
* - /users/{userId}/courses/{courseId}/chapters/{chapterId}: Stores chapter data, accessible only to the user.
* - /courses/{courseId}: Stores public course data, readable by anyone if published.
*
* Key Security Decisions:
* - Users can only access their own data.
* - Public courses are readable by everyone but writable only by the owner.
* - Listing of users is disallowed.
* - Data validation is relaxed in this prototyping phase, focusing on authorization.
*/
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
/**
* @description Enforces that all requests are made by an authenticated user.
*/
function isSignedIn() {
return request.auth != null;
}
/**
* @description Checks if the request is made by the owner of the document.
*/
function isOwner(userId) {
return request.auth.uid == userId;
}
/**
* @description Checks if the request is made by the owner of the existing document.
* Also verifies that the resource exists to prevent accidental operations on non-existent documents.
*/
function isExistingOwner(userId) {
return isOwner(userId) && resource != null;
}
/***************** Users Collection *******************/
/**
* @description Controls access to user profiles.
* @path /users/{userId}
* @allow (create) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can create their profile with matching user ID.
* @allow (get) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can read their profile.
* @allow (update) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can update their profile.
* @allow (delete) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can delete their profile.
* @deny (create) User 'someOtherUserId' cannot create a profile with userId 'gHzseHPOIIT8gtSJktYcnP8glBy2'.
* @deny (get) User 'someOtherUserId' cannot read user 'gHzseHPOIIT8gtSJktYcnP8glBy2' profile.
* @principle Enforces document ownership for all operations.
*/
match /users/{userId} {
allow get: if isOwner(userId);
allow list: if false; // Listing users is not allowed.
allow create: if isOwner(userId) && request.resource.data.id == userId;
allow update: if isExistingOwner(userId) && request.resource.data.id == resource.data.id;
allow delete: if isExistingOwner(userId);
}
/***************** Private Courses Collection *******************/
/**
* @description Controls access to private courses stored under a user's profile.
* @path /users/{userId}/courses/{courseId}
* @allow (create) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can create a course under their profile.
* @allow (get) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can read a course under their profile.
* @allow (update) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can update a course under their profile.
* @allow (delete) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can delete a course under their profile.
* @deny (create) User 'someOtherUserId' cannot create a course under user 'gHzseHPOIIT8gtSJktYcnP8glBy2' profile.
* @deny (get) User 'someOtherUserId' cannot read a course under user 'gHzseHPOIIT8gtSJktYcnP8glBy2' profile.
* @principle Enforces document ownership for all operations on private courses.
*/
match /users/{userId}/courses/{courseId} {
allow get: if isOwner(userId);
allow list: if isOwner(userId);
allow create: if isOwner(userId) && request.resource.data.userId == userId;
allow update: if isExistingOwner(userId) && request.resource.data.userId == resource.data.userId;
allow delete: if isExistingOwner(userId);
}
/***************** Chapters Collection *******************/
/**
* @description Controls access to chapters stored under a user's course.
* @path /users/{userId}/courses/{courseId}/chapters/{chapterId}
* @allow (create) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can create a chapter in their course.
* @allow (get) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can read a chapter in their course.
* @allow (update) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can update a chapter in their course.
* @allow (delete) User 'gHzseHPOIIT8gtSJktYcnP8glBy2' can delete a chapter in their course.
* @deny (create) User 'someOtherUserId' cannot create a chapter in user 'gHzseHPOIIT8gtSJktYcnP8glBy2' course.
* @deny (get) User 'someOtherUserId' cannot read a chapter in user 'gHzseHPOIIT8gtSJktYcnP8glBy2' course.
* @principle Enforces document ownership for all operations on chapters.
*/
match /users/{userId}/courses/{courseId}/chapters/{chapterId} {
allow get: if isOwner(userId);
allow list: if isOwner(userId);
allow create: if isOwner(userId) && request.resource.data.courseId == courseId;
allow update: if isExistingOwner(userId) && request.resource.data.courseId == resource.data.courseId;
allow delete: if isExistingOwner(userId);
}
/***************** Public Courses Collection *******************/
/**
* @description Controls access to public courses.
* @path /courses/{courseId}
* @allow (get) Anyone can read a published course.
* @allow (list) Anyone can list published courses.
* @allow (create) Only the owner can create a public course and must set userId.
* @allow (update) Only the owner can update a public course, and userId cannot be changed.
* @allow (delete) Only the owner can delete a public course.
* @deny (create) User cannot create a course with a different userId than their own.
* @deny (update) User cannot update a course and change the userId.
* @principle Allows public read access to published courses but restricts writes to the owner.
*/
match /courses/{courseId} {
allow get: if true;
allow list: if true;
allow create: if isSignedIn() && request.resource.data.userId == request.auth.uid;
allow update: if isExistingOwner(resource.data.userId) && request.resource.data.userId == resource.data.userId;
allow delete: if isExistingOwner(resource.data.userId);
}
}
}