Update Firestore security rules & indexes
This commit is contained in:
87
firestore.indexes.json
Normal file
87
firestore.indexes.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"indexes": [
|
||||
{
|
||||
"collectionGroup": "sets",
|
||||
"queryScope": "COLLECTION",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "owner",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"order": "ASCENDING"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionGroup": "sets",
|
||||
"queryScope": "COLLECTION",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "public",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "owner",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"order": "ASCENDING"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionGroup": "progress",
|
||||
"queryScope": "COLLECTION",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "uid",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "start_time",
|
||||
"order": "DESCENDING"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionGroup": "progress",
|
||||
"queryScope": "COLLECTION",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "uid",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "start_time",
|
||||
"order": "DESCENDING"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionGroup": "progress",
|
||||
"queryScope": "COLLECTION",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "setIds",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "uid",
|
||||
"order": "ASCENDING"
|
||||
},
|
||||
{
|
||||
"fieldPath": "start_time",
|
||||
"order": "ASCENDING"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fieldOverrides": []
|
||||
}
|
||||
@@ -17,9 +17,10 @@ service cloud.firestore {
|
||||
function isSetOwner(setId) {
|
||||
return get(/databases/$(database)/documents/sets/$(setId)).data.owner == request.auth.uid;
|
||||
}
|
||||
|
||||
function isPublicSet(setId) {
|
||||
return get(/databases/$(database)/documents/sets/$(setId)).data.public;
|
||||
|
||||
function isSetOwnerOrIsPublic(setId) {
|
||||
let data = get(/databases/$(database)/documents/sets/$(setId)).data;
|
||||
return data.public || data.owner == request.auth.uid;
|
||||
}
|
||||
|
||||
function verifyCreateFields(fields) {
|
||||
@@ -43,8 +44,8 @@ service cloud.firestore {
|
||||
return getRequestField(field, "") is string;
|
||||
}
|
||||
|
||||
function verifyNullType(field) {
|
||||
return getRequestField(field, null) == null;
|
||||
function verifyEmptyArrayType(field) {
|
||||
return getRequestField(field, []) == [];
|
||||
}
|
||||
|
||||
match /users/{userId} {
|
||||
@@ -54,7 +55,8 @@ service cloud.firestore {
|
||||
|
||||
function verifyThemeValue() {
|
||||
let requestField = getRequestField("theme", "default");
|
||||
return requestField == "default";
|
||||
let themes = ["default", "red", "maroon", "green", "light-blue", "pink", "yellow", "orange"];
|
||||
return requestField in themes;
|
||||
}
|
||||
|
||||
function verifyFieldTypes() {
|
||||
@@ -74,9 +76,9 @@ service cloud.firestore {
|
||||
|
||||
match /groups/{groupId} {
|
||||
function verifyGroupFieldTypes() {
|
||||
return getRequestField("role", "") == "member" ||
|
||||
getRequestField("role", "") == "contributor" ||
|
||||
getRequestField("role", "") == "owner";
|
||||
return getRequestField("role", "member") == "member" ||
|
||||
getRequestField("role", "contributor") == "contributor" ||
|
||||
getRequestField("role", "owner") == "owner";
|
||||
}
|
||||
|
||||
function getPossibleGroupFields() {
|
||||
@@ -88,7 +90,14 @@ service cloud.firestore {
|
||||
|
||||
allow read, delete: if isSignedIn() && (isSignedInUser() || getGroupRole(groupId) == "owner" || isAdmin()); // is current user's data or is owner of group or is admin
|
||||
allow create: if isSignedIn() && isSignedInUser() && (getRequestField("role", "") == "member" || (isAdmin() && verifyGroupFieldTypes())) && verifyCreateFields(getPossibleGroupFields());
|
||||
allow update: if isSignedIn() && ((getGroupRole(groupId) == "owner" || isAdmin()) && verifyGroupFieldTypes()) && verifyUpdateFields(getPossibleGroupFields());
|
||||
allow update: if isSignedIn() &&
|
||||
(getGroupRole(groupId) == "owner" || isAdmin()) &&
|
||||
verifyGroupFieldTypes() &&
|
||||
!(isSignedInUser()) && verifyUpdateFields(getPossibleGroupFields());
|
||||
allow update: if isSignedIn() &&
|
||||
isAdmin() &&
|
||||
isSignedInUser() &&
|
||||
getRequestField("role", "") == "owner";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,11 +126,16 @@ service cloud.firestore {
|
||||
|
||||
|
||||
match /sets/{setId} {
|
||||
function verifyPublicField() {
|
||||
return ((resource == null || resource.data == null || resource.data.groups == [] || resource.data.group == null) && verifyBoolType("public")) ||
|
||||
(resource.data.groups != [] && resource.data.groups is list && getRequestField("public", true) == true);
|
||||
}
|
||||
|
||||
function verifyFieldTypes() {
|
||||
return verifyBoolType("public") &&
|
||||
return verifyPublicField() &&
|
||||
verifyStringType("title") &&
|
||||
verifyStringType("owner") &&
|
||||
verifyNullType("groups");
|
||||
verifyEmptyArrayType("groups");
|
||||
}
|
||||
|
||||
function getPossibleFields() {
|
||||
@@ -142,20 +156,16 @@ service cloud.firestore {
|
||||
return [[], fields[0]];
|
||||
}
|
||||
|
||||
allow read, delete: if isSignedIn() && request.auth.uid == resource.data.owner;
|
||||
allow read: if isSignedIn() && resource.data.public;
|
||||
allow read: if isSignedIn() && (request.auth.uid == resource.data.owner || resource.data.public == true);
|
||||
allow create: if isSignedIn() && request.auth.uid == request.resource.data.owner && verifyCreateFields(getPossibleCreateFields()) && verifyFieldTypes();
|
||||
allow update: if isSignedIn() && request.auth.uid == resource.data.owner && verifyUpdateFields(getPossibleUpdateFields()) && verifyFieldTypes();
|
||||
allow delete: if isSignedIn() && request.auth.uid == resource.data.owner && (resource == null || resource.data == null || resource.data.groups == []);
|
||||
|
||||
match /vocab/{vocabId} {
|
||||
function verifySoundValue() {
|
||||
return getRequestField("sound", vocabId) == vocabId;
|
||||
}
|
||||
|
||||
function verifyVocabFieldTypes() {
|
||||
return verifyStringType("term") &&
|
||||
verifyStringType("definition") &&
|
||||
verifySoundValue();
|
||||
verifyBoolType("sound");
|
||||
}
|
||||
|
||||
function getPossibleFields() {
|
||||
@@ -176,10 +186,10 @@ service cloud.firestore {
|
||||
return [[], fields[0]];
|
||||
}
|
||||
|
||||
allow read, delete: if isSignedIn() && isSetOwner(setId);
|
||||
allow read: if isSignedIn() && isPublicSet(setId);
|
||||
allow read: if isSignedIn() && isSetOwnerOrIsPublic(setId);
|
||||
allow create: if isSignedIn() && isSetOwner(setId) && verifyCreateFields(getPossibleCreateFields()) && verifyVocabFieldTypes();
|
||||
allow update: if isSignedIn() && isSetOwner(setId) && verifyUpdateFields(getPossibleUpdateFields()) && verifyVocabFieldTypes();
|
||||
allow delete: if isSignedIn() && isSetOwner(setId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,16 +206,20 @@ service cloud.firestore {
|
||||
return get(/databases/$(database)/documents/progress/$(progressId)).data.progress < get(/databases/$(database)/documents/progress/$(progressId)).data.questions.size();
|
||||
}
|
||||
|
||||
allow read: if isSignedIn() && isProgressUser();
|
||||
allow delete: if isSignedIn() && isProgressUser() && isNotComplete();
|
||||
allow read: if isSignedIn() && resource.data.uid == request.auth.uid;
|
||||
allow delete: if isSignedIn() && resource.data.uid == request.auth.uid && isNotComplete();
|
||||
|
||||
match /terms/{vocabId} {
|
||||
allow read: if isSignedIn() && isProgressUser() && !(isLanguageSwitched());
|
||||
allow read: if isSignedIn() && isProgressUser() && (!(isLanguageSwitched()) || !(isNotComplete()));
|
||||
}
|
||||
|
||||
match /definitions/{vocabId} {
|
||||
allow read: if isSignedIn() && isProgressUser() && isLanguageSwitched();
|
||||
allow read: if isSignedIn() && isProgressUser() && (isLanguageSwitched() || !(isNotComplete()));
|
||||
}
|
||||
}
|
||||
|
||||
match /join_codes/{joinCode} {
|
||||
allow get: if isSignedIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user