Skip to content

Commit

Permalink
Disable firestore rules as a workaround fix for 804
Browse files Browse the repository at this point in the history
  • Loading branch information
silviot committed Sep 8, 2023
1 parent da5eb86 commit d44be31
Showing 1 changed file with 2 additions and 198 deletions.
200 changes: 2 additions & 198 deletions packages/firestore/firestore.rules
Original file line number Diff line number Diff line change
@@ -1,204 +1,8 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// #region auth-checks
function isAdminByEmail(request, org) {
return (
request.auth.token.email != null &&
request.auth.token.email in org.data.admins
);
match /{document=**} {
allow read, write: if true;
}
function isAdminByPhone(request, org) {
return (
request.auth.token.phone_number != null &&
request.auth.token.phone_number in org.data.admins
);
}
function isAdmin(organization) {
// Given an organization name retrieve it from firestore
// and check if the currently logged in user is part of the admin
// array in that document. If they are return true.
let org = get(/databases/$(database)/documents/organizations/$(organization));
return request.auth != null && (isAdminByEmail(request, org) || isAdminByPhone(request, org));
}
// #endregion auth-checks

// #region enums
function getCategories() {
return ["course-adults", "pre-competitive-adults", "course-minors", "pre-competitive-minors", "competitive"]
}
function getSlotTypes() {
return ["ice", "off-ice"]
}
// #endregion enums

// #region type-checks
function checkRequiredString(input) {
return (
input is string &&
input.size() > 0
)
}
function checkOptionalBoolean(data, property) {
return (
!(property in data) ||
data[property] is bool
)
}
// #endregion type-checks

// #region regex-checks
// we're using this func to check if the required date is a valid ISO string
function checkValidDate(date) {
return (
date is string &&
date.matches('[12][0-9][0-9][0-9]-[01][0-9]-[0123][0-9]')
);
}
// we're using this func to check if the optional date is a valid ISO string
function checkOptionalValidDate(data, property) {
// if the field is an empty string, we bypass the check
return (
!(property in data) ||
data[property] == "" ||
checkValidDate(data[property])
)
}
function checkValidEmail(email) {
return email.matches("^\\w+([\\.#$%&*+/=?^`.{|}~-]?\\w+)*@\\w+([\\.#$%&*+/=?^`.{|}~-]?\\w+)*(\\.\\w\\w+)+$")
}
function checkValidPhoneNumber(phone) {
return phone.matches('(\\+|00)[0-9]{9,15}')
}
// #endregion regex-checks

// #region helpers
// Check that the date isn't updated or if updated
// should be the same as in the existing resource
function checkConsistentDate(data, storedData) {
return (
!("date" in data) ||
data.date == storedData.date
)
}
// #endregion helpers

match /organizations/{organization} {
allow read, write: if isAdmin(organization);

match /slots/{slotId} {
// Only admins can read/delete slots
allow read, delete: if isAdmin(organization)
// Validate data integrity for create/update
allow create, update: if isAdmin(organization) &&
// check date
checkValidDate(request.resource.data.date) &&
// check valid type
request.resource.data.type in getSlotTypes() &&
// contains only supported categories
request.resource.data.categories.hasOnly(getCategories())
}
// #endregion slot-checks

// #region slots-by-day-checks
match /slotsByDay/{document=**} {
// Everyone has access to all available slots.
// Security-wise this is equivalent to showing a form that lets unauthenticated
// users book their slots, as is the current solution.
allow read: if true;
}
// #endregion slots-by-day-checks

// #endregion bookings-checks
match /bookings/{secretKey} {
// Anybody with 'secretKey' can read from 'bookings'
// No one should be able to write to bookings document (it's done through cloud functions)
allow read: if true;

function checkBookingSlot(slotId, bookingData) {
let bookedSlot = get(/databases/$(database)/documents/organizations/$(organization)/slots/$(slotId));

return (
// Check date integrity
bookingData.date == bookedSlot.data.date &&
// Check interval integrity
bookingData.interval in bookedSlot.data.intervals
);
}
function checkBookedSlotCategory(slotId) {
let customer = get(/databases/$(database)/documents/organizations/$(organization)/bookings/$(secretKey));
let bookedSlot = get(/databases/$(database)/documents/organizations/$(organization)/slots/$(slotId));

return customer.data.categories.hasAny(bookedSlot.data.categories)
}
match /bookedSlots/{slotId} {
// Anybody with secret key should be able to read and write (with valid data) to 'bookedSlots'
allow read, delete: if true;
// Check data integrity for create/update
allow create, update: if (
checkBookingSlot(slotId, request.resource.data) &&
checkBookedSlotCategory(slotId)
)
}
match /attendedSlots/{slotId} {
allow read: if true;
}
match /calendar/{date} {
// Anybody with secret key should be able to read and write
allow read, write: if true;

}
}
// #endregion bookings-checks

// #region customer-checks
match /customers/{customerId} {
// Only admins can access customer collection
allow read, delete: if isAdmin(organization)
// Check data integrity
allow create, update: if (
isAdmin(organization) &&
// Check required fields
checkRequiredString(request.resource.data.name) &&
checkRequiredString(request.resource.data.surname) &&
// Check optional dates
checkOptionalValidDate(request.resource.data, "birthday") &&
checkOptionalValidDate(request.resource.data, "certificateExpiration") &&
request.resource.data.categories.hasOnly(getCategories()) &&
// Check valid email
(
!("email" in request.resource.data) ||
request.resource.data.email == "" ||
checkValidEmail(request.resource.data.email)
) &&
// Check valid phone number
(
!("phone" in request.resource.data) ||
request.resource.data.phone == "" ||
checkValidPhoneNumber(request.resource.data.phone)
)
)
}
// #region customer-checks

// #region attendance-checks
match /attendance/{slotId} {
// Only admin can access attendance
// Only read and (conditional) update access are allowed
// Everything else gets updated by cloud function
allow read: if isAdmin(organization);
allow update: if (
isAdmin(organization) &&
// Check that the date doesn't change
checkConsistentDate(request.resource.data, resource.data)
)
}
// #endregion attendance-checks
}
// #region public-info-check
match /publicOrgInfo/{organization} {
allow read: if true;
}
// #endregion public-info-check
}
}

0 comments on commit d44be31

Please sign in to comment.