Guard let not distinguishing inputs - swift

I have a SIMPLE login screen and I am protecting against missing data as follows:
#IBAction func btnLoginTapped(_ sender: Any)
{
guard let email = emailTextField.text, !email.isEmpty else
{
self.showMessage(messageToDisplay: "Email Address is required", title: "")
return
}
guard let password = passwordTextField.text, !password.isEmpty else
{
self.showMessage(messageToDisplay: "Password is required", title: "")
return
}
....
I load the app on my device and press login and get the alert "Email Address is required". I enter my email address and press login and get the alert "Email Address is required" and NOT "Password is required"
How can that be???

If there's a problem with the first guard let, we print "Email Address is required" and return.
Thus, the second guard let is never encountered and "Password is required" is never printed.
Your code will never print both messages; that would be impossible, the way you've written the code.
So we have to conclude that one of the tests in the first guard let is failing. But you have not given enough information for us to know why that is. Perhaps emailTextField is nil? Perhaps showMessage doesn't do what you think it does? You could be making a lot of wrong assumptions here. But the logic of your code is clear.

Related

Firebase username uniqueness in Swift

I am trying to check username uniqueness while registering user. I know there are tons of questions about it and I went through all of them however my problem is that it doesn't do anything, it doesn't print that the username exists and it even doesn't register with the username.
What I am doing wrong? I can't seem to find answer, the only thing that could be wrong is the if nesting.
This is the struct:
AppName:
users
1v2mRJTvrBQ7dMQohUU3rnn7ypI3: //UID
username: John
And that is the code:
func registerUser(){
guard let username = usernameField.text, let email = emailField.text, let password = passwordField.text else{
print("Successfully registered")
return
}
if connectedToNetwork() == true{
if passwordField.text == confirmPasswordField.text{
let usersRef = FIRDatabase.database().reference().child("users")
usersRef.queryOrdered(byChild: "username").queryEqual(toValue: "\(username)")
.observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in
if snapshot.value is NSNull{
AuthProvider.Instance.register(withEmail: email, password: password, username: username, loginHandler: { (errMessage) in
if errMessage != nil{
}else{
let user = FIRAuth.auth()?.currentUser
guard let uid = user?.uid else{
return
}
user?.sendEmailVerification() { error in
if let error = error {
print(error.localizedDescription)
} else {
print("Email has been sent to you!")
}
}
//User logged in and redirect
}
})
}else{
print("Username already exists")// It doesn't execute this
}
})
}else{
Util.errorAlert(message: "Passwords do not match!")
}
}else{
Util.errorAlert(message: "The internet connection appears to be offline.")
}
}
I even tried different security rules but those shouldn't make any difference but those that I used:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"Snuses": {
".indexOn": "Brand",
"$username": {
".validate": "!root.child(users').hasChild($username)"
}
}
}
}
What is the thing I am doing wrong?
Your problem is in your security rules. You're doing a query before the user has been authenticated. This query will fail because your rules state that the user has to be authenticated in order to query the database (auth != null).
What you need to do is create another child called "usernames". Make this readable by anyone without authentication. Check if the username is taken and if not, claim it for the new user. Then, do your auth call and create your user in the "users" child.
Knowing nothing about Firebase, your way of "knowing that it's doing something" appears to be alerting or printing. So if it's not doing that, i see at least two execution paths which don't end in alerting or printing.
if errMessage != nil{
guard let uid = user?.uid else{
Also this could be missing else but i can't find it with the level of effort adequate to answering a S.O. question:
if snapshot.value is NSNull{
Purely theoretically, your Util.errorAlert may be broken too.
Firebase won't allow duplicate user (names) so just look for an error when you try to create the user.
FIRAuth.auth()?.createUser(withEmail: email, password: password) { (user, error) in
// ...
}
There are 4 errors that could be returned:
FIRAuthErrorCodeInvalidEmail
Indicates the email address is malformed.
FIRAuthErrorCodeEmailAlreadyInUse (this is the one to address you question)
Indicates the email used to attempt sign up already exists. Call
fetchProvidersForEmail to check which sign-in mechanisms such
user used, and prompt the user to sign in with one of those.
FIRAuthErrorCodeOperationNotAllowed
Indicates that email and password accounts are not enabled. Enable them in the
Authentication section of the Firebase console.
FIRAuthErrorCodeWeakPassword
Indicates an attempt to set a password that is considered too weak. The
NSLocalizedFailureReasonErrorKey field in the NSError.userInfo
dictionary object will contain more detailed explanation that can
be shown to the user.

how to deny login access for incorrect login in iOS swift

I want to deny access for either an incorrect userEmail or userPassword but am not sure how to add in both details. and my code to deny login for an incorrect email is not having any effect, or returning any errors. It just lets everyone log in. How can I correct this code?
func displayMyAlertMessage(userMessage:String)
{
var myAlert = UIAlertController(title:"Alert", message:userMessage, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.Default, handler:nil);
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated:true, completion:nil);
}
#IBAction func loginButtonTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userEmailStored = NSUserDefaults.standardUserDefaults().stringForKey("userEmail");
let userPasswordStored = NSUserDefaults.standardUserDefaults().stringForKey("userPassword");
if(userEmailStored == userEmail)
{
if(userPasswordStored == userPassword)
{
// Login is successfull
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
self.dismissViewControllerAnimated(true, completion:nil);
}
//Check if passwords match
else if(userPasswordStored != userPassword)
{
// Display an alert message
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
displayMyAlertMessage("Passwords do not match");
return;
}
}
The problem is that you're first checking whether the email is correct, and then if it is you're checking the password inside that block. You haven't provided any code to run if the email is incorrect.
Instead of structuring it like this:
if userEmailStored == userEmail {
if userPasswordStored == userPassword {
// Login successful
} else {
// Login unsuccessful
}
}
Try structuring it like this:
if userEmailStored == userEmail && userPasswordStored == userPassword {
// Login successful
} else if userEmailStored != userEmail {
// Login unsuccessful (email incorrect)
} else /* if userPasswordStored != userPassword */ {
// Login unsuccessful (password incorrect)
}
Note: on line 5, I've commented out the condition if userPasswordStored != userPassword because it's not actually required.
However, you may notice that when you log into most websites, if you get your details wrong, they don't specify whether it was your username or email that was incorrect.
For example:
They do it that way because it's more secure. So you may want to consider simply doing it like this:
if userEmailStored == userEmail && userPasswordStored == userPassword {
// Login successful
} else {
// Login unsuccessful
}
Important note:
Remember that NSUserDefaults isn't in any way encrypted, so if you're ever planning on storing a username and a password in there... don't. It's stored as XML (I believe), so anyone can simply go and look at it with minimal effort. Use Keychain instead!
A less important note: There's one place where you have two whole lines of whitespace between your else if and its bracket, and some other messy things in the rest of your code. You'll probably get more people answering your questions, as well as making it a lot easier for you and other people to understand your code, if you put in some effort to make it more readable. Two lines of whitespace before an opening bracket is an eyesore, and lots of that can make code really difficult to understand.

Updating PFUser.currentUser

For my app the user can change their current username. So using parse and I set the new username for the current user shown in my code below. I then call saveInBackgroundWithBlock to save the new username. However I get this error "Username already taken." But now PFUser.currentUser.username is set to the invalid new username even though the save failed. I called fetch and that didn't change anything. How can I update the PFUser.currentUser?
let user = PFUser.currentUser()
user.username = newUsernameText
user.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
self.helper.successAlert("Saved!", msg: "Your profile has been updated.")
} else {
// There was a problem, check error.description
self.helper.errorAlert("Error", msg: (error?.localizedDescription)!)
PFUser.currentUser().fetch()
self.user = PFUser.currentUser()
print(user.username) //prints the new username that was invalid
}
}
Try with changing the username to something totally else. There's a chance you already have the username in your database. Another way of going about this would be to query all existing users first and then to check if the username if taken or not with an if-else statement. If it's not update it, if it is throw an alert. Cheers

Correct output when .isEmpty != nil but no output in the else statement

This function does print out "Enter a number!" when nothing is entered into the textField but if I DO put something in the textField it still prints out "Enter a number!" I obviously want it to print out "Oh, you're (newAge)" when a number is entered in. What am I missing?
Swift 2.0
#IBAction func SubmitAgeButton(sender: AnyObject) {
let newAge = String(textField.text!)
if ((textField.text?.isEmpty) != nil) {
label.text = "Enter a number!"
}
else {
label.text = "Oh, you're \(newAge)" // This isn't printing out.
return()
}
}
with your code you check if the text is there and returns something at all. Which both "" as well as a non empty string do. namely a Bool.
so if let text = textField.text where !text.isEmpty)

Swift Firebase Login Registration auth

So when I first the page up I've kept it simple 2 text fields (email & password) 1 lbl 2 buttons (login register). Initially when I started out testing it everything worked when there was a problem an alert would pop up and tell you the problem, or you would be segue to next page based on button press and auth being complete.
But now every time I open the app to run code deeper inside no matter what I type I can sign in with the wrong password, or sign in with a previous email address even though previously these would both present errors. I have rebuilt this page numerous times over the week and decided to also add a get photo function from the users profile page.
Whenever I run the app and press a button I get this in the console:
Warning: Attempt to present on whose view is not in the window hierarchy!
I figure this is the problem because there is an error with the registration but the user is allowed to continue regardless. I've looked it up googled it read all the documentation I can find and even messed about trying and failing to put in a task structure.
PS I moved away from error label to use alerts hoping they would force a stop in the code
#IBAction func registerBtn(_ sender: Any) {
if emailTextField.text! == "" || passwordTextField.text == "" {
displayAlert(title: "Error", message: "Please Enter Your EMail Address & Choose A Password")
} else {
if let email = emailTextField.text {
if let password = passwordTextField.text {
//Create User
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
// Auth.auth().createUserAndRetrieveData(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
self.displayAlert(title: "Error", message: error!.localizedDescription)
} else {
print("Registration Successful")
self.performSegue(withIdentifier: "registrationSegue", sender: nil)
}
self.login()
})
}
}
}
}
if error != nil {
// show your alert
}
You don’t need an else statement on authenticating your users. so delete that line
Also, if you’re presenting a view controller that’s supposed to be accessible by authenticated users.
Please try:
let HomePage = HomePageController() // Change this to your viewcontroller name
self.present(HomePage, animated: true, completion: nil)
swift 4 - Xcode 9.1
func signUP(){
Auth.auth().createUser(withEmail: emailIdTextField.text!, password: passworTextField.text!) { (user, error) in
print(user?.email)
}
}
func signIn(){
Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
print(user?.uid)
}
}

Resources