5
votes

I would like to allow users to only upload documents to their own bucket in storage with a maximum file size of 1MB, and still let them delete the files. I have added the following, which:

match /myusers/{userId}/{allPaths=**} {
  allow write: if request.auth.uid == userId && request.resource.size < 1 * 1024 * 1024;
  allow read: if request.auth.uid == userId;
}

I am testing both in the simulator and live in my project. This doesn't let me delete the document (access denied). If I remove && request.resource.size < 1 * 1024 * 1024; from the rule above, the the document can be deleted (but then won't prevent upload of files greater than 1MB.

I thought maybe it was rejecting it because request.resource is null, so I tried the following:

match /myusers/{userId}/{allPaths=**} {
  allow write: if request.auth.uid == userId && (request.resource.size < 1 * 1024 * 1024 || request.resource == null);
  allow read: if request.auth.uid == userId;
}

Still, deleting fails with the following error (in the simulator):

Error: simulator.rules line [5], column [16]. Property resource is undefined on object.

enter image description here

I have looked at all of these solutions and modified the rule as many ways as I can think of, to no avail:

Does anyone know how to set a max size for the file allowed but still allow for deleting?

2
Hmm... that last one should work, except that I'm not sure what happens if you dereference null. Can you try with only request.resource == null? If that works correctly, try swapping the conditions in the or: (request.resource == null || request.resource.size < 1 * 1024 * 1024).Frank van Puffelen
@Frank van Puffelen, our thikning is very much in line here -- tried both of these as well. It also fails with allow write: if request.auth.uid == userId && request.resource == null. And, in my screenshot, I did actually swap the order to (request.resource == null || request.resource.size < 1 * 1024 * 1024) in case it was actually crashing on request.resource.size due to attempting to access size from a null object (request.resource). Both didn't work, but the solution I just posted below does! :)Rbar

2 Answers

4
votes

Figured it out! Here's what works both in production and in the simulator :)

match /myusers/{userId}/{allPaths=**} {
  allow write: if request.auth.uid == userId && 
                  (request.resource.size < 1 * 1024 * 1024 || request.method == 'delete');
  allow read: if request.auth.uid == userId;
}

p.s. @Doug Stevenson, if you're able to submit a note internally, I imagine that it would be very helpful for others if request.method examples with delete, update, get, and/or create could be added to the documentation!

EDIT:

Also, this works in both the simulator and production (and is a bit more readable than the first option, in my opinion). Thanks to @Doug Stevenson on the tip!

match /myusers/{userId}/{allPaths=**} {
  allow write: if request.auth.uid == userId && request.resource.size < 1 * 1024 * 1024;
  allow delete: if request.auth.uid == userId 
  allow read: if request.auth.uid == userId;
}
1
votes

As far as I can see, this is just a bug in the console simulator. I wrote actual (Android) app code against these rules, and I was able to create and delete the content with no problems. The problem is that the simulator doesn't understand how to interpret request.resource == null, and just fails the whole thing as a result.

I'll file a bug report internally for this, but you should always check against your rules against the actual product if something doesn't make sense, as it's difficult to keep the simulator fully in sync.