Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore replication data creation and rules #6707

Open
ben12 opened this issue Jan 2, 2025 · 5 comments
Open

Firestore replication data creation and rules #6707

ben12 opened this issue Jan 2, 2025 · 5 comments
Labels

Comments

@ben12
Copy link

ben12 commented Jan 2, 2025

I am trying to implement this kind of rules in Firestore database (https://firebase.google.com/docs/firestore/security/insecure-rules#open_access):

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{document} {
      // Allow reads and deletion if the current user owns the existing document
      allow read, delete: if request.auth.uid == resource.data.author_uid;
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;
    }
  }
}

In replication configuration I set filter to be conform with the rules:

        pull: {
          filter: [
            firestore.where("author_uid", "==", getAuth()?.currentUser?.uid),
          ],
        },

But this do not work for data creation because push do a get by ids without the pull filter configuration.

Even though all documents returned by the query have the correct "author_uid", "resource.data.author_uid" is not the result of the query but the potential result obtained using the query criteria (https://firebase.google.com/docs/firestore/security/rules-conditions#rules_are_not_filters) :

Cloud Firestore security rules evaluate each query against its potential result and fails the request if it could return a document that the client does not have permission to read. Queries must follow the constraints set by your security rules.

So, using Firestore replication plugin, it is impossible to implement rules based on the values ​​of the result data fields.

@pubkey
Copy link
Owner

pubkey commented Jan 4, 2025

Can you reproduce this in a unit test?

@ben12
Copy link
Author

ben12 commented Jan 5, 2025

I can reproduce this in an unit test, but when I try to fix it, it not works :/

getDocs(document, where("author_uid", "==", ownerId)) works, but
getDocs(document, where("author_uid", "==", ownerId), where(documentId(), "in", ids)) does NOT work,
getDocs(document, where("author_uid", "==", ownerId), where(documentId(), "==", id)) does NOT work.

I also tried with real firestore instead of emulator, with the same result.

I do not find any explanation or issue about this behavior...
And I am surprised because it is the default example in Firebase documentation (and in yours).

For my project I changed for the user uid in the collection path, but It could be fine for share data between users (with a public boolean field for example).

Copy link

stale bot commented Jan 12, 2025

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.

@stale stale bot added the stale label Jan 12, 2025
@ben12
Copy link
Author

ben12 commented Jan 19, 2025

I found the problem. When we query an non-existent document ID, firestore does not generate the resource variable for the rules.

I tested this code:

  const doc1 = await addDoc(ownershipCollection, {name: 'test1', owner: ownerUid});
  console.log('doc1 added:', doc1.id);
  
  const doc2 = await addDoc(ownershipCollection, {name: 'test1', owner: ownerUid});
  console.log('doc2 added:', doc2.id);

  const docs1 = await getDocs(query(ownershipCollection, where('owner', '==', ownerUid)));
  const ids = docs1.docs.map(doc => doc.id);
  console.log('docs1:', docs1.docs.map(doc => doc.id));

  const docs2 = await getDocs(query(ownershipCollection, where('owner', '==', ownerUid), where(documentId(), 'in', ids)));
  console.log('docs2:', docs2.docs.map(doc => doc.id));

  const docs3 = await getDocs(query(ownershipCollection, where('owner', '==', ownerUid), where(documentId(), 'in', [...ids, '5QwNhNMnKTx8fwTNBnBi'])));
  console.log('docs3:', docs3.docs.map(doc => doc.id));

I get this output:

doc1 added: VYKXfYOckcaH02e08stn
doc2 added: 4BjqNIyeApw3Xs2oLsOv
docs1: [ '4BjqNIyeApw3Xs2oLsOv', 'VYKXfYOckcaH02e08stn' ]
docs2: [ '4BjqNIyeApw3Xs2oLsOv', 'VYKXfYOckcaH02e08stn' ]
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[FirebaseError:
evaluation error at L5:36 for 'list' @ L5, evaluation error at L5:36 for 'list' @ L5, evaluation error at L5:36 for 'list' @ L5, false for 'list' @ L5, false for 'list' @ L5, Variable read error. Variable: [resource]. for 'list' @ L5] {
  code: 'permission-denied',
  customData: undefined,
  toString: [Function (anonymous)]
}

docs2 works, but docs3 where an ID in the list does not exist in firestore database, does not works.

Maybe a firestore issue...

Edit:
I sent the issue to Google using Bug Report form (https://firebase.google.com/support/troubleshooter/report/bugs)

Reproducing Firestore issue: https://github.com/ben12/firestore-issue

@stale stale bot removed the stale label Jan 19, 2025
Copy link

stale bot commented Jan 26, 2025

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.

@stale stale bot added the stale label Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants