Skip to content

Instantly share code, notes, and snippets.

@calendee
Last active August 29, 2015 14:10
Show Gist options
  • Save calendee/2125fa951bc004159c34 to your computer and use it in GitHub Desktop.
Save calendee/2125fa951bc004159c34 to your computer and use it in GitHub Desktop.
Firebase : Unique Mobiles with Security Restrictions
{
"rules": {
".read": false,
".write": false,
"users" : {
"$userId" : {
".write" : "$userId === auth.uid && !data.exists() && newData.exists() && auth.uid !== 'anonymous'",
// Can only read if the node is the same as the uid
".read" : "$userId === auth.uid",
// Only allow these properties
".validate": "newData.hasChildren(['mobile'])",
// no other properties can be included in this sample profile - real world would have others
"$other": { ".validate": false },
"mobile" : {
// Ensure the mobile number was the last one checked
".validate": "root.child('checkMobileInUseStep2').child(auth.uid).child('mobile').val() === newData.val()"
}
}
},
"checkMobileInUseStep1" : {
// Allows user to check mobile number up to 3 times.
// If they are allowed to add the mobile number here, then they are allowed to try to write to mobileInUseChecksStep2
// Used in conjunction with checkMobileInUseStep2 to allow user to check if mobile number is not already registered
"$userId": {
// Only authenticated users can write here. Can't be anonymous users
".write": "$userId === auth.uid && newData.exists() && auth.uid !== 'anonymous'",
// No one is allowed to read this table
".read" : false,
// Counts the number of times user has written here.
"attemptsCounter" : {
// attemptsCounter can only be incremented by 1 each time
".validate": "newData.isNumber() && newData.val() > 0 && newData.val() <= 3 && ((!data.exists() && newData.val() === 1) || (newData.val() === data.val() + 1))"
},
// Collection of each individual attempt to check if a mobile number is in use.
"attempts" : {
"$attemptId" : {
// The attemptId must match the attemptsCounter counter above
// The attempt must have a valid 'mobile' entry
// The record cannot already exist. This prevents the user from just changing the mobile number over and over.
".validate": "newData.hasChildren(['mobile']) && !data.exists() && root.child('checkMobileInUseStep1').child($userId).child('/attemptsCounter').exists() && root.child('checkMobileInUseStep1').child($userId).child('/attemptsCounter').val() + '' == $attemptId",
"$other": { ".validate": false },
"mobile" : {
".validate": "newData.isString() && newData.val().length > 1 && newData.val().length < 25"
}
}
}
}
},
// Used in conjunction with checkMobileInUseStep1
"checkMobileInUseStep2" : {
"$userId": {
// Again, only authenticated users can write here
".write": "$userId === auth.uid && newData.exists() && auth.uid !== 'anonymous'",
// No one can read this table
".read" : false,
// Make sre the entry has only a mobile record and nothing else
".validate": "newData.hasChildren(['mobile'])",
"$other": { ".validate": false },
// The mobile number must NOT exist in the 'registedMobiles' table.
// The mobile number must exist in one of the attempts recorded in the 'checkMobileInUseStep1' table.
"mobile" : {
".validate": "!root.child('registeredNumbers').child(newData.val()).exists() && ( root.child('checkMobileInUseStep1').child($userId).child('attempts').child('1').child('mobile').val() === newData.val() || root.child('checkMobileInUseStep1').child($userId).child('attempts').child('2').child('mobile').val() === newData.val() || root.child('checkMobileInUseStep1').child($userId).child('attempts').child('3').child('mobile').val() === newData.val() )"
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment