I have two Ember models: a items
and comments
. User will post an item, and other users will be able to comment on the items.
I cannot setup security rules within firebase that allow name
and description
to be writable by only the current user, but allow for comments
to be written to by any logged in user.
Item
// app/models/item.js
export default DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
comments: DS.hasMany('comment'),
user: DS.belongsTo('user')
})
Comment
// app/models/comment.js
export default DS.Model.extend({
user: DS.belongsTo('user')
body: DS.attr('string'),
timestamp: DS.attr('string'),
item: DS.belongsTo('user')
})
Saving a comment
// app/components/comment-form.js
const comment = this.get('comment');
const item = this.get('item');
// service that tracks the currently logged in user
const currentUser = this.get('sessionManager.user');
comment.set('timestamp', new Date());
comment.set('user', currentUser);
// setup both sides of the relationship
item.get('comments').pushObject(comment);
comment.set('item', item');
// save both
return Ember.RSVP.Promise.all([item.save(), user.save()]);
All this works fine. Today, I added security rules in firebase. I only want the currently logged in user to be able to edit an item, but allow any other user to add a comment to any item.
"items": {
".read": "auth !== null",
"$item_id": {
// only the currently logged in user can write to this node
".write": "root.child('users/'+data.child('user').val()+'/uid').val() === auth.uid",
// allow any user to write comments
"comments": {
".write": "auth !== null"
}
}
},
In the firebase simulator this works. As the user who owns the item I can write to /items/<item_id>/description
. As a user who does not own the item, I can write to /items/<item_id>/comments/
, but not to /items/<item_it>/description
. However it fails within Ember using Emberfire.
My working theory is that when I add a new comment to an item I do not "own", then I call item.save()
Emberfire tries to write to /items/<item_id>
.
How can I setup Firebase security rules such that only the user who owns the item
can update most of its properties, but any user can add a comment
Here is is in the firebase rules simulator:
Attempt to write to /items/<item_id>/comments
with a user that does not own this item item, with data
{
"cde": "comment_id"
}
will successfully write with the above rules.
However,
Attempt to write to /items/<item_id>
with a user that does not own this item item, with data
{
"comments": {
"cde": "comment_id"
}
}
fails.
The problem is that in the .write
rule you have used the data
predefined variable and data
refers to:
A RuleDataSnapshot representing the data as it existed before the attempted operation.
For new items, data.exists()
will be false
. To allow users to write new items, you should use newData
, instead:
".write": "root.child('users/' + newData.child('user').val() + '/uid').val() === auth.uid"
And, if you want to allow for the deletion of items, you should test for the existence of newData
and use data
if it does not exist:
".write": "root.child('users/' + (newData.exists() ? newData.child('user').val() : data.child('user').val()) + '/uid').val() === auth.uid"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With