Password reset not checking for existing users - swift

In my password reset function the user can put in whatever he/she wants. It does not even needs to be a email address.
I would like to check for a valid email address, and that the email is registered in Parse Server
#IBAction func forgotPasswordButtonTapped(_ sender: Any) {
let forgotPasswordAlert = UIAlertController(title: "Forgot password?", message: "Please enter your email address", preferredStyle: .alert)
forgotPasswordAlert.view.tintColor = UIColor.red
forgotPasswordAlert.addTextField { (textField) in
textField.placeholder = "Email address"
}
forgotPasswordAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
forgotPasswordAlert.addAction(UIAlertAction(title: "Reset password", style: .default, handler: { (action) in
let resetEmail = forgotPasswordAlert.textFields?.first?.text
PFUser.requestPasswordResetForEmail(inBackground: resetEmail!, block: { (success, error) in
if error != nil {
let resetFailedAlert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
resetFailedAlert.view.tintColor = UIColor.red
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
} else {
let resetEmailSentAlert = UIAlertController(title: "Password reset instructions sendt", message: "Please check your email", preferredStyle: .alert)
resetEmailSentAlert.view.tintColor = UIColor.red
resetEmailSentAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailSentAlert, animated: true, completion: nil)
}
})
}))
//PRESENT ALERT
self.present(forgotPasswordAlert, animated: true, completion: nil)
}

In your action you can check for email validity:-
forgotPasswordAlert.addAction(UIAlertAction(title: "Reset password", style: .default, handler: { (action) in
let resetEmail = forgotPasswordAlert.textFields?.first?.text
if self.isValidEmail(testStr: resetEmail) {
// Check of email registered on server should be done via this API and API should return error based on that.
PFUser.requestPasswordResetForEmail(inBackground: resetEmail!, block: { (success, error) in
if error != nil {
let resetFailedAlert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
resetFailedAlert.view.tintColor = UIColor.red
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
} else {
let resetEmailSentAlert = UIAlertController(title: "Password reset instructions sendt", message: "Please check your email", preferredStyle: .alert)
resetEmailSentAlert.view.tintColor = UIColor.red
resetEmailSentAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailSentAlert, animated: true, completion: nil)
}
})
} else {
//Show error that email entered is not correct format
// present the reset email alertbox again.
}
}))
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: testStr)
}

There is a parse email adapter to verify emails.
Verifying user email addresses and enabling password reset via email requires an email adapter. As part of the parse-server package we provide an adapter for sending email through Mailgun. To use it, sign up for Mailgun, and add this to your initialization code:
https://github.com/parse-community/parse-server

In regard to Parse Server not notifying the client that a user with the provided email address does not exist:
Pre 3.1.0 of Parse Server the request to reset a password returned an error if the email address was not found however this is a security risk as it allows an attacker to obtain user data for use in a brute force attack - see this explanation.
You can also take a look at the changelog and the PR that implemented this change.
It would still be possible to implement this yourself by querying the User class before making the password reset request. However, this should not be done in client code as it would require user data to be publicly accessible which is a major breach of privacy. It could also be implemented in cloud code using the master key so that user data could remain inaccessible to the public but this would present the same security risk mentioned above.

Related

Display an alert within an alert

I am trying to display an alert that takes user input and then pops up the text that has been given
#IBAction func forgotPassword(_ sender: Any) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Email Recovery", message: "Enter your email to recover your account", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.text = ""
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("An email has been sent to \(String(describing: textField?.text)) for account recovery")
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
}
The input works fine as well the output although instead of giving another alert, it just prints what I need in the console.
Am I missing something?
I guess you misunderstood a bit: "print" is just printing on your console, if you want to open a new alert after touching on the "ok" button, you may want to complete your code with:
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert, weak self] (_) in
let message = "An email has been sent to \(alert?.textFields?.first?.text ?? "") for account recovery"
let innerAlert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
innerAlert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self?.present(innerAlert, animated: true, completion: nil)
}))

Alert view with taking input password

In the following code, it is successfully implemented. Just need one modification. When the app initially opens the admin password should take a default password "Hello" and then when the user has access to the admin password, will edited and save it and then it will be in the key "admin password"
How can I make that default password possible on the first?
func enableSectionAlert() {
let alertController = UIAlertController(title: "Admin Password", message: "Please input admin password", preferredStyle: .alert)
let enable = UIAlertAction(title: "Enable", style: .default) { (_) in
let field = alertController.textFields?[0].text
if let x = UserDefaults.standard.string(forKey: "admin password"), x == field {
self.demosSelectionEnabled()
self.showSection.isUserInteractionEnabled = false
self.showSection.textLabel?.textColor = UIColor.lightGray
}
else{
let wrongPwd = UIAlertController(title: "Wrong Admin Password", message: nil, preferredStyle:UIAlertControllerStyle.alert)
wrongPwd.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(wrongPwd, animated: true, completion: nil)
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "Admin Password"
textField.isSecureTextEntry = true
}
alertController.addAction(enable)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
}
You can initialize a textfield with initial text this way
alertController.addTextField { (textField) in
textField.text = "Hello"
textField.isSecureTextEntry = true
}
I believe you want the default password to be "Hello", and have the option to change this later, and persist in userDefaults.
If this is the case, why not initially set the default value as follows:
UserDefaults.standard.set("Hello", forKey: "admin password")
Set it just once in maybe AppDelegate, using the following method:
private func setDefaultPassword() {
if UserDefaults.standard.string(forKey: "admin password") == nil {
UserDefaults.standard.set("Hello", forKey: "admin password")
}
}
If I understand you correctly you want that the password "Hello" allows the user to login after they installed the app. Once they are logged in they can change the password, right?
Do archive this check in the applicationDidLaunch method of your AppDelegate if a value for the key admin password is set. UserDefaults.standard.string returns nil if there is no value set for this key. If you get nil from this call just set the string to Hello.
This allows the user to login with Hello until the password save in the user defaults is changed.

Swift Beginner help : Editor placeholder in source file

I am a beginner at Swift. I am trying to implement a sign in and signup page for a new app I am creating. I have looked at other questions asked that are similar to mine but couldn't resolve so I am asking for your help.
I must admit I am following an outdated tutorial which may not be compatible with the current Xcode.
#IBAction func signup(_ sender: Any) {
if username.text == "" || password.text == "" {
var alert = UIAlertController(title: "Error in form", message: "Please enter a username and password", preferredStyle: <#T##UIAlertControllerStyle#>.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
}
Error messages I am receiving
1) Static member 'Alert' cannot be used on instance of type 'UIAlertControllerStyle'
2) Editor placeholder in source file
Can anyone offer any guidance? I can preview the page and it looks good but the build fails.
Thanks in advance.
The errors are on this line:
var alert = UIAlertController(title: "Error in form", message: "Please enter a username and password", preferredStyle: <#T##UIAlertControllerStyle#>.Alert)
Note the placeholder text after preferredStyle:. Remove that and put the proper value:
var alert = UIAlertController(title: "Error in form", message: "Please enter a username and password", preferredStyle: .Alert)
Unrelated to your issue, do not call self.dismiss... in the alert action. The alert will be dismissed automatically when the user taps on any button.

Password Recovery/ Reset

I'm having trouble understanding Firebase's documentation. In my Login ViewController, I have a button that allows users to reset password. So when user presses the button, it opens an alert controller where user would have to input their email to be sent a password reset/ recovery.
#IBAction func forgottenPassword(sender: AnyObject) {
var loginTextField: UITextField?
let alertController = UIAlertController(title: "Password Recovery", message: "Please enter your email address", preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
if loginTextField?.text != "" {
DataService.dataService.BASE_REF.resetPasswordForUser(loginTextField?.text, withCompletionBlock: { (error) in
if (error == nil) {
self.showErrorAlert("Password reset", msg: "Check your inbox to reset your password")
} else {
print(error)
self.showErrorAlert("Unidentified email address", msg: "Please re-enter the email you registered with")
}
})
}
print("textfield is empty")
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in
}
alertController.addAction(ok)
alertController.addAction(cancel)
alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in
// Enter the textfiled customization code here.
loginTextField = textField
loginTextField?.placeholder = "Enter your login ID"
}
presentViewController(alertController, animated: true, completion: nil)
}
func showErrorAlert(title: String, msg: String) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
presentViewController(alert, animated: true, completion: nil)
}
Does the Firebase Backend server automatically generate the code to send the user a reset to their email?
Would i have to provide further code? Such as sendPasswordResetForEmail()? ... Or does the Firebase Backend service handles it from here? ...
Is that the function you are looking for ?
resetPasswordForUser(email:withCompletionBlock:)
Just call it on your Firebase instance.
Then go to your app dashboard to customize email that will be send to user upon password changes.

How to restore in-App purchases with Parse?

I would like to create a "Restore in-App" button because it is required by Apple. I am using Parse for my iAP product and I used this code to do that:
PFPurchase.buyProduct("iapbanner", block: { (error:NSError!) -> Void in
if error != nil {
let alert = UIAlertController(title: "Errore", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
self.opzioniTableView.reloadData()
}
})
This works fine. Though, in the Parse's documentation it's not mentioned how to restore your iAp so I'm asking you.
Use PFPurchase.restore() to restore purchases with Parse. I'm not sure why they don't have this in their docs.