I have this structure
"Following": {
".validate": newData != null && newData.child(count).val() == root.child(Following).child($User).child(count).val() + 1),
"$User": {
"$Following": {
"created": {}
},
"count": {}
}
}
i want to prevent that the count variable can be incremented or decremented without the creation or the delete of a following
for prevent the increment without the creation of a new following i add this rule
".validate": newData != null &&
newData.child(count).val() ==
root.child(Following).child($User).child(count).val() + 1)
but i have problem to prevent the decrement without the delete of a following.
the my ask is this
how can I decrease the count variable only if I know that the Following is going to be deleted ?
sorry for bad english :/
What do you think of this method?
"Event": {
"$User": {
"counter": {
".validate": "newData.hasChildren(['value', 'tmp'])",
"value": {},
"tmp": {},
"$other": {
".validate": "false"
},
".write": "data.val() != null && newData.val() != null && (newData.parent().child(newData.child('tmp').val()).val() != null && newData.child('value').val() == data.child('value').val() + 1 || root.child('Event').child($User).child(newData.child('tmp').val()).val() != null && newData.parent().child(newData.child('tmp').val()).val() == null && newData.child('value').val() == data.child('value').val() - 1)"
},
"$Event": {
//some variable and permissions
}
}
}
i use the tmp variable to recognize the event key that i want verify if is in creation or in delete and consequently i update the value variable .
in the example i add only the update rules without other rules to not get in confusion
Related
I have a realtime database. In rules, doing (a || b) works, but doing (b || a) does not work. I couldn't find the reason. Since my rules are long, I'm putting a small part of it here. actually it was working until today but today it stopped working and i didn't change anything.
Not working :
{
"rules": {
"allGames": {
"$gameID": {
".read": true
".write": "auth != null && ((!data.exists() &&
(newData.child('players').child('0').child('userID').val().contains(auth.uid) ||
newData.child('players').child('1').child('userID').val().contains(auth.uid) ||
newData.child('players').child('2').child('userID').val().contains(auth.uid) ||
newData.child('players').child('3').child('userID').val().contains(auth.uid)) ) ||
(!data.exists() &&
(newData.child('0').child('name').val().contains(auth.uid) ||
newData.child('1').child('name').val().contains(auth.uid) ||
newData.child('2').child('name').val().contains(auth.uid) ||
newData.child('3').child('name').val().contains(auth.uid)) ) )"
}
}
}
}
my json:
[
{
"durum": "davetYollayan",
"name": "PzbcSmKziaOcd4PdYNPnIWuG2iH2",
"score": 0
},
{
"durum": "davetYollayan",
"name": "efezefebcSmKziaOcd4PdYNPnIWuG2iH2",
"score": 0
}
]
Screenshot:
it works when i replace the write code with this. but both codes are the same, I don't understand why it gives an error?
".write": "auth != null && ((!data.exists() &&
(newData.child('0').child('name').val().contains(auth.uid) ||
newData.child('1').child('name').val().contains(auth.uid) ||
newData.child('2').child('name').val().contains(auth.uid) ||
newData.child('3').child('name').val().contains(auth.uid)) ) ||
(!data.exists() &&
(newData.child('players').child('0').child('userID').val().contains(auth.uid) ||
newData.child('players').child('1').child('userID').val().contains(auth.uid) ||
newData.child('players').child('2').child('userID').val().contains(auth.uid) ||
newData.child('players').child('3').child('userID').val().contains(auth.uid)) ))"
l want make only user able to create new post, and only user able to modify only the post that were created by them. Like delete or edit !
database structure
{
"post" : {
"-LWzHsKzAyK9Wfa1kbD_" : {
"name" : "test",
"title" : "test",
"userId" : "8D3sENaBcLaXoGNnh1MPuoyj5LP2"
},
"-LWzHx6u-gQ7XoVR714a" : {
"name" : "check",
"title" : "check",
"userId" : "WUM2HBkGo8TFDeOjEqO1s3lCj1p1"
}
}
}
l used this rules but l got error when to save No such method/property 'userId'.
{
"rules": {
".read": false,
".write": false,
"report": {
".read": "auth != null",
".write": "auth != null && ( (data.exists() && data.userId === auth.uid) || !data.exists() || !newData.exists() )"
}
}
}
You can't just use property accessor notation to get a child value of the data. You must call the child() function to get the child, and the val() function to get its value.
So:
data.child('userId').val() === auth.uid
My app's content is generated by the user. I want each user to access and edit his own data (the nodes he creates). So the user creates a "clips" node and a "clipOwners" node if the nodes are empty and he should also be able also to update any of these nodes and child nodes if he is the owner. Another user shouldn't be able to create a new node if the node pushKey (i.e. "$11111111") is already taken.
Here is my database structure:
clips {
variable Key >>> "111111111111" : {
"MACaddress" : "111111111111",
"comments" : "",
"created" : "Mon Apr 16 2018 12:40:13 GMT+0100 (BST)",
"inRoom" : "-LADDm48Uqabm1bcQGOw",
"ins" : {
"1523878813443" : true
},
"name" : "1",
"outs" : {
"1523878813443" : true
},
"ownerID" : "QpMHsVHHRrMvk92rbSQvcYEv4en1"
},
"222222222222" : {
"MACaddress" : "222222222222",
"comments" : "",
"created" : "Mon Apr 16 2018 12:40:13 GMT+0100 (BST)",
"inRoom" : "-LADDm48Uqabm1bcQGOw",
"ins" : {
"1523878813443" : true
},
"name" : "1",
"outs" : {
"1523878813443" : true
},
"ownerID" : "QpMHsVHHRrMvk92rbSQvcYEv4en1"
}
},
"clipOwners" : {
"111111111111": "QpMHsVHHRrMvk92rbSQvcYEv4en1"
"222222222222": "QpMHsVHHRrMvk92rbSQvcYEv4en1",
}
I am trying this but the "ownerID" child node keeps on being updated by another user if another user tries to write to the same $MACaddress:
"clips": {
".read": "true",
".write": "!data.exists() || newData.exists()",
"$MACaddress":{
"ownerID": {
".validate": "!data.exists() || newData.val() === root.child('clipOwner').child($MACaddress).val()",
}
}
},
"clipOwners": {
".read": true,
".write": "newData.exists()",
"$MACaddress": {
},
Why is it behaving like that?
Any ideas on how I can lock this thing?
In your current write rules you only check if data (not) exists. In this answer i will only focus on the write rules to make sure you can't have duplicate keys (see clipOwners rules) and you can only write to your own data (see clips rules):
"clipOwners": {
".read": true,
"$MACaddress": {
//Only create or delete are possible and value is the user uid
".write": "(!data.exists() || !newData.exists()) && (newData.val() == auth.uid || data.val() == auth.uid)"
}
},
"clips": {
".read": "true",
"$MACaddress":{
//The $MACaddress has to exist in the clipOwners node and its value has to be the user uid
".write": "root.child('clipOwners/'+$MACaddress).exists() && root.child('clipOwners/'+$MACaddress).val() == auth.uid"
}
}
When writing you first have to write the $MACaddress in the clipOwners node because this will be used to check if the user can write to the clips node.
You can take a look at these docs for a simular case.
I have my data like, a teacher and few students with payment options.
I want to structure below data.
Authenticated teacher with read/write access to students profiles.
r/w access to Authenticated student profile.
invoice readable by student however, write access to teacher.
looking for inputs/help in structuring the above dB with security rules in firebase.
Update
Use below sample DB to test against Bradley answer.
{
"invoices" : {
"stid1" : {
"studentID" : "9EtsXHveIyaEkkLLk5hpo6vCtVx1"
}
},
"students" : {
"3d2HnQUxAbgaOqWBEqfDuhkhkj63" : {
"name" : "s2"
},
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"name" : "s1"
}
},
"teachers" : {
"aiBunX1rZceD2lRslEmCrFHS2XF3" : {
"name" : "s1"
}
}
}
The following database rules:
{
"rules": {
// teachers profiles stored under this node
// teachers can read and write under their own node
"teachers": {
"$teacherID": {
".read": "auth != null && auth.uid == $teacherID",
".write": "auth != null && auth.uid == $teacherID"
}
},
// teachers can r/w student profiles, and the students can also r/w their own profile
"students": {
"$studentID": {
".read": "auth != null && (root.child('teachers').child(auth.uid).exists() || auth.uid == $studentID)",
".write": "auth != null && (root.child('teachers').child(auth.uid).exists() || auth.uid == $studentID)"
}
},
"invoices": {
"$invoiceID": {
// assuming each invoice has the student ID located at /$invoiceID/studentID
// students can read, teachers can r/w
".read" : "auth != null && (root.child('invoices').child($invoiceID).child('studentID').val() == auth.uid || root.child('teachers').child(auth.uid).exists())",
".write": "auth != null && root.child('teachers').child(auth.uid).exists()"
}
}
}
}
Works on the following database:
{
"teachers" : {
"aiBunX1rZceD2lRslEmCrFHS2XF3" : {
"name" : "s1"
}
},
"students" : {
"3d2HnQUxAbgaOqWBEqfDuhkhkj63" : {
"name" : "s2"
},
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"name" : "s1"
}
},
"invoice" : {
"stid1" : {
"9EtsXHveIyaEkkLLk5hpo6vCtVx1" : {
"ispaid" : false
},
"studentID" : "9EtsXHveIyaEkkLLk5hpo6vCtVx1"
}
}
}
I created the rule by using the Firebase Bolt compiler.
// ####### Root
path / {
read() = true;
write() = false;
}
// ######## USERS PHOTOS
// Allow anyone to read the list of Photos.
path /users_photos {
read() = true;
}
// All individual Photos are writable by anyone.
path /users_photos/$id is Photos {
write() = isSignedIn();
}
type Photos {
image: String,
user_id: String,
removed: Boolean,
dt_created: InitialTimestamp,
dt_updated: CurrentTimestamp
}
type CurrentTimestamp extends Number {
validate() = this == now;
}
type InitialTimestamp extends Number {
validate() = initial(this, now);
}
//
// Helper Functions
//
isSignedIn() = auth != null;
// Returns true if the value is intialized to init, or retains it's prior
// value, otherwise.
initial(value, init) = value == (prior(value) == null ? init : prior(value));
Ref: https://github.com/firebase/bolt/blob/master/docs/guide.md
My script:
/*Upload*/
VigiApp.controller('UploadController', ['$scope', 'Upload', '$timeout', 'FirebaseURL', function ($scope, Upload, $timeout, FirebaseURL) {
// upload on file select or drop
$scope.upload = function (file, id) {
$('.page-spinner-bar').removeClass('ng-hide hide').addClass('ng-show show');
id = typeof id !== 'undefined' ? id : null;
Upload.base64DataUrl(file).then(function(base64){
//auth
var fbAuth = FirebaseURL.getAuth();
//Ref
var usersPhotosRef = FirebaseURL.child("users_photos");
usersPhotosRef.push({'image': base64,'removed': true, 'user_id': fbAuth.uid}, function(error){
if (error) {
alert('Error: Something went wrong when creating your post please try again');
} else {
var newID = usersPhotosRef.key();
if(id !== null){
$('#'+id).css("background-image", "url('"+base64+"')");
$('#'+id).css("background-size", "100% 100%");
}
}
$('.page-spinner-bar').removeClass('ng-show show').addClass('ng-hide hide');
});
});
}
}]);
Compile ...
>firebase-bolt mmgv-vigiapp.bolt -o rules.json
bolt: Generating rules.json...
And deploy ...
>firebase deploy:rules
=== Deploying to 'vivid-heat-2144'...
i deploying rules
+ Deploy complete!
Dashboard: https://vivid-heat-2144.firebaseio.com
But I'm getting the error:
FIREBASE WARNING: set at /users_photos/-K5VL1m04oF8s2xp8oTf failed: permission_denied
The rules created:
{
"rules": {
".read": "true",
"users_photos": {
".read": "true",
"$id": {
".validate": "newData.hasChildren(['image', 'user_id', 'removed', 'dt_created', 'dt_updated'])",
"image": {
".validate": "newData.isString()"
},
"user_id": {
".validate": "newData.isString()"
},
"removed": {
".validate": "newData.isBoolean()"
},
"dt_created": {
".validate": "newData.isNumber() && newData.val() == (data.val() == null ? now : data.val())"
},
"dt_updated": {
".validate": "newData.isNumber() && newData.val() == now"
},
"$other": {
".validate": "false"
},
".write": "auth != null"
}
}
}
}
When I remove the date, it works.
...
type Photos {
image: String,
user_id: String,
removed: Boolean,
}
...
How can I generate the creation date and update?
Where is my wrong, please?
When you are adding a Photo, you pass this information:
usersPhotosRef.push({'image': base64,'removed': true, 'user_id': fbAuth.uid}
Your security rules, require these properties:
".validate": "newData.hasChildren(['image', 'user_id', 'removed', 'dt_created', 'dt_updated'])",
There is no magic "default value" for dt_created and dt_updated, so you'll need to pass these in from your application code:
usersPhotosRef.push({
'image': base64,
'removed': true,
'user_id': fbAuth.uid,
'dt_created': Firebase.ServerValue.TIMESTAMP,
'dt_updated': Firebase.ServerValue.TIMESTAMP
}
Since this snippet is adding a new record, dt_created and dt_updated are set to the same value. When you update a record, you'll only want to set dt_updated.