Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate array values with firestore's security rules?

I've a form which creates the following JSON structure.

{  
   "reviewed":false,
   "title":"Just a title",
   "user":"UYV9TRKXfNW1NeCyFyfjZfagJ8B",
   "items":[  
      {  
         "age":"33",
         "experience":"Newcomer",
         "image":"https://image-url",
         "job":"Nerd",
         "name":"Testname",
         "party":"AAA",
         "type":"person"
      },
      {  
         "age":"33",
         "experience":"Newcomer",
         "image":"https://image-url",
         "job":"Informatiker",
         "name":"Testname",
         "party":"AAA",
         "type":"person"
      }
   ]
}

How do I check the values of "items" with firestore's security rules? Is there a way to loop/iterate over the array?

like image 350
Fabian Avatar asked Aug 15 '18 10:08

Fabian


1 Answers

For the sake of completeness: That's my solution so far. I did it the way described in the linked answer. The possible amount of items is limited to 10, so we can go without dynamic loops.

service cloud.firestore {
  match /databases/{database}/documents {
    match /events/{event} {

      function isAuthed() {
        return request.auth.uid != null
            && request.auth.uid == request.resource.data.user
            && request.auth.token.email_verified == true;
      }

      function isReviewed() {
        return request.resource.data.reviewed == false
            || request.resource.data.reviewed == "false"
      }

      function isValidTitle() {
        return isValidStringInput(request.resource.data.title, 200);
      }

      function items() {
        return request.resource.data.items;
      }

      function isValidPerson(item) {
        return items()[item].keys().hasAll(['image','type','name','job','age','party','experience'])
                && isValidStringInput(items()[item].image, 100)
                && isValidStringInput(items()[item].type, 10)
                && isValidStringInput(items()[item].name, 50)
                && isValidStringInput(items()[item].job, 50)
                && isValidStringInput(items()[item].party, 50)
                && isValidStringInput(items()[item].experience, 50)
                && isValidNumber(items()[item].age);
      }

      function isValidParty(item) {
        return items()[item].keys().hasAll(['image','type','name','orientation','experience','promi'])
                && isValidStringInput(items()[item].image, 100)
                && isValidStringInput(items()[item].type, 10)
                && isValidStringInput(items()[item].name, 50)
                && isValidStringInput(items()[item].orientation, 50)
                && isValidStringInput(items()[item].experience, 50)
                && isValidStringInput(items()[item].promi, 50);
      }

      function isValidItem(item) {
        return isValidPerson(item)
            || isValidParty(item);
      }

      function isValidStringInput(input, maxSize) {
        return input is string
            && input.size() > 0
            && input.size() <= maxSize;
      }

      function isValidNumber(input) {
        return input is int
            || input.matches('^[0-9]+$');
      }

        // One can READ
            // always ...
        allow read: if true;

      // One can WRITE, when ...
        // writer is logged in
        // uid in event is same as uid of writer
        // writer has email confirmed
        // reviewed is initial set to false
        // form/user input is ok
      allow write, update:
        if isAuthed()
        && isReviewed()
        && isValidTitle()
        && items().size() >= 1
        && items().size() <= 10
        && isValidItem(0)
        && (items().size() < 2 || isValidItem(1))
        && (items().size() < 3 || isValidItem(2))
        && (items().size() < 4 || isValidItem(3))
        && (items().size() < 5 || isValidItem(4))
        && (items().size() < 6 || isValidItem(5))
        && (items().size() < 7 || isValidItem(6))
        && (items().size() < 8 || isValidItem(7))
        && (items().size() < 9 || isValidItem(8))
        && (items().size() < 10 || isValidItem(9));
    }
  }
}
like image 69
Fabian Avatar answered Sep 19 '22 13:09

Fabian