-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfirestore.rules
147 lines (126 loc) · 5.57 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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
rules_version="2"
service cloud.firestore {
match /databases/{database}/documents {
match /projects/{project} {
function getEmail(req) {
return req.auth.token.email.replace('\\.' , '@@');
}
function userHasRole(req, r, roles, allowIfNull) {
return (
(req.auth != null) &&
(
(allowIfNull && r == null) ||
(r.data.roles.get(getEmail(req), null) in roles)
)
);
}
function ownRoleNotChanged(req, old, new) {
let email = getEmail(req);
return old.data.roles[email] == new.data.roles[email];
}
function ownerNotChanged(old, new) {
return (old.data.owner == new.data.owner);
}
function isValidProject(r) {
let updateTypes = ['release', 'flow', 'insights', 'raid', 'goals'];
let roles = ['owner', 'administrator', 'author', 'member'];
let requiredKeys = ['name', 'description', 'updateTypes', 'teams', 'owner', 'roles', 'tokens'].toSet();
let possibleKeys = requiredKeys.union([].toSet());
return (
r.data.keys().toSet().hasAll(requiredKeys) && // all required keys are present
possibleKeys.hasAll(r.data.keys()) && // no unknown keys
r.data.name is string && // name is a string
r.data.description is string && // description is a string
r.data.updateTypes.hasOnly(updateTypes) && // only references known update types
r.data.teams is list && // teams is a list
r.data.roles.values().hasOnly(roles) && // only references known roles
r.data.roles[r.data.owner] == 'owner' && // has an owner (field and in roles map)
r.data.tokens is list // tokens is a list
);
}
// CRUD rules
allow create: if (
userHasRole(request, request.resource, ['owner'], false) &&
isValidProject(request.resource)
);
allow read: if (
userHasRole(request, resource, ['owner', 'administrator', 'author', 'member'], true)
);
allow update: if (
userHasRole(request, resource, ['owner', 'administrator'], false) &&
isValidProject(request.resource) &&
ownRoleNotChanged(request, request.resource, resource) &&
ownerNotChanged(request.resource, resource)
);
allow delete: if (
userHasRole(request, resource, ['owner'], false)
);
// Updates
match /updates/{update} {
function canViewUpdate(request) {
return userHasRole(request, get(/databases/$(database)/documents/projects/$(project)), ['owner', 'administrator', 'author', 'member'], true);
}
function canModifyUpdate(request) {
return userHasRole(request, get(/databases/$(database)/documents/projects/$(project)), ['owner', 'administrator', 'author'], false);
}
function isValidUpdate(u) {
let updateTypes = ['insights', 'flow', 'release', 'raid', 'goals'].toSet();
let requiredKeys = ['type', 'title', 'summary', 'date', 'team'].toSet();
let possibleKeys = requiredKeys.union(['cycleTimeData', 'authorId', 'authorName', 'text', 'raidItems', 'releaseDate', 'status'].toSet());
return (
u.data.keys().toSet().hasAll(requiredKeys) && // all required keys are present
possibleKeys.hasAll(u.data.keys()) && // no unknown keys
updateTypes.hasAll([u.data.type]) && // known update type
u.data.title is string && // title is a string
u.data.summary is string && // summary is a string
u.data.date is timestamp && // date is a date
(u.data.team == null || u.data.team is string) && // team is null or string
(
(
u.data.type == 'insights' &&
u.data.authorId is string &&
u.data.authorName is string &&
u.data.text is string
) ||
(
u.data.type == 'flow' &&
u.data.cycleTimeData is list
) ||
(
u.data.type == 'release' &&
(u.data.releaseDate is timestamp || u.data.releaseDate == null) &&
u.data.status is string &&
u.data.text is string
) ||
(
u.data.type == 'raid' &&
u.data.raidItems is list
) ||
(
u.data.type == 'goals' &&
u.data.authorId is string &&
u.data.authorName is string &&
u.data.text is string
)
)
);
}
// CRUD rules
allow create: if (
canModifyUpdate(request) &&
isValidUpdate(request.resource)
);
allow read: if (
canViewUpdate(request)
);
allow update: if (
canModifyUpdate(request) &&
isValidUpdate(request.resource)
);
allow delete: if (
canModifyUpdate(request)
);
}
}
}
}