Firebase checking two different database refs despite a if check - javascript

I am trying to seperate two different logins for the different types of users that are in the account. One of the users is a regular consumer who is able to search through the app. The other is a business dashboard where businesses get to see what users are checkedin to their business.
The problem is that when I check my two different database references, it seems it checks both of them instead of validating the first check and proceeds to pull and error saying one of my nodes is null.
The case it apprently fails is the first if check but in my database the node userType is set properly:
The problem seems to be it auth().onStateChanged where it looks for the uid of in both database references. When I try to login with a business account it successfully enters that statement and redirects, when I log in with a consumer account it tries to check the business refs if and then pulls out the error userType is null cannot read
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// This prompts the user to allow for location access
// When logged in it would allow us to show the
// nearby businesses to the user
var uid = user.uid
if(window.navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(function(position){
})
}
var uid = user.uid
console.log(uid)
business.child(uid).on("value", snap => {
if(snap.val().userType == "business") {
alert("This is not a consumer account!")
firebase.auth().signOut()
window.location.href = "businesslogin.html"
} else {
consumer.child(uid).on("value", snap => {
if(snap.val().userType == "consumer") {
if(snap.val().isPhoneVerified == true) {
window.location.href = 'nearbyBusinesses.html'
} else {
window.location.href = 'loginVerification.html'
}
if(snap.val().isUserCheckedin == true){
window.location.href = "leave.html" + '#' + snap.val().checkedInBusinessId
} else {
window.location.href = "nearbyBusinesses.html"
}
}
})
}
})
}
})

The bug is in this line if(snap.val() == "business"). It needs to be if(snap.val().userType == "business"). Atleast that is what i can see imediately. Try that and see if it solves your problem

Related

How to make separate login for Users and Freelancer based on Roles that is in my real time database Firebase

Hello I am working a web application with Firebase Realtime Database and Authentication with nodejs or javascript.
This is my real time database and I want to make a login form which if the User = User he will go to User Index and if the User = Freelancer he will go to Freelancer Index.
And this is the line of code that I was tweaking or trying but It doesn't go in my way.
<script>
firebase.auth().onAuthStateChanged(function(user)
{
if(user)
{
var userID = firebase.auth().currentUser.uid;
firebase.database().ref('Users/' + userID).once('value').then(function(snapshot)
{
if (snapshot.val())
{
window.location.href = "index.html";
}
else
{
window.location.href = "okay.html";
}
});
}
});
</script>
Hoping I can get feedbacks or answers here. I am almost trying it for 2days already that's why I seek help here.
Comments and answers are highly appreciated thank you!
With your current data structure you will need to check in two places to determine what role a user has. While this technically possible, it is less efficient and more complex in code.
I recommend instead to store a single top-level node (say UserRoles) where you simply keep the role for each UID:
"UserRoles": {
"uidOfUser1": "Freelancer",
"uidOfUser2": "User"
}
With that in place, you can load it in your onAuthStateChanged callback with:
const ref = firebase.database.ref("UserRoles");
ref.child(user.uid).once("value").then((snapshot) => {
if (snapshot.val() === "Freelancer") {
window.location.href = "okay.html";
}
else if (snapshot.val() === "User") {
window.location.href = "index.html";
}
else {
alert("Can't determine role for user: "+user.uid)
}
});

Checking for login credentials in HTML5 Storage

i'm building a quizz app , which asks me to : Add user authentication: allow users to log in, and save their login credentials to local storage (HTML5 browser storage). what i want to add is to check if the user name && password (together, because you can have the same username and not the same password and vice versa), so i can prompt a "Welcome back (name of the user)".
i spent 3 days trying to figure out which logic works , tried everything but every time i get a logic problem where things doesn't go the way it should be , here's the code :
var usersinfo = {
users : []
}
localStorage.setItem("users", JSON.stringify(usersinfo.users))
function registerInfo(){
var name = document.forms[0].username.value;
var pw = document.forms[0].pw.value;
if (name === "" || pw === "") {
alert ('please complete all the forms')
} else {
var adding = JSON.parse(localStorage.getItem("users"));
// logic that goes here : i tried everything , looping...etc
}
return false;
}
Note that the function is attached to a button , and everything works fine on the HTML , the problem is in login logic .
Untested, but try something like this:
const users = JSON.parse(localStorage.getItem("users"));
if (users.some((user) => {
return user.name === document.forms[0].username.value;
})) {
alert('Welcome back!');
}
Basically, we use some on the array to loop through and figure out if any of the elements have the same name as the one from your form. If they do, we immediately stop looping and return true. If not, we return false.
See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
And, do take #AnilRedshift's advice and don't store usernames/passwords in localstorage...

firebase authentication custom attribute failure

I have been putting together a website and i've been using the latest firebase script and everything.
When I request for a custom user attribute that has been created it says it's 'undefined'.
CustomAttributes:
points
ownedavatars
Code:
SignUp
var user = firebase.auth().currentUser;
user.updateProfile({
displayName: //username,
photoURL: //icon,
points: 0,
ownedavatars: "default"
}).then(function() {
user.sendEmailVerification().then(function() {
//it would save email and password and then redirect here
}).catch(function(error) {
console.log(error.message);
});
}).catch(function(error) {
console.log(error.message);
});
Login
var listofavatars;
firebase.auth().signInWithEmailAndPassword(email, password).then(function() {
var user = firebase.auth().currentUser;
if (user != null) {
document.getElementById("user").innerHTML = user.displayName;
if (user.points == undefined) {
document.getElementById("points").innerHTML = "0p";
} else {
document.getElementById("points").innerHTML = user.points + "p";
}
listofavatars = user.ownedavatars;
if (user.photoURL == "default") {
document.getElementById("avatar").src = //would pull default;
} else {
document.getElementById("avatar").src = //would pull any other icon saved;
}
}
}).catch(function(error) {
alert(error.message + " Code:" + error.code);
});
You can't use updateProfile to save arbitrary custom user variables. This API only currently supports photoURL and displayName`. To save other user data, you have to use a separate database to do so. You can use Firebase realtime database or Firestore to do so. Here is an example how to save user specific data securely: https://firebase.google.com/docs/database/security/user-security
If you need to save user specific data for role based access control, you can use the Firebase Admin SDK to set custom user attributes:
https://firebase.google.com/docs/auth/admin/custom-claims
However, it is highly recommended that this custom user data is to be used for access control. For other data, use a dedicated database as described above.

How to require the user's password when you want to update the user's information in the Firebase JSON tree?

I've got a form which is used to update a user's information, both in the Firebase JSON tree and the seperate database which holds the email + password combination for the users. Whenever you want to update either the email or password, you need to provide an email + password combination for it to work.
However, when you only want to update the JSON tree you can do it without a password. My form requires you to enter your current password before anything can happen, but if you type in the wrong password it will still update the display name of the user.
So my question is, is there a way that I can require the correct password before actually updating anything in the database?
The code in my controller:
//If the user has entered a new display name
if (sharedInfo.getUser().displayName !== $scope.user.displayName) {
var isNameChanged = userLogic.changeDisplayName($scope.user);
isNameChanged.then(function(isSuccessful) {
if (isSuccessful === true) {
$scope.isSuccessful = true;
}
else {
$scope.error = 'Update failed';
}
});
}
Function in my service:
changeDisplayName: function(user) {
//Get the user ID
var userData = sharedInfo.getAuthState();
return fbRef.getSyncedReference('users/' + userData.uid).$update({displayName: user.displayName}).then(function() {
return true;
}, function(error) {
return false;
});
}

Meteor - How to use use server side validation on password

I'm performing server-side validation in the "Accounts.onCreateUser" function so that I can pass the options object as well. I wasn't able to figure out how to do this with the validate user function.
First, I'm totally open for correct if I'm going the wrong direction so please advise.
I can't figure out how to validate password length server-side. Is it because it's already converted prior to the creation? When testing, if I enter in a single character for password it doesn't throw an error.
Accounts.onCreateUser(function (options, user) {
if (options.profile) {
user.profile = options.profile;
user.profile.user_status = "new user";
}
// Error checking
var errors = "";
if (user.username.length === 0) {
errors = errors + '<li>Email is required</li>';
}
if (user.username.length !== 0 && user.username.length < 4) {
errors = errors + '<li>Email too short</li>';
}
if (user.profile.firstname.length === 0) {
errors = errors + '<li>First name is required</li>';
}
if (user.profile.firstname.length !== 0 && user.profile.firstname.length < 2) {
errors = errors + '<li>First name is too short</li>';
}
if (user.profile.lastname.length === 0) {
errors = errors + '<li>Last name is required</li>';
}
if (user.profile.lastname.length !== 0 && user.profile.lastname.length < 2) {
errors = errors + '<li>Last name is too short</li>';
}
if (user.services.password.length === 0) {
errors = errors + '<li>Please enter a password</li>';
}
if (user.services.password.length < 7) {
errors = errors + '<li>Password requires 7 or more characters</li>';
}
if (errors) {
throw new Meteor.Error(403, errors);
} else {
return user;
}
});
I'm not using Accounts-ui. Trying to roll out my own... Being completely new with Meteor it has been a bit of a battle trying to understand account creation and verification. If there's a way to do this with ValidateNewUser function should I be using that instead?
Thank you for all your help.
I've figured out the best manner to perform this. Hope this will help others.
I'm using a method on server side to validate and returning error if there is one. Then proceeding with the Account Creation.
Meteor.call('Validate_Registration', email, password, cpassword, firstname, lastname, terms, function(error) {
if (error) {
error = error.reason;
$('#Error-Block').fadeIn().children('ul').html(error);
console.log(error);
} else {
Accounts.createUser({
username: email,
email: email,
password: password,
profile: {
firstname: firstname,
lastname: lastname
}
}, function(error) {
if (error) {
error = error.reason;
$('#Error-Block').fadeIn().children('ul').html(error);
} else {
var uid = Accounts.connection.userId();
Meteor.call('Verify_Email', uid, email);
Router.go('/email-instructions');
}
});
}
});
The only thing I'm unsure of at this point is if it's correct to use:
var uid = Accounts.connection.userId();
This seems to be local to the current user only, and is stored in local storage to the user.
Accounts-password uses SRP, which is a bit complicated so I won't describe it fully here. The actual check of the hashed tokens happens around here Basically, the password does not arrive at the server as a plain text string therefore you will not be able to enforce password policy on the server, while using SRP.
Also notably around here there is a DDP only "plaintext" login option for those who (understandably) don't want to implement SRP on their own. As advertised, it should only be used if the user is connected w/ SSL. I would probably start there.
In the meantime, you can at least do some client side enforcing until you can roll your server-side login handler.
You may also want to check out this meteorhacks article for a custom login handler tutorial.
According to the documentation, the password "is not sent in plain text over the wire", so the password string you're looking at on the server side is not the same as what the user typed in.
EDIT: At least, that's what I think.
EDIT2: Found a comment in another question that confirms it.

Categories