Ankur
Ankur

Reputation: 181

Firestore rules to write/update one particular field without auth

I want to give write/update access to only one field from my firestore database collection without requesting the auth service. My rules for firestore is:

service cloud.firestore {
  match /databases/{database}/documents {
    match /businesses/{businessId} {
      allow read;
      allow write: if request.auth.uid != null;
    }
  }
}

My database structure for businesses is:

addedBy: string;
address: string;
category: string;
claim: boolean;
city: string;
email: string;
id: string;
likes: number;
location: {
    _lat: number,
    _long: number
};
name: string;
ocHours: [{
    day: string,
    from: string,
    status: string,
    to: string
}];
phone: number;
sponsored: boolean;
state: string;
status: string;
verificationCode: string;

I want to update only the claim field without request.auth.uid != null.

Any suggestions?

Upvotes: 3

Views: 2058

Answers (5)

Mattia Galati
Mattia Galati

Reputation: 2587

I don't know if this thread is still valid, but searching for a solution I stumbled upon the rules.MapDiff spec, that does exactly what you are looking for:

// Compare two Map objects and return whether the key "a" has been
// affected; that is, key "a" was added or removed, or its value was updated.
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["a"]);

See here for details https://firebase.google.com/docs/reference/rules/rules.MapDiff

Upvotes: 6

yuri
yuri

Reputation: 191

As explained in this blog post, request.resource.data does not contain only the updated fields, but the entire future state if the write would be successful.

So you could simply check if the field in the resource differs from the one in the request and, as the author neatly suggests, create a function like this:

function notUpdating(field) {
 return !(field in request.resource.data) || resource.data[field] == request.resource.data[field]
}

In your case, you would probably want to break your write into create,update,delete and the update could look something like this:

allow update: if
     notUpdating(addedBy)
  && notUpdating(address)
  && notUpdating(category)
  // ... put all fields here except 'claim'
  && notUpdating(status)
  && notUpdating(verificationCode) ;

Upvotes: 1

ampgular
ampgular

Reputation: 91

rights assignments in firestore Rules as Ron says can only be applied to a whole document. Nevertheless there is a way of allowing to write/update/delete/create a specific file and that is by ensuring that the incoming change object has only the field you want to grant rights. And you do that by:

  1. Reading all keys in the incoming Object: request.resource.data.keys()
  2. Ensuring that the only key in the object is hasOnly(["claim"])

service cloud.firestore {
    match /databases/{database}/documents {
        match /businesses/{businessId} {
            allow read;
            allow write: if request.resource.data.keys().hasOnly(["claim"]); 
        }
    }
}

Hope it helps although the question was posted a while a go!!

Upvotes: 9

Tilo
Tilo

Reputation: 635

I have written the following function to be used to allow only one field to be editable:

function onlyField(field) {
    return request.resource.data.keys().hasOnly([field]);
}

This function can be used as follow:

match /someObject/{document=**} {
    allow update: if onlyField('someFieldOfYOurObject');
}

Upvotes: 0

Ronnie Smith
Ronnie Smith

Reputation: 18555

Authorization is applied to the entire document. You can create a "claims" collection of documents identified by business-uid's and set it to write only so it is impossible for public to read the list but they can update the claim property. These documents could be boolean like

home/claimsCollection
    bizABC123
        claim:true
    bizXYZ123
        claim:false

Upvotes: 0

Related Questions