-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
firestore.rules
80 lines (80 loc) · 4.11 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
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isCreator() {
return auth() && resource != null && (resource.data.uid == request.auth.uid || request.auth.token.admin == true);
}
function isNotImpersonating() {
return request.resource != null && (request.auth.token.admin == true || (request.resource.data.uid == request.auth.uid));
}
function onlyUpdated(keys) {
return request.resource.data.diff(resource.data).affectedKeys().hasOnly(keys);
}
function auth() {
return request.auth != null && request.auth.token.email_verified;
}
function limitResourceKeys(required, optional) {
let keys = request.resource.data.keys();
return keys.hasAll(required) && keys.hasOnly(required.concat(optional));
}
function nameWordsMatchesName() {
let normalizedNameWords = request.resource.data.name.replace("[\\x{0300}-\\x{036F}]", "").replace("\\W", " ").lower().trim().split("\\s+").removeAll([" "]);
return request.resource.data.nameWords.hasOnly(normalizedNameWords);
}
function canView() {
return
resource.data.visibility == 1 ||
resource.data.visibility == 2 ||
(resource.data.visibility is list && auth() && resource.data.visibility.hasAny([request.auth.token.email])) ||
isCreator();
}
function validateFormResponse(additionalKeys) {
let requiredFields = ["name", "email", "text", "uid", "response"];
return limitResourceKeys(requiredFields.concat(additionalKeys), []) && request.resource.data.response == null;
}
function validateSet() {
return
isNotImpersonating() &&
request.resource.data.terms.size() >= 1 &&
nameWordsMatchesName() &&
request.resource.data.numTerms == request.resource.data.terms.size() &&
request.resource.data.updatedTime == request.time;
}
function onlyAddedRemoved(list1, list2) {
let set1 = list1.toSet();
let set2 = list2.toSet();
return set1.difference(set2).hasOnly([request.auth.uid]) || set2.difference(set1).hasOnly([request.auth.uid]);
}
match /sets/{set_id} {
allow get: if resource == null || canView();
allow list: if (resource.data.visibility == 2 || isCreator()) && request.query.limit <= 10 && (!("likes" in resource.data) || resource.data.likes.hasAny([request.auth.uid]));
allow delete: if isCreator();
allow update: if isCreator() && onlyUpdated(["name", "terms", "description", "visibility", "nameWords", "numTerms", "collections", "updatedTime"]) && validateSet();
allow update: if auth() && canView() && onlyUpdated(["likes", "comments"]) &&
onlyAddedRemoved(request.resource.data.likes, resource.data.likes) && onlyAddedRemoved(request.resource.data.comments.keys(), resource.data.comments.keys())
&& request.resource.data.comments.get(request.auth.uid, "") is string;
allow create: if auth() &&
limitResourceKeys(["name", "uid", "terms", "visibility", "nameWords", "numTerms", "collections", "likes", "creationTime", "comments", "updatedTime"], ["description"]) &&
request.resource.data.likes == [] && request.resource.data.comments == {} && validateSet() && request.resource.data.creationTime == request.time;
}
match /collections/{collection_id} {
allow get: if true;
allow list: if isCreator();
allow delete: if isCreator();
allow create: if auth() && limitResourceKeys(["name", "uid", "sets"], []) && isNotImpersonating();
allow update: if isCreator() && onlyUpdated(["name", "sets"]);
}
match /form_data/types/{form_type}/{submission_id} {
allow get: if resource == null || isCreator();
allow list, delete: if isCreator();
allow create: if request.auth != null && (
form_type in ["feedback", "bug", "takedown", "other"]) &&
(
(form_type == 'feedback' && validateFormResponse(['rating'])) ||
(form_type == 'bug' && validateFormResponse(['url'])) ||
(form_type == 'takedown' && validateFormResponse(['url'])) ||
(form_type == 'other' && validateFormResponse([]))
);
}
}
}