Firebase rules access to data - ios

I'm going to create app to share photo albums, using firebase.
Now I've issue with securing common objects.
My data object is
"Album" : {
"AbAY6YVhy6MLyvVjyYC517v62o22" : {
"-KeD0I9C-esXW2zA4uH_" : {
"backgroundPattern" : 0,
"collaboratorsIDS" :
[ "cS5O4Klt8CXrrKLJPVkHMaSTltW2","J55nZlr4SSPHL5GW7c7yrUkbAUl1", "LQ5mNECXAMQi9AoLCXh8GMsihf12" ],
"date" : "2017-03-02",
"direction" : 2,
"imageUrl" : "",
"ownerID" : "AbAY6YVhy6MLyvVjyYC517v62o22",
"scrapBookID" : "-KeD0I9C-esXW2zA4uH_",
"title" : "Test"
}
}
And question is, how to set .read and .write rules for albums. Main point is that collaboratorsIDS is user ID's that should have access to album.

"Album": {
"$albumId" : {
"$pushKey" : {
".read":"data.child('collaboratorsIDS').val().contains(auth.uid)"
}
}
With this, you can allow access to your node for collaboratorsIDS

Related

Delete all Data belonging to user

I am rebuilding a social media app like Instagram.
My user can decide to delete their account and then I would like to automatically delete all things belonging to the user.
Most of the stuff I can delete easily, but things like posts is where I struggle because the uid is just a sub child of the key where the post is saved into.
My Database tree:
"Feed" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
"-KjTBFFE5QzktG1IT5u0" : true,
"-KjTHFNe1RRS8Ly6bKsA" : true,
"-KjY30xwWA2IJBwlvyzf" : true
}
"myPosts" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : {
"-KjTBFFE5QzktG1IT5u0" : true,
"-KjTHFNe1RRS8Ly6bKsA" : true,
"-KjY30xwWA2IJBwlvyzf" : true
}
"posts" : {
"-KjTBFFE5QzktG1IT5u0" : {
"bookmarkCount" : 0,
"caption" : "Toll",
"commentCount" : 1,
"creationDate" : 1.494081403379004E9,
"hoursSinceUpload" : 0,
"likeCount" : 0,
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F76192CBE-55F0-4907-889A-849E196D5796?alt=media&token=de675609-4b73-411d-b402-f1ff3db64f79",
"ratio" : 1.502732240437158,
"score" : 16.38698994684219,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
},
"-KjTHFNe1RRS8Ly6bKsA" : {
"bookmarkCount" : 1,
"bookmarks" : {
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"caption" : "Traumhaft",
"commentCount" : 0,
"creationDate" : 1.494082976550228E9,
"hoursSinceUpload" : 0,
"likeCount" : 2,
"likes" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : true,
"jlkRoaucY6Q4GBkzhor5yAAl97I2" : true
},
"photoUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/Posts%2F306BF7E1-9FEF-493A-ABF8-C0E061E8648F?alt=media&token=128bdd90-023a-49ac-8361-19c02c631183",
"ratio" : 1.502732240437158,
"score" : 166.6491847103437,
"uid" : "jlkRoaucY6Q4GBkzhor5yAAl97I2"
}
"users" : {
"es5fIbnKFpX4szcCbroUqHjJg6E3" : {
"email" : "user3#mail.de",
"profilText" : "Schreib etwas über dich",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/funcloud-8e84e.appspot.com/o/profile_image%2Fes5fIbnKFpX4szcCbroUqHjJg6E3?alt=media&token=ce8d8722-39bc-457a-8149-e51c837ef0a3",
"username" : "Blondine",
"username_lowercase" : "blondine"
}
My function where I delete data
static func removeUserData() {
let user = Auth.auth().currentUser
let uid = API.User.CURRENT_USER?.uid
Database.database().reference().child("users").child(uid!).removeValue()
Database.database().reference().child("Feed").child(uid!).removeValue()
Database.database().reference().child("Favoriten").child(uid!).removeValue()
Database.database().reference().child("LikesFromUsers").child(uid!).removeValue()
Database.database().reference().child("post-comments").child(uid!).removeValue()
Database.database().reference().child("notification").child(uid!).removeValue()
Database.database().reference().child("followers").child(uid!).removeValue()
Database.database().reference().child("following").child(uid!).removeValue()
Database.database().reference().child("LikesCommentsFromUsers").child(uid!).removeValue()
Database.database().reference().child("comments").child(uid!).removeValue()
user?.delete(completion: { (error) in
if let error = error {
print(error.localizedDescription)
} else {
print("success")
}
})
}
I would love to iterate through all posts and look for every post which contains the uid of the current user and then delete these posts.
Thanks in advance :)
I would build a server task that can run this asynchronously, removing the responsibility from the mobile device. If the app crashes or loses connection, you'll get a severely broken data set. You need to be able to run it in a stable and verifiable environment. This inherently solves your problem as well, since now you can (at your server's leisure) cycle through and delete all posts owned by the user.
As far as your app is concerned, you'll just need to call a single API after validating that the user wants to delete their account, and voila.

In the iOS SDK (Swift 3.0), Firebase Database Queries that make use of "queryOrdered/queryEqual", don't work as expected

When running the code below, I get an empty response, even though the corresponding data is there:
self.ref?.child("play-data/calories/GC5g4RUmy0WTTL5w3jSobefa9Ft2").
queryOrdered(byChild: "parentId").
queryEqual(toValue: "-KcpS62MR-73MozKJEVt").
observeSingleEvent(of: .value, with: { (snapshot) in
print("ITEMS \(snapshot.childrenCount)")
}) { (error) in
print("ERROR :: \(error)")
}
The data looks like this:
{
"play-data" : {
"calories" : {
"GC5g4RUmy0WTTL5w3jSobefa9Ft2" : {
"-KcpTSo0KrnNIzmAAD9O" : {
"endTime" : 1486955567572,
"id" : "-KcpTSo0KrnNIzmAAD9O",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955550331,
"value" : 1.328500509262085
},
"-KcpTT---0Zu-0eTd4a8" : {
"endTime" : 1486955627572,
"id" : "-KcpTT---0Zu-0eTd4a8",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955567572,
"value" : 4.62333345413208
},
"-KcpTT-1SvZrScKdceLC" : {
"endTime" : 1486955636994,
"id" : "-KcpTT-1SvZrScKdceLC",
"parentId" : "-KcpS62MR-73MozKJEVt",
"startTime" : 1486955627572,
"value" : 0.7260898947715759
}
}
}
So based on the data, it should print 3 but does 0. Permissions are configured correctly since I have Android and web implementations that work fine with this data. Any ideas?
OK, looks like this was the result of my local and cloud versions of the data being out of sync and therefore the inconsistent results during testing (where I had to run tests, replace the post-test data with an older backup, repeat) I fixed these issues by adding this line to my init code:
ref?.child("play-data").keepSynced(true)
I already had this one before:
db?.persistenceEnabled = true
Where ref and db are references to FIRDatabaseReference/FIRDatabase.

Create push notification when value in firebase database change

I want to send a push notification to the user when a value in my firebase database change. this is my database
{
"Battles" : {
"00000111-062B3333-4046-4FB4-AA37-C2B05853E497" : {
"BattleProgress" : "",
"Player1" : "lzsPuNwHbIZI1J8k40FspYRV4XQ2",
"Player2" : "tHNBif9csWNCOuftAGLAqvLWNUw1",
"Score" : "0-0",
"Turn" : 1
}
},
"users" : {
"lzsPuNwHbIZI1J8k40FspYRV4XQ2" : {
"Coins" : 1,
"Dollars" : 0,
"FBID" : “ID”,
"GamesLost" : 0,
"GamesWon" : 0,
"name" : “Name”
},
"tHNBif9csWNCOuftAGLAqvLWNUw1" : {
"Coins" : 0,
"Dollars" : 0,
"FBID" : “ID”,
"GamesLost" : 0,
"GamesWon" : 0,
"name" : “Name”
}
}
}
So lets say, the value of "Turn" changes, then I want a push notification sent out to the player whos turn it is. But how can I check if the value of "Turn" changes when the user shuts down the app?
I've read a bit about Firebase Cloud Messaging, but cant seem to find the answar...
You can do this with Firebase using Cloud Functions. Check out https://firebase.google.com/docs/functions/use-cases and https://firebase.google.com/docs/functions/database-events for more information.

Firebase: Searching child nodes that have a unique ID

I'm fairly new to Firebase and have a rankings app, where my structure currently looks like the following:
{
"Rankings" : {
"-KFGX5H3rLSnpPvupakm" : {
"Sports Teams" : {
"Red sox" : 1,
"Warriors" : 3,
"Yankees" : 2
}
},
"-KFGZkwAIl817CLDLmMp" : {
"Beers" : {
"Bud light" : 3,
"Coors" : 2,
"Pbr" : 4
}
}
}
}
I'm using childIDs so I can sort these chronologically. If I want to search rankings by name, how can I bypass the child ID to do so?
For instance, if a user searches for rankings using the term "Sports," how can I traverse my Rankings tree by searching for all rankings containing "Sports"?
This type of deep querying on dynamic paths is not possible with Firebase (nor with many other NoSQL databases). What you'll need to do is set up a so-called index, that maps the keys that you want to search for to the values that you want to find.
{
"Rankings" : {
"-KFGX5H3rLSnpPvupakm" : {
"Sports Teams" : {
"Red sox" : 1,
"Warriors" : 3,
"Yankees" : 2
}
},
"-KFGZkwAIl817CLDLmMp" : {
"Beers" : {
"Bud light" : 3,
"Coors" : 2,
"Pbr" : 4
}
}
},
"SearchTerms": {
"Red sox" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Warriors" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Yankees" : {
"-KFGX5H3rLSnpPvupakm": true
},
"Bud light" : {
"-KFGZkwAIl817CLDLmMp": true
},
"Coors" : {
"-KFGZkwAIl817CLDLmMp": true
},
"Pbr" : {
"-KFGZkwAIl817CLDLmMp": true
}
}
}
This process is called denormalizing your data and it's described in this blog post, in the Firebase documentation on structuring data and in this article on NoSQL data modeling. And in probably half a dozen similar answers I've given recently.
I was able to get the values of the child node-id's.
Here is my sample code:
LOCATION_URL.queryOrderedByChild("email").queryEqualToValue(FIRAuth.auth()?.currentUser?.email).observeEventType(.Value, withBlock: { snapShot in
let enumerator = snapShot.children
while let rest = enumerator.nextObject() {
var shot = rest.childSnapshotForPath(rest.key)
// child node ID
print(shot.key)
}
})
I hope this helps you..
Best regards,
Nazar Medeiros

Return data & reference from falcor router

I've got a route that returns details about a features on a user's account:
// games[{keys:games}].features[{integers:indices}]
{
$type : "atom",
value : {
id: "6",
count: "1",
...
}
}
There's also a route that returns generic details about specific features:
// features[{integers:features}]
{
$type : "atom",
value : {
name : "fooga",
max : 10,
...
}
}
I don't want to merge the generic feature data into the user-specific data because that will be a bunch of data duplication, but I also want to be able to get it all in a single request
What's a smart way to structure my routes/returned data so that games[{keys:games}].features[{integers:indices}] can return a useful reference to features[{integers:features}]?
I tried splitting them up like this:
// games[{keys:games}].features[{integers:indices}].details
{
$type : "atom",
value : {
id: "6",
count: "1",
...
}
}
// games[{keys:games}].features[{integers:indices}].meta
{
$type : "ref",
value : [
"features",
"15"
]
}
but I couldn't figure out a way to resolve the .meta reference w/o writing redundant-seeming paths like ...features.0.meta.[name,max,...]. Ideally the ref would just return an atom because it's a small amount of data.
I ended up structuring it like this:
games[{keys:games}].features[{integers:indices}].details
games[{keys:games}].features[{integers:indices}].feature
features[{keys:games}][{integers:features}].details
Ugly paths, but ¯\_(ツ)_/¯

Resources