Update Firestore rules for new database structure

This commit is contained in:
2021-07-25 22:47:37 +01:00
parent 2cfefcb9e2
commit b816a53c67

View File

@@ -7,7 +7,7 @@ service cloud.firestore {
} }
function isAdmin() { function isAdmin() {
return request.auth.token.admin; return request.auth.token.admin == true;
} }
function getGroupRole(groupId) { function getGroupRole(groupId) {
@@ -43,19 +43,22 @@ service cloud.firestore {
return getRequestField(field, "") is string; return getRequestField(field, "") is string;
} }
function verifyNullType(field) {
return getRequestField(field, null) == null;
}
match /users/{userId} { match /users/{userId} {
function isSignedInUser() { function isSignedInUser() {
return request.auth.uid == userId; return request.auth.uid == userId;
} }
function verifyFieldTypes() { function verifyFieldTypes() {
return verifyStringType("display_name") && return verifyBoolType("sound") &&
verifyBoolType("sound") &&
verifyStringType("theme"); verifyStringType("theme");
} }
function getPossibleFields() { function getPossibleFields() {
let requiredFields = ["display_name", "sound", "theme"]; let requiredFields = ["sound", "theme"];
let optionalFields = []; let optionalFields = [];
let allFields = requiredFields.concat(optionalFields); let allFields = requiredFields.concat(optionalFields);
return [requiredFields, allFields]; return [requiredFields, allFields];
@@ -63,7 +66,6 @@ service cloud.firestore {
allow read: if isSignedIn() && isSignedInUser(); // is current user's data allow read: if isSignedIn() && isSignedInUser(); // is current user's data
allow update: if isSignedIn() && isSignedInUser() && verifyUpdateFields(getPossibleFields()) && verifyFieldTypes(); allow update: if isSignedIn() && isSignedInUser() && verifyUpdateFields(getPossibleFields()) && verifyFieldTypes();
allow delete: if isSignedIn() && (isSignedInUser() || isAdmin());
match /groups/{groupId} { match /groups/{groupId} {
function verifyGroupFieldTypes() { function verifyGroupFieldTypes() {
@@ -80,8 +82,8 @@ 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 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") || ((getGroupRole(groupId) == "owner" || isAdmin()) && verifyGroupFieldTypes())) && verifyCreateFields(getPossibleGroupFields()); allow create: if isSignedIn() && isSignedInUser() && (getRequestField("role", "") == "member" || (isAdmin() && verifyGroupFieldTypes())) && verifyCreateFields(getPossibleGroupFields());
allow update: if isSignedIn() && ((isSignedInUser() && getRequestField("role", "") == "member") || ((getGroupRole(groupId) == "owner" || isAdmin()) && verifyGroupFieldTypes())) && verifyUpdateFields(getPossibleGroupFields()); allow update: if isSignedIn() && ((getGroupRole(groupId) == "owner" || isAdmin()) && verifyGroupFieldTypes()) && verifyUpdateFields(getPossibleGroupFields());
} }
} }
@@ -91,54 +93,21 @@ service cloud.firestore {
} }
function getPossibleFields() { function getPossibleFields() {
let requiredFields = ["display_name"]; let nonStaticFields = ["display_name"];
let optionalFields = []; let staticFields = ["join_code", "sets", "users"];
let allFields = requiredFields.concat(optionalFields);
return [requiredFields, allFields]; let allFields = staticFields.concat(nonStaticFields);
return [nonStaticFields, allFields];
}
function getPossibleUpdateFields() {
let fields = getPossibleFields();
return [[], fields[0]];
} }
allow read: if isSignedIn() && (getGroupRole(groupId) != null || isAdmin()); allow read: if isSignedIn() && (getGroupRole(groupId) != null || isAdmin());
allow create: if isSignedIn() && getGroupRole(groupId) == "owner" && verifyCreateFields(getPossibleFields()) && verifyFieldTypes(); allow update: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin()) && verifyUpdateFields(getPossibleUpdateFields()) && verifyFieldTypes();
allow update: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin()) && verifyUpdateFields(getPossibleFields()) && verifyFieldTypes();
allow delete: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin()); allow delete: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin());
match /sets/{setId} {
function isSetVisibleToUser(setId) {
return (isPublicSet(setId) || isSetOwner(setId));
}
function verifySetFieldTypes() {
return getRequestField("exists", true);
}
function getPossibleSetFields() {
let requiredFields = ["exists"];
let optionalFields = [];
let allFields = requiredFields.concat(optionalFields);
return [requiredFields, allFields];
}
allow read: if isSignedIn() && ((getGroupRole(groupId) != null) || isAdmin());
allow create: if isSignedIn() && isSetVisibleToUser(setId) && (getGroupRole(groupId) == "contributor" || getGroupRole(groupId) == "owner" || isAdmin()) && verifyCreateFields(getPossibleSetFields()) && verifySetFieldTypes();
allow delete: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin());
}
match /static/data {
function verifyStaticFieldTypes() {
return verifyStringType("join_code");
}
function getPossibleStaticFields() {
let requiredFields = ["join_code"];
let optionalFields = [];
let allFields = requiredFields.concat(optionalFields);
return [requiredFields, allFields];
}
allow read, delete: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin());
allow create: if isSignedIn() && (getGroupRole(groupId) == "owner" || isAdmin()) && verifyCreateFields(getPossibleStaticFields()) && verifyStaticFieldTypes();
}
} }
@@ -146,29 +115,28 @@ service cloud.firestore {
function verifyFieldTypes() { function verifyFieldTypes() {
return verifyBoolType("public") && return verifyBoolType("public") &&
verifyStringType("title") && verifyStringType("title") &&
verifyStringType("owner"); verifyStringType("owner") &&
verifyNullType("groups");
} }
function getPossibleFields() { function getPossibleFields() {
let nonStaticFields = ["public", "title"]; let nonStaticFields = ["public", "title"];
let staticFields = ["owner"]; let staticFields = ["owner", "groups"];
let requiredFields = staticFields.concat(nonStaticFields);
let optionalFields = []; let allFields = staticFields.concat(nonStaticFields);
let allFields = requiredFields.concat(optionalFields); return [nonStaticFields, allFields];
return [requiredFields, allFields, nonStaticFields];
} }
function getPossibleCreateFields() { function getPossibleCreateFields() {
let fields = getPossibleFields(); let fields = getPossibleFields();
return [fields[0], fields[1]]; return [fields[1], fields[1]];
} }
function getPossibleUpdateFields() { function getPossibleUpdateFields() {
let fields = getPossibleFields(); let fields = getPossibleFields();
return [[], fields[2]]; return [[], fields[0]];
} }
allow read, delete: if isSignedIn() && request.auth.uid == resource.data.owner; allow read, delete: if isSignedIn() && request.auth.uid == resource.data.owner;
allow read: if isSignedIn() && resource.data.public; allow read: if isSignedIn() && resource.data.public;
allow create: if isSignedIn() && request.auth.uid == request.resource.data.owner && verifyCreateFields(getPossibleCreateFields()) && verifyFieldTypes(); allow create: if isSignedIn() && request.auth.uid == request.resource.data.owner && verifyCreateFields(getPossibleCreateFields()) && verifyFieldTypes();
@@ -210,19 +178,17 @@ service cloud.firestore {
allow read: if isSignedIn() && isProgressUser(); allow read: if isSignedIn() && isProgressUser();
allow delete: if isSignedIn() && isProgressUser() && isNotComplete(); allow delete: if isSignedIn() && isProgressUser() && isNotComplete();
// TODO: update and create disallowed as these are handled by Cloud Functions to ensure sound file Ids aren't altered to illegally access other files // NOTE: update and create disallowed as these are handled by Cloud Functions to ensure sound file Ids aren't altered to illegally access other files
// TODO: disallow start_time update // NOTE: disallow start_time update
match /terms/{vocabId} { match /terms/{vocabId} {
allow read: if isSignedIn() && isProgressUser() && !(isLanguageSwitched()); allow read: if isSignedIn() && isProgressUser() && !(isLanguageSwitched());
// TODO: create handled by Cloud Functions // NOTE: create handled by Cloud Functions
allow delete: if isSignedIn() && isProgressUser() && isNotComplete();
} }
match /definitions/{vocabId} { match /definitions/{vocabId} {
allow read: if isSignedIn() && isProgressUser() && isLanguageSwitched(); allow read: if isSignedIn() && isProgressUser() && isLanguageSwitched();
// TODO: create handled by Cloud Functions // NOTE: create handled by Cloud Functions
allow delete: if isSignedIn() && isProgressUser() && isNotComplete();
} }
} }
} }