swift Firebase stop signup process - firebase

I want to stop the signup process if the username exists. I don't want to create Email\Password (Authentication) and other info if the username exists
database rules:
{
"rules": {
"users": {
".read": "(auth != null)",
".indexOn": ["username"],
"$uid": {
"$username":{
".write": "(auth != null) && !data.exists() || newData.exists()"
}
}
}
}
}
I have added !data.exists() in .write , but still it duplicate usernames.
And then I added ".validate" to make username atleast 3 characters, to see if the signup process gonna fail if its longer, but it created email\password and other stuff but didn't wrote any data in database root\users\
After registered new user with email\password I got this error, Which means username couldn't be more than 3 characters. How to stop the signup process and show alert message at this situation?
[Firebase/Database][I-RDB03812] setValue: or removeValue: at /users/jt94ARqOoodtU3kYp3W1MtlUZ4m1 failed: permission_denied
Please help me if you could fix the problem.

Your simplified rules are:
{
"rules": {
".write": "(auth != null)",
"users": {
"$uid": {
"username": {
".write": "auth != null && (!data.exists() || !newData.exists())",
So you first grant any authenticated user write access on the root of the data and subsequently say that a user can only write if there is not data a the current location.
That won't work: once you grant permissions at a certain level, you cannot take that permission away on a lower level.
The Firebase documentation describes this as Read and Write rules cascade:
Child rules can only grant additional privileges to what parent nodes have already declared. They cannot revoke a read or write privilege.

Related

can't create new children in firebase database aftter setting the rules

I am using firebase database in my app. I have set the rules to allow normal users to create new childs in the node but I found that it's refused.
this is the writing rules of the node :
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && !data.exists()) || auth.token.email == data.child(\"userEmail\").val())",
I think that newData.exists() && !data.exists() should allow users to write in the database but this doesn't happened
this is the rules of the users node :
"users":{
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && data.child(\"userEmail\").val() != null) || auth.token.email == data.child(\"userEmail\").val())",
".read": "auth != null"
}
The database strucutre is like that :
-users
-user1
-userName, userEmail ....
-user2
-userName, userEmail .....
when a new user sign up in the app he should be allowed to push his data in the database
this is the database structre :
Ok, I think you're creating extra validation steps that aren't needed.
First
With ".read": "auth != null" on your users root, each user is able to access other user's data, so we should address the access for each user individually.
Second
If you just want to allow users that are authenticated to write and read its own contents, you can remove these extra ((newData.exists() && !data.exists()) and auth.token.email == data.child(\"userEmail\").val()) steps.
Tip: this ((newData.exists() && !data.exists()) comparison means exactly: Write here if you're sending anything but there should be nothing written in this requested "path". You should reflect on the need of this, as I don't know your exact use cases.
Also, I would guess the hardcoded UID you're requesting is of an Admin you've created - I wouldn't recommend this, please read more about user roles on this answer.
To clarify, I think your rules structure should be something like this:
{
"rules": {
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
".read": "auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}

Secure basic Firebase form for newsletter

I would like to create a newsletter subscription form. Meaning a user can register to my newsletter without creating an account.
I would like to do a simple insertion. But what is the best way to secure it ?
I have implemented "Anonymous Log In" (https://firebase.google.com/docs/auth/web/anonymous-auth)
I need basic rules, read to check is the user is allready registered and write to push user data into Realtime DB.
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
when the Anonymous Login is done, I push into the Realtime Database.
let dbConnection = firebase.database().ref('/newsletter_user');
dbConnection.push(datas).then(callback);
The problem is that Anonymous Auth do not check Auth Domain. (How to block localhost in firebase?)
Meaning a user can grab my ApiKey and perform insert or read data into my realbase database.
Then it do not seems really secure to me. What can I do to improve security ?
One thing you can do to improve your security is limiting your database access. Currently you have basic read/write rules for your database wich means that someone that is authenticated can do anything in your database. If I want I could write an entire encyclopedia in your datadump node :)
So the first thing you can do is limit read/write access to specific locations:
{
"rules": {
"newsletter_user" : {
".read": "auth != null",
".write": "auth != null"
}
}
}
Now I can only do something under the newsletter_user node.
Next you can use validation rules to make sure only the data you want can be written:
{
"rules": {
"newsletter_user" : {
".read": "auth != null",
".write": "auth != null",
// a valid newsletter_user must have attributes "color" and "size"
// allows deleting newsletter_user (since .validate is not applied to delete rules)
".validate": "newData.hasChildren(['color', 'size'])",
"size": {
// the value of "size" must be a number between 0 and 99
".validate": "newData.isNumber() &&
newData.val() >= 0 &&
newData.val() <= 99"
},
"color": {
// the value of "color" must exist as a key in our mythical
// /valid_colors/ index
".validate": "root.child('valid_colors/' + newData.val()).exists()"
}
}
}
}

Firebase database rules: users permission

I want to make different permission for different user roles.
For example, when the user is not super-owner, don't let him write in my items table.
This is what I tried to do:
{
"rules": {
"items": {
".write": "auth.authority == 'super-owner'"
}
}
}
But I notice that the authority field is stored in my users node I created on my own and is releated to the Firebase auth. How I can access users->authority of current logged in user through the rules?
Update: I did try this:
".read": "root.child('users/'+auth.uid).authority.exists()",
but I get Error saving rules - Line 10: No such method/property 'authority'.
You get this error because root.child('users/'+auth.uid) returns instance of DataSnapshot which does not have authority property of course. But it has hasChild method.
For full list of methods about DataSnapshot visit the following link.
https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot.
Try this.
".read": "root.child('users/'+auth.uid).hasChild('authority')",
".write": "root.child('users/'+auth.uid).hasChild('authority') && root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"
or this
".read": "root.child('users/'+auth.uid+'/authority').exists()",
".write": "root.child('users/'+auth.uid+'/authority').exists() && root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"
or the shortest version
".read": "root.child('users/'+auth.uid+'/authority').val() !== null",
".write": "root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"

Firebase Security rules for a nested data structure

I'm working on a Firebase rule configuration to control read/write access to my database. I had more rules written originally, but I've pared things down during troubleshooting. Here is my current rule configuration:
{
"rules": {
"developers": {
"$dev": {
".write": "!data.exists() && auth != null",
".read": "auth.devBucket === $dev",
"$proj": {
".read": "auth.devBucket === $proj",
"shared": {
".write": "!data.exists() || (auth.devBucket === $dev && auth.projBucket === $proj)"
}
}
}
}
}
}
What I'm trying to do is allow users of the Firebase to create a $dev node, $proj node, and shared node as long as they don't already exist and the user is authenticated. Then, I want to allow a user to have free write access within the shared node as long as their auth token's devBucket matches the $dev node they're writing within and their auth token's projBucket matches the $proj node they're writing within. I'm using the Firebase custom auth system for Android and I've loaded my tokens with these devBucket and projBucket variables. Authentication is definitely working according the my logcat, but I'm definitely getting permission denied errors with my current rules. I've been pouring over the Firebase Rule documentation and questions here for days and I am still puzzled as to the nuances of how their rule system works.
According to the documentation rules carry through to lower levels of nesting in the JSON, I'm just having trouble understanding how I can write a rules that allows a node and it's children to be created once, but also allows any number of children to be written or overwritten under shared if you're properly authenticated.
Does anyone have any idea how I could write rules to accomplish what I'm trying to do?
EDIT: I think it's also worth mentioning that I'm getting permission denied errors when I try to point listeners to my nodes too.
I figured out a configuration that worked for me.
{
"rules": {
"developers": {
".write": "!data.exists() || auth != null",
".read": "auth != null",
"$dev": {
".write": "!data.exists() || (auth != null && auth.devBucket == $dev)",
".read": "auth != null && auth.devBucket == $dev",
"$proj": {
".write": "!data.exists() || (auth != null && auth.projBucket == $proj)",
".read": "auth != null && auth.projBucket == $proj"
}
}
}
}
}

FIREBASE WARNING: set at /users/simplelogin:32 failed: permission_denied

Before in my app I was creating accounts successfully until I put some rules
{
"rules": {
"users": {
"$uid": {
// grants write access to the owner of this user
// account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in
// with an email and password
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
then, the accounts are created because I see those accounts in the dashboard. But once I try to create, I am getting this kind of errors
FIREBASE WARNING: set at /users/simplelogin:32 failed: permission_denied
Since you want the user to be able to create their own node initially, you'll need to explicitly allow the case where the location is new.
Based on the documentation on the auth parameter:
".write": "!data.exists() || auth.uid === $uid""
Note: I'm not entirely sure this will work, but felt it'd be more readable as in answer-format than as a "try this" comment.

Resources