-
Notifications
You must be signed in to change notification settings - Fork 0
/
firestore.rules
104 lines (90 loc) · 4.18 KB
/
firestore.rules
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
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//////////////////////////////////////////////////////////////
// USERS COLLECTION
//////////////////////////////////////////////////////////////
match /users/{userId} {
allow read: if isSignedIn() && userOwnsDocument(userId);
allow create: if isSignedIn();
allow update: if false; // there are currently no UPDATE to users documents from clientSide
allow delete: if false; // there are currently no DELETE to users documents from clientSide
}
//////////////////////////////////////////////////////////////
// RECIPES COLLECTION
//////////////////////////////////////////////////////////////
match /recipes/{recipeId} {
allow read: if true; // everyone can read
allow create: if isSignedIn();
allow update: if isSignedIn() && userOwnsDocument(getIncomingData().authorId);
allow delete: if isSignedIn() && userOwnsDocument(getExistingData().authorId);
//////////////////////////////////////////////////////////////
// REVIEWS SUB-COLLECTION
//////////////////////////////////////////////////////////////
match /reviews/{reviewId} {
allow read: if true; // everyone can read
allow create: if isSignedIn();
allow update: if isSignedIn() && userOwnsDocument(getIncomingData().authorId);
allow delete: if isSignedIn() && userOwnsDocument(getExistingData().authorId);
}
//////////////////////////////////////////////////////////////
// INGREDIENTS SUB-COLLECTION
//////////////////////////////////////////////////////////////
match /ingredients/{ingredientId} {
allow read: if true; // everyone can read
allow create: if isSignedIn() && userOwnsRecipe() && wasDocumentCreatedThroughBatchWrite(ingredientId);
allow update: if false; // no current way of updating ingredients from clientSide
allow delete: if isSignedIn() && userOwnsRecipe();
}
function getRecipeAuthorId() {
return get(/databases/$(database)/documents/recipes/$(recipeId)).data.authorId;
}
function userOwnsRecipe() {
return request.auth.uid == getRecipeAuthorId();
}
function wasDocumentCreatedThroughBatchWrite(ingredientId) {
return getAfter(/databases/$(database)/documents/recipes/$(recipeId)/ingredients/$(ingredientId)).data.createdAt == request.time;
}
}
//////////////////////////////////////////////////////////////
// DEFAULT CASE
//////////////////////////////////////////////////////////////
match /{document=**} {
allow read, write: if false; // every non-considered case is blocked
}
//////////////////////////////////////////////////////////////
// FUNCTIONS
//////////////////////////////////////////////////////////////
function isSignedIn() {
return request.auth != null;
}
// provide the potential authorId
function userOwnsDocument(authorId) {
return request.auth.uid == authorId
}
// User intents to write this data in to the database
// This Data content fields are accesable (data.creationDate)
function getIncomingData() {
return request.resource.data
}
// This Data is already saved in the database
function getExistingData() {
return resource.data
}
// function isExistingDataLocked() {
// return getExistingData().locked
// }
// function getUserData() {
// return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
// }
// function hasVerifiedEmail() {
// return request.auth.token.email_verified;
// }
}
}
// const arr = [] // example
// arr.keys() -> access keys of dictionary as an array
// arr.hasAny(['admin', 'editor']) -> has any of this values?
// arr.hasAll(['admin', 'editor']) -> has all this values?
// request.time() -> time when this request was made
// getExistingData().createdAt -> time when existing data was added to database