Firestore Storage Rules Chat - google-cloud-firestore

I have a chat application in which images can be sent, I want to write the security rules for Storage so that only what is in the chats collection and in the UserIds array can send images, but it always tells me that I am not authorized.
service firebase.storage {
match /b/{bucket}/o {
match /Users/{userId}/{allPaths=**} {
allow read: if request.auth.uid != null;
allow write: if request.auth.uid == userId;
}
match /Chats/{chatId}/{documents=**} {
allow read, write: if chatRoomPermission(chatId)
}
function chatRoomPermission(chatId) {
return request.auth.uid in get(/databases/$(database)/documents/Chats/$(chatId)).data.userIds;
}
}
}

Posting this as a Community Wiki as it's based on Frank's Comments:
Reading data from Firestore directly in the Firebase Rules of your Storage is not possible and the alternative os using custom claims is not possible since they cannot exceed 1000 bytes.
The alternative you have in this case would be to create the control in your app's code or in a Cloud Function.

Related

Firestore security rule that only allows writes on documents to specific fields?

I know that Firestore security rules cannot restrict document reads at the field level, but can they only allow a write if the write is updating a specific field?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /someCollection/{doc} {
// Anyone can read
allow read: if true;
// Only allow write if signed in and the field they are changing is `count`
allow write: if request.auth != null && ?????;
}
}
}

Firestore security when retrieving document by id denies permission

When I directly retrieve a document using .doc().get() firestore security rues deny permission. What do I need to do to allow CRUD operations for authenticated users of my Ionic app?
I have the following function in my PWA Ionic app
``` async getUserProfile(): Promise<firebase.firestore.DocumentSnapshot> {
const user: firebase.User = await this.authProvider.getUser();
this.currentUser = user;
console.log('found current user');
this.userProfile = firebase.firestore().doc(`userProfile/${user.uid}`);
console.log('returing userprofile', this.userProfile.get());
return this.userProfile.get();
}```
But the call to this.userprofile.get() fails due to security warning from Firestore Security rules
found current user
returing userprofile
ZoneAwarePromise
__zone_symbol__state: 0
__zone_symbol__value: FirebaseError: Missing or insufficient permissions. at new e (http://localhost:8100/vendor.js:92760:23) at http://localhost:8100/vendor.js:102987:28
.
.
.
(http://localhost:8100/polyfills.js:10248:56)
code: "permission-denied"
name: "FirebaseError"
toString: ƒ ()
message: "Missing or insufficient permissions."
stack: "FirebaseError: Missing or insufficient permissions.\n at new e
The Firestore Security Rules are set simply as
service cloud.firestore {
match /databases/{database}/documents {
match /userProfile/{userId}/{documents=**} {
allow read, update, get,delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
What should be the correct security rule to implement to allow authenticated users to CRUD their documents? Or the correct way to retrieve the document from the collection
UPDATE: It works directly from the simulator but not from the app
Some inspiration. I use this very basic role based access to allow read and write where a normal user can read and admins can write:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
function googleProvider() {
return request.auth.token.firebase.sign_in_provider == "google.com";
}
function getUserData() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
}
allow read: if googleProvider() && getUserData().roles['user'] == true;
allow write: if googleProvider() && getUserData().roles['admin'] == true;
}
}
}
What version of security rules do you have?
There is a hint for the version 1:
Security rules use version 1 by default. In version 1, recursive wildcards match one or more path items. They do not match an empty path, so match /cities/{city}/{document=} matches documents in subcollections but not in the cities collection, whereas match /cities/{document=} matches both documents in the cities collection and subcollections.
That could explain why you can't get the data you want.
The version 2 behaves different:
In version 2 of the security rules, recursive wildcards match zero or more path items. match/cities/{city}/{document=**} matches documents in any subcollections as well as documents in the cities collection.
Here you can see the whole docu for it.
The version should be on top of your rules like here:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}

Firebase Firestore server side rules - problems

I have an app in iOS that I'm nearly complete and I'm working to configure the server side rules in Firestore. I'm copying the rules identically to another app I have which users the same authentication and database structure. This set of code is not working however.
My data structure has two root collections: User and Feed. Feed is a public collection that any authenticated user should be able to access.
The User Collection and sub collections should only be accessible to the authenticated user who is logged in.
The feed access is working correctly here, but I'm not able to read and presumably not write anything to the user collection/subcollections.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
match /feed/{docId} {
allow read, write: if request.auth != null;
}
}
}
This works - so it is established that the authentication is working. The user documentID is the same as the UID in the authentication table. I'm going nuts with this.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
}
}
I got it to work with this - I still don't understand why my other app works but not this one.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth.uid == userId;
}
match /feed/{docId} {
allow read, write: if request.auth != null;
}
}
}

Security rules Firestore

I'm trying to secure my data in Firestore. I have read the documentation and watch some videos but I still have some difficulties getting it right.
What I have built is a project app. With a data structure like this:
"School": {
school1:
school2: {
"Users": {
userId: {
"SchoolName": "school2"
}
}
"Projects": {
projectId: {
}
}
}
}
Only authenticated users can read and write to the whole database and only users in the same school can read and write data to that school. For example, only users in school2 can add a project to school2.
I tried something like this but it didn't work
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
match /School/{schoolName} {
allow read, write: if get(/databases/{database}/documents/School/$(schoolName)/Users/{userId}).data.SchoolName[(schoolName)]
}
}
}
Can someone please show me how to do this and maybe some good explanation on how to think about security rules. Thank you very much in advance!
you made just one mistake, replace this line:
allow read, write: if get(/databases/{database}/documents/School/$(schoolName)/Users/{userId}).data.SchoolName[(schoolName)]
with this :
allow read, write: if get(/databases/{database}/documents/School/$(schoolName)/Users/{request.auth.uid}).data.SchoolName == "school2"

Security Rules for Firestore to allow access to all subcollections based on UID

So trying to setup my firestore database and I have a collection called Users that stores the users information. I also have subcollections of Towers for each user. My users documents have a playerUid field that I use for security settings. Here are my current security rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
}
match /users/{user=**}{
allow read, create: if request.auth.uid != null;
allow update: if request.auth.uid == resource.data.playerUid;
}
}
}
this allows users to read, create both their user document and the subcollection of tower documents, but they cant edit the subcollection. There is no playerUid in the tower documents. Is there a way to use the playerUid in the user document to authenticate for updating the towers? Or do I need to add a playerUid field to the tower documents to authenticate against
You can get the user document in the rules of the Towers subcollection as shown in the Firestore documentation on accessing other documents:
allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
Alternatively you can indeed include the UID if the user in the documents of the subcollection. That will prevent needing an extra document read in the rules.
This snippet may be able to help you
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
}
match /users/{user=**}{
allow read, create: if request.auth.uid != null;
allow update: if request.auth.uid == user; // <== THIS LINE
}
}
}
Wouldn't this match the 'user' path with the 'uid'?
I will try test this when I have some time.
It would save a get call if it does work.