Firebase Storage security rules .matches(regex) not working - firebase

I've been working on writing securities rules for my website and come across an issue.
When I attempt to do the regex "^[0-9].jpg" I get an error. The error says that there is an unexpected "');" in storage.rules on line 8. I've tried changing the regex to "/^[0-9].jpg/" but to no avail. The only regexes it seems to like are the ones I directly copy and past from the docs. As for the regex, I am try to match filenames for 0.jpg, 1.jpg etc but below 10 total files.
Any help is appreciated!
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /photos/{uid}{
match /profile_photos/{image} {
allow read: if isUserIsAuth();
allow write: if isUserIsAuth() && isUserOwner(uid) &&
image.matches('^[0-9]\.jpg');
}
}
}
}
function isUserIsAuth(){
return request.auth != null &&
request.auth.token.email_verified || request.auth != null &&
request.auth.token.firebase.sign_in_provider == "anonymous"
}
function isUserOwner(userID){
return request.auth.uid == userID
}

Related

How to monitor Firestore rules errors?

I just found out that 10% of my Firestore requests go in error:
These are my rules:
service cloud.firestore {
match /databases/{database}/documents {
match /notifications/{notification} {
allow read, delete: if request.auth.uid == resource.data.authUID;
allow create, update: if request.auth.uid == request.resource.data.authUID;
}
match /various/{doc} {
allow read, write: if request.auth != null;
}
}
}
How can I monitor which are these errors?
Or can you see anything particularly wrong in the rules definitions, which can cause errors?
UPDATE:
I have modified the rules according to what #Mises said, but I still get the errors:
service cloud.firestore {
match /databases/{database}/documents {
match /notifications/{notification} {
allow read, delete, update: if request.auth != null && resource.data != null && request.auth.uid == resource.data.authUID;
allow create: if request.auth != null && request.auth.uid == request.resource.data.authUID;
}
match /various/{doc} {
allow read, write: if request.auth != null;
}
}
}
Firebase console only provides an at-a-glance view of rules invocations. Is not possible to get error logs about specific parts of your security rules that fail.
You could enable and disable rules at a time to test which one is producing errors using one of these tools:
Rules playground in the Firebase console.
Emulator suite and its debug function.

Firebase Security Rules -- using attribute from User document

I'm struggling to make my Firebase security rules work.
I only want to allow write access to documents in the collection Nouns to users with the attribute 'admin' == true (boolean) in their user document (stored in collection Users).
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /Users/{userId}/{documents=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId
}
match /Nouns/{documents=**} {
allow read: if request.auth != null
}
match /Nouns/{documents=**} {
allow read, write: if request.auth != null
&& resource.data.admin == true
}
}
}
The rules playground gives the following error when I try a write on a document in the Nouns collection:
Error: simulator.rules line [17], column [13]. Property admin is undefined on object.
Can anyone please let me know what I'm doing wrong?
resource.data will contain data of the document being accessed in Nouns collection. If you want to read data from user's document, use get() instead:
match /Nouns/{documents=**} {
allow read, write: if request.auth != null
&& get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.admin == true
}
Collection names are case-sensitive so make sure you enter it correctly.

How to manage rights in firebase to allow differents users to read/upate/write?

I've a firestore database and I now need to add a new collection.
Each entry of this collection should contain:
Which userId is the owner(field admin)
Which userId has been allowed to edit this element(field writer)
Which userId has been allowed to only read(field reader).
I'm currently only at the first step, and already strugling:
I was hoping to be able to query my collection( /trips/) and get only the one that I'm allowed to access, but I get an error:
FirebaseError: Missing or insufficient permissions.
Here is my rules file:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
match /trips/{trip} {
allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.admin;
allow create: if request.auth != null;
}
}
}
So my questions:
Is this the correct way of managing resource that must be acceeded by multiple people(meaning, I cannot just have the userId in the path since there are multiple users)
How should I query only the documents list that I'm allowed to see?
Thank you very much for your help
As you will read in the doc, "All match statements should point to documents, not collections".
With
service cloud.firestore {
match /databases/{database}/documents {
match /trips {
// ....
}
}
}
you don't point to a document. You should use a wildcard to point to any document in the specified path, as follows:
service cloud.firestore {
match /databases/{database}/documents {
match /trips/{trip} {
// ....
}
}
}
Therefore the following should correctly implement your requirements:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /trips/{trip} {
allow read: if request.auth != null &&
(request.auth.uid == resource.data.admin
|| request.auth.uid == resource.data.writer
|| request.auth.uid == resource.data.reader
);
allow update: if request.auth != null &&
(request.auth.uid == resource.data.admin
|| request.auth.uid == resource.data.writer
);
allow create: if request.auth != null;
}
}
}
Then, for the two questions:
Is this the correct way of managing resource that must be acceeded by multiple people (meaning, I cannot just have the userId in the path
since there are multiple users)
If the admin, writer and reader are specific for each document, yes this is the correct way. If those roles would be more global (e.g. all the trips to Europe can be edited by the same user), you could use a role based approach with Custom Claims.
How should I query only the documents list that I'm allowed to see?
It is important to note that rules are not filter. So your query for getting docs needs to be aligned with the rules. In your specific case, you could have an additional field of type Array which contains three values; the uids of the admin, writer and reader, and use the array-contains operator. Something like:
const user = firebase.auth().currentUser;
const query = db.collection("trips").where("authorizedReaders", "array-contains", user.uid);
match /{document=**} {
allow read, write: if false;
}
You don't need the above code as it will apply to all routes of the database, because of the above line you are getting the below error as it does not allow you to read and write to the database
FirebaseError: Missing or insufficient permissions.
Now, if you want to assign privileges to users then you should add the Role field to users collections which would have a value such as Admin, Editor, Reader
Then, you can check in routes something like below
match /users/{userId}/trips/{tripId} {
allow read, delete: if request.resource.data.role == "Admin";
allow create, update: if request.resource.data.role == "Admin || request.resource.data.role == "Editor";
}
If you want to know more about how to create a route check out this video for the best explanation

How to set Firestore security rules? resource.data: Null value error

I need some help making my security rules for firestore work.
These are my firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderID} {
allow read, update: if request.auth.uid == resource.data.buyerId || request.auth.uid == resource.data.sellerId;
}
}
}
my orders collection:
orders: {
sellerId: 'some-id',
createdAt: timestamp,
buyerId: 'some-id'
}
It should return all documents from orders collection which has either buyerId or sellerId equal to authorised user (request.auth.uid).
but the above rule is not working as expected.
firestore collections screenshot
firebase simulator output
That error message is suggesting that the requested document was not actually present in the database. You entered "orders/{orderId}", which looks like you put a wildcard in the Location field in the simulator. That's not going to work. You need to enter the path to an actual document that exists if you want to test your rule that uses its field values.
resource.data: Null - this error happens when you try to create a new entity.
Split write rule, on create and update.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /user/{userId} {
allow read: if request.auth.uid == userId;
function authed() {
return request.auth.uid == userId;
}
allow create: if authed() && request.resource.data.keys().hasOnly(['name']);
allow update: if authed() && request.resource.data.diff(resource.data).changedKeys().hasOnly(['name']);
allow delete: if authed();
}
}
}

Firestore security rule get() not work

The solution is in the end of the post. Check it out.
Решение проблемы в конце поста. Дочитайте.
just a simple question: whats wrong with this and why this is not working?
Trying to get access with user who has role 'admin' in users section to the /titles/{anyTitle} but still get
Missing or insufficient permissions.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write: if false;
allow read: if false;
}
function userCanWrite () {
return get(/databases/{database}/documents/users/$(request.auth.uid)).data.role == "admin";
}
match /titles/{anyTitle=**} {
allow read: if request.auth != null;
allow write: if userCanWrite();
}
}
}
Here is my database structure
P.S.
I tried another rule from official documents
get(/databases/{database}/documents/users/$(request.auth.uid‌​)).data.isAdmin == true;
and this is not working too
UPDATE: CORRECT WAY TO DO IT
Support helped me find the solution
this is how you should do:
db structure:
users -> {{ userid }} -> { role: "admin" }
database rule settings:
get(usersPath/$(request.auth.uid)).role == "admin" || get(usersPath/$(request.auth.uid)).data.role == "admin";
I contacted to the Firebase support to report that bug and they gave me a temporary solution on this. It seems that they are having a bug in their systems on the security rules side. They say that the documentation is ok, but for now we should workaround this way:
get(path).data.field == true || get(path).field == true;
Because the bug is that data object isn't populated, you should check both properties. There's no ETA for launching a solution on this bug, so I asked they if they could give me an advice when they solved this issue, so I'll keep this answer up-to-date with their information.
So the way I've solved it is I've created another Collection Called admins
Then I've just added the uid of the user I needed there as such -
Here is my database structure - https://i.imgur.com/RFxrKYT.png
And here is the rules
service cloud.firestore {
match /databases/{database}/documents {
function isAdmin() {
return exists(/databases/$(database)/documents/admins/$(request.auth.uid));
}
match /tasks/{anyTask} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update: if request.auth != null && isAdmin();
allow delete: if request.auth != null && isAdmin();
}
}
}
You can view my full Open Source project here:
https://github.com/metaburn/doocrate
You should use $(database) instead of {database} in your code:
get(/databases/{database}/documents/users/$(request.auth.uid)).data.role == "admin";
What worked for me was moving the userCanWrite function above my rules. It appears that the function has to be defined before any of the match rules that call it. Maddening :-)
This is the Firestore rule I use to check if the user is admin.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if userIsAdmin();
}
function userIsAdmin() {
return getUserData().userRole == 'Admin';
}
function getUserData() {
return get(/databases/$(database)/documents/User/$(request.auth.uid)).data;
}
}
}

Resources