14

I'm crying myself to sleep on this one.

My getAfter is returning an object that only has 1 field, as every other field type is incorrect. Which I have no idea how to check without any debugging tools (I can't see the data, so its all guess and check).

Here is a watered down version of my rules for users.

match /users/{userId} {
  function isValidUser(user) {
    return user.id is string &&
       (user.address is string || user.address == null) &&
       (user.dateOfBirth is number || user.dateOfBirth == null) &&
       user.email is string &&
       user.name is string &&
       (user.phoneNumber is string || user.phoneNumber == null);
  }

  function isValidWrite(userId, user) {
    return signedIn() && 
        writeHasMatchingId(userId, user) &&
        isValidUser(user);
  }

  allow read: if signedIn();
  allow create: if signedInAndWriteHasMatchingId(userId) &&
    userHasId(userId) &&
    isValidUser(request.resource.data); // Tested
  allow update: if isValidWrite(
    userId,
    getAfter(/databases/$(database)/documents/users/$(userId))
  );
}

and this is the transaction I am trying to run.

const user1Ref = this.userCollection.doc(user1Id);
const user2Ref = this.userCollection.doc(user2Id);
const batchWrite = this.store.batch();

batchWrite.update(user1Ref, {
     "details.friend": user2Id,
});
batchWrite.update(user2Ref, {
     "details.wishlist": true,
});

batchWrite.commit();

If I comment out the isValidUser(user) line, the operation succeeds. If I leave any line uncommented out inside the function isValidUser(user) except user.id is string, it fails.

Why would the getAfter document only have the id field and no others when they are listed in the Firebase console? Is there a way to output or debug the value of getAfter so I can see what it even is?

ColdLogic
  • 7,206
  • 1
  • 28
  • 46
  • 1
    We can simulate the firebase security rules...I don't think we can debug them. – Sushant Somani Oct 18 '18 at 06:23
  • why are you using write when you have create? Either use write or use granular operations – Umar Hussain Oct 18 '18 at 07:06
  • https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations – Umar Hussain Oct 18 '18 at 07:06
  • @UmarHussain it was actually a typo when typing out the question. In my rules, it is an `update`, not a `write`. I updated the question. – ColdLogic Oct 18 '18 at 07:54
  • How did u end up debugging the rules. – Ride Sun Jan 26 '20 at 20:31
  • @RideSun Never found a perfect way to do it. If there are no new tools, then my methods were to comment out half the rules and attempt the operation. If it succeeds, then you know one of the ones you commented is the problem. Then you can keep going through by commenting half of the problem ones. Do this until you find the culprit and once you have it narrowed down to a single rule you can start checking the data before you send it to Firebase, what it looks like when you make the call, and what you expect to return. Very difficult – ColdLogic Jan 27 '20 at 12:49
  • Thank u . Sounds like programming I'm the 70's. – Ride Sun Jan 27 '20 at 15:45

2 Answers2

7

I'm answering based on just one line of your question:

Is there a way to output or debug the value of getAfter so I can see what it even is?

There kind of is - at least in 2020.

When one runs something in the Rules Playground (Rules Simulator, see bottom left), the steps taken in the rule evaluation are shown like this:

enter image description here

This list sometimes gives indications that help figure out what the rules evaluator is doing. It's a bit tedious that one needs to 'click' the steps open, individually, instead of seeing true/false just by glancing. But it's better than nothing.

Note: I presume this feature is under development by Firebase. It sometimes seems to give wrong information - or I have failed to read it correctly. But it may help, and looks like a good place for providing such information to the developers. We really would like to see: with the current data, the built query document, and the rules, how does Firebase see it and why does the rule evaluate to true or false?

akauppi
  • 17,018
  • 15
  • 95
  • 120
2

Another approach, not mentioned here yet and likely not available at the time the question was raised, is wrapping your rules with debug().

Why this is cool?

  • Allows to see the values suspected of not being right; I still use the same comment-out-narrow-down method that @ColdLogic nicely described in one of their comments

Why this is not enough?

  • There is no tagging about which value was output; just eg. int_value: 0. Debug would benefit from eg. printing the first 10 letters of the equation it's evaluating, in the output.

  • Security Rules rejection reasons are still awfully short, as false for 'update' @ L44.

    • the line number always points to the main expression being evaluated. Never to a function called, or a subexpression with && that really causes the fail.

    Firebase could fix this (not change the output syntax; just give a more detailed line number). That would eliminate the need to comment-out-and-narrow-down.

  • The output goes to firestore-debug.log (fairly hidden), so one needs to open yet another terminal and keep an eye on it.

Debugging Security Rules is unnecessarily difficult - and I'm afraid it means people don't use their full potential. We should change this.

akauppi
  • 17,018
  • 15
  • 95
  • 120