Cannot connect to MYSQL database using swift - swift

this is my swift code:
import UIKit
class SignUpViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var pwdField: UITextField!
#IBOutlet weak var pwdAgain: UITextField!
#IBAction func SignUpTapped(_ sender: UIButton) {
if pwdField.text == pwdAgain.text {
var request = URLRequest(url: NSURL(string: "sftp://....compute.amazonaws.com/var/www/html/register.php") as! URL) //... is hide my user name
request.httpMethod = "POST"
let postString = "email=\(emailField.text!)&name=\(nameField.text)&password=\(pwdField.text)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil{
print("response = \(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
}
task.resume()
}else if pwdAgain.text == "" || pwdField.text == "" || emailField.text == "" || nameField.text == ""{
let alert = UIAlertController(title: "Notification", message: "Please fill all block!", preferredStyle: UIAlertControllerStyle.alert)
self.present(alert, animated: true, completion: nil)
}else{
let alert = UIAlertController(title: "Notification", message: "Please enter same password twice!", preferredStyle: UIAlertControllerStyle.alert)
self.present(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
and my php code:register.php
<?php
include 'dbConnect.php';
$email = $_POST['email'];
$name = $_POST['name'];
$pwd = $_POST['password'];
$id = date('mdHis');
$checkEmail = false;
$checkName = false;
$dbInsert = false;
if ($conn->query("SELECT * FROM fyp.blogger WHERE email='$email'")- >num_rows == 0) {
$checkEmail = true;
}
if ($conn->query("SELECT * FROM fyp.blogger WHERE name='$name'")->num_rows == 0) {
$checkName = true;
}
if ($checkName && $checkEmail) {
$dbInsert = $conn->query("INSERT INTO fyp.blogger (blogger_id,email,name,pwd) VALUES ($id, '$email','$name', '$pwd')");
}
$conn->close();
?>
the problem is i trying test the connection, like something blocking me.
Error below:
Is any about my using sftp? i just wanna save some data to MYSQL database
and read data.
i hope anyone can solve problem.

Related

AlertController view is not in the window hierarchy

i am a beginner in swift, i was trying to use an UIAlertController but i have got an error and the UiAlertController do not show up and i can see an error in the console that says
2021-06-20 18:16:28.494162+0200 Bicycall[50670:543648] [Presentation] Attempt to present <UIAlertController: 0x7fbaca034e00> on <Bicycall.login: 0x7fbabb01d800> (from <Bicycall.login: 0x7fbabb01d800>) whose view is not in the window hierarchy.
2021-06-20 18:16:28.494339+0200 Bicycall[50670:543648] [Presentation] Attempt to present <UIAlertController: 0x7fbac9862800> on <Bicycall.login: 0x7fbabb01d800> (from <Bicycall.login: 0x7fbabb01d800>) whose view is not in the window hierarchy.
Here what i have tried:
import UIKit
import CoreData
import AVKit
import AVFoundation
import TKSubmitTransition
class login: UIViewController {
#IBOutlet weak var passwordView: UIView!
#IBOutlet weak var emailView: UIView!
var id: Int?
var name: String?
var lastname: String?
var email:String?
var password:String?
var phone:String?
var u = ConnectedUser()
var BR = BaseUrl.baseUrl
var player: AVPlayer?
let videoURL: NSURL = Bundle.main.url(forResource: "Bikers", withExtension: "mp4")! as NSURL
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
func presentTestAlert(_ title: String, _ message: String){
let alert = UIAlertController(title: title , message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .default, handler: { _ in
NSLog("The \"OK\" alert occured.")
}))
DispatchQueue.main.async {
self.getTopMostViewController()?.present(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.DeleteAllData()
player = AVPlayer(url: videoURL as URL)
player?.actionAtItemEnd = .none
player?.isMuted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
playerLayer.zPosition = -1
playerLayer.frame = view.frame
view.layer.addSublayer(playerLayer)
player?.play()
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: CMTime.zero)
self?.player?.play()
// Do any additional setup after loading the view.
}
emailView.layer.cornerRadius = 30.0
emailView.layer.borderWidth = 0.5
emailView.layer.borderColor = UIColor.white.cgColor
passwordView.layer.cornerRadius = 30.0
passwordView.layer.borderWidth = 0.5
passwordView.layer.borderColor = UIColor.white.cgColor
}
//widgets
#IBOutlet weak var txtEmail: UITextField!
#IBOutlet weak var txtPassword: UITextField!
//Actions
#IBAction func btnLogin(_ sender: Any){
//get
/*
guard let url = URL(string: "http://localhost:3000/bikes") else {
return
}
let session = URLSession.shared
session.dataTask(with: url) { ( data , response ,error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do
{
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
}catch{
print(error)
}
}
}.resume()
*/
//post
guard let url = URL(string: BR+"/login") else {
return
}
let bodyparameters = ["email": txtEmail.text, "password": txtPassword.text]
if (txtEmail.text!.isEmpty || txtPassword.text!.isEmpty ){
self.presentTestAlert("Wrong credentials","Email and Password must not be empty")
}else{
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: bodyparameters, options: []) else{
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data,response,error) in
let status = (response as! HTTPURLResponse).statusCode
//print(response)
print(status)
if let response = response {
let status = (response as! HTTPURLResponse).statusCode
//print(response)
print(status)
}
if((status) == 200){
self.presentTestAlert("Connection Success", " internet connection")
print(" Connection Successssssssssssssss")
if let data = data {
do {
//let json = try JSONSerialization.jsonObject(with: data, options: [])
// print(json);
print(data)
let user = try JSONDecoder().decode(User.self, from: data)
DispatchQueue.main.async {
self.id = user.user_id
self.name = user.name
self.lastname = user.lastname
self.email = user.email
self.password = user.password
self.phone = user.phone
print(self.id!)
print(self.email!)
if(user.user_id != 0){
self.saveUser()
self.DisplayConnectedUser()
self.performSegue(withIdentifier: "HomeSegue", sender: "nil")
}else{
self.presentTestAlert("Login Failed","Wrong credentials")
}
}
}catch{
print(error)
}
}
}else {
self.presentTestAlert("No Connection", "No internet connection")
print(" Connection Nooooooooooooooooooooooooo")
}
}.resume()
}
}
func DeleteAllData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let DelAllReqVar = NSBatchDeleteRequest(fetchRequest: NSFetchRequest<NSFetchRequestResult>(entityName: "Users"))
do {
try managedContext.execute(DelAllReqVar)
}
catch {
print(error)
}
}
func saveUser() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext
let entityDescription = NSEntityDescription.entity(forEntityName: "Users" , in: managedContext)
let object = NSManagedObject(entity: entityDescription! , insertInto: managedContext )
object.setValue(id! , forKey: "user_id" )
object.setValue(email! , forKey: "email" )
object.setValue(password! , forKey: "password" )
object.setValue(name! , forKey: "name" )
object.setValue(lastname! , forKey: "lastname" )
object.setValue(phone! , forKey: "phone" )
do {
try managedContext.save()
print("INSERT SUCCESSFULLY")
print(id!)
}
catch {
print("INSERT ERROR")
}
}
#IBAction func btnSignup(_ sender: Any) {
performSegue(withIdentifier: "signupSegue", sender: "nil")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
func DisplayConnectedUser() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext //retourne NSManagedObject toujours
//la requete retourne un NSManagedObject
let request = NSFetchRequest<NSManagedObject>(entityName : "Users")
//execution de la requete
do {
let result = try managedContext.fetch(request)
for item in result {
print(item.value(forKey: "user_id") as! Int )
print(item.value(forKey: "email") as! String)
self.u.user_id = (item.value(forKey: "user_id") as! Int)
self.u.email = (item.value(forKey: "email") as! String)
self.u.password = (item.value(forKey: "password") as! String)
self.u.name = (item.value(forKey: "name") as! String)
self.u.lastname = (item.value(forKey: "lastname") as! String)
self.u.phone = (item.value(forKey: "phone") as! String)
print(self.u.user_id!)
print(self.u.email!)
print(self.u.password!)
print(self.u.name!)
print(self.u.lastname!)
print(self.u.phone!)
}
}
catch {
print("NO DATA FOUND , Error")
}
}
}
What is annoying me is that none of my alerts worked! i read some other answer in stackoverflow but the solutions did not work for me
What i am trying is to make my alerts working good
Any help will be so appreciated
It seems you want to present the alert over the video player (playerLayer) but you are calling your alert over the layer behind the playerLayer, it will give you the error that you're getting.
With reference to Swift 4 Attempt to present ViewController whose view is not in the window hierarchy
Add this function in your code
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
And replace (Line 33)
self.present(alert, animated: true, completion: nil)
with
DispatchQueue.main.async {
getTopMostViewController()?.present(alert, animated: true, completion: nil)
}

Ensure phone number UITextField has a "+" prefix

I have several UITextField where a user can insert phone numbers into it. When I click the send button, it sends an automated message to the numbers listed. Everything works well but what I want to do is that when I click on the Send Button, I want it to check if the UITextFields that has text in it has a + symbol in front of the phone number listed before connecting with my server to send the automated message. How do I go about sending an alert to the user if the phone number listed does not have a + symbol?
ViewController:
class ViewController: UIViewController {
#IBOutlet weak var scrollviewcontact: UIScrollView!
#IBOutlet weak var viewcontact: UIView!
#IBOutlet weak var phonenumber: UITextField!
#IBOutlet weak var phonenumber1: UITextField!
#IBOutlet weak var phonenumber2: UITextField!
#IBOutlet weak var phonenumber3: UITextField!
var currentTextField: UITextField?
private let contactPicker = CNContactPickerViewController()
override func viewDidLoad() {
super.viewDidLoad()
phonenumber.textContentType = .telephoneNumber
phonenumber1.textContentType = .telephoneNumber
phonenumber2.textContentType = .telephoneNumber
phonenumber3.textContentType = .telephoneNumber
}
#IBAction func sendbutton(_ sender: Any) {
var numArray: Array<Any>
numArray = [phonenumber.text!, phonenumber1.text!, phonenumber2.text!, phonenumber3.text!]
let Url = String(format: "//URL")
guard let serviceUrl = URL(string: Url) else { return }
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: numArray, options:[]) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
print("json ", json)
} catch {
print(error)
}
}
}.resume()
}
extension ViewController: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
let phoneNumberCount = contact.phoneNumbers.count
guard phoneNumberCount > 0 else {
dismiss(animated: true)
return
}
if phoneNumberCount == 1 {
setNumberFromContact(contactNumber: contact.phoneNumbers[0].value.stringValue)
}else{
let alertController = UIAlertController(title: "Select one of the numbers", message: nil, preferredStyle: .alert)
for i in 0...phoneNumberCount-1 {
let phoneAction = UIAlertAction(title: contact.phoneNumbers[i].value.stringValue, style: .default, handler: {
alert -> Void in
self.setNumberFromContact(contactNumber: contact.phoneNumbers[i].value.stringValue)
})
alertController.addAction(phoneAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: {
alert -> Void in
})
alertController.addAction(cancelAction)
dismiss(animated: true)
self.present(alertController, animated: true, completion: nil)
}
}
func setNumberFromContact(contactNumber: String) {
var contactNumber = contactNumber.replacingOccurrences(of: "-", with: "")
contactNumber = contactNumber.replacingOccurrences(of: "(", with: "")
contactNumber = contactNumber.replacingOccurrences(of: ")", with: "")
contactNumber = contactNumber.replacingOccurrences(of: " ", with: "")
currentTextField?.text = String(contactNumber)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
}
}
The goal that I'm trying to achieve is that when the Send Button is clicked, it checks which UITextField has text in it, and if it doesn't have a + as a prefix, an alert message should pop up.
You can try
let numArray = [phonenumber.text!, phonenumber1.text!, phonenumber2.text!, phonenumber3.text!]
guard numArray.filter { $0.hasPrefix("+") }.count == numArray.count else {
// alert with message make sure all textfields has + prefix
return
}
You can use the hasPrefix method. For example:
for num in numArray {
if num.hasPrefix("+") {
// do something
} else {
// do something else
}
}

objc[75927]: Class PFFile and objc[75927]: Class PFLogger is implemented in both One of the two will be used. Which one is undefined

No errors in my code, but the console is printing the title of this post. I am using parse as a server. I am using this exact same code in an example video that i learned from on Udemy. Also None of my buttons are working when they are connected properly.
import UIKit
import Parse
class ViewController: UIViewController {
var signUpMode = true
var activityIndicator = UIActivityIndicatorView()
#IBOutlet var emailTextField: UITextField!
#IBOutlet var passwordTextField: UITextField!
#IBOutlet var signUpOrLogin: UIButton!
#IBOutlet var changeSignUpMode: UIButton!
#IBOutlet var messageLabel: UILabel!
func createAlert(title:String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
//self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
#IBAction func signUpOrLogin(_ sender: Any) {
if emailTextField.text == "" || passwordTextField.text == "" {
createAlert(title: "Error due to form", message: "Please enter an Email and Password.")
} else {
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.style = UIActivityIndicatorView.Style.gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
if signUpMode{
let user = PFUser()
user.username = emailTextField.text
user.email = emailTextField.text
user.password = passwordTextField.text
user.signUpInBackground(block:{ (success, error) in
self.activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil {
var displayErrorMessage = "Please try again later"
if let errorMessage = (error! as NSError).userInfo["error"] as? String {
displayErrorMessage = errorMessage
//This is the message that the console gives us
}
self.createAlert(title: "Signup Error", message: displayErrorMessage)
} else {
print("user signed up")
}
})
} else {
//login mode
PFUser.logInWithUsername(inBackground: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
self.activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil{
var displayErrorMessage = "Please try again later"
if let errorMessage = (error! as NSError).userInfo["error"] as? String {
displayErrorMessage = errorMessage
//This is the message that the console gives us
}
self.createAlert(title: "Login Error", message: displayErrorMessage)
} else {
print("logged in")
}
}
}
}
}
#IBAction func changeSignUpMode(_ sender: Any) {
if signUpMode{
//Change to Login Mode
signUpOrLogin.setTitle("Log In", for: [] ) //empty array is default state again....
changeSignUpMode.setTitle("Sign Up", for: [])
messageLabel.text = "Don't have an account?"
signUpMode = false
} else {
//Change to SignupMode
signUpOrLogin.setTitle("Sign Up", for: [])
changeSignUpMode.setTitle("Log In", for: [])
messageLabel.text = "Already have an account?"
signUpMode = true
}
}

Custom Auth using AWS Cognito, Swift

I am trying to use AWS Cognito for password less signin/signup using mobile number.
Signin/Signup steps:
User submits only mobile number
After receiving the passcode via sms, the user submits that to signin/signup.
To achieve the above, as there is no example code for mobile number only Signin, I am trying to amend the standard sign up (email, password) code shown in this aws sdk github example.
Can someone please advice what changes are to be made to achieve signin via mobile number only (no e-mail or username).
import Foundation
import AWSCognitoIdentityProvider
class SignUpViewController: UIViewController {
var pool: AWSCognitoIdentityUserPool?
var sentTo: String?
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var phone: UITextField!
#IBOutlet weak var email: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.pool = AWSCognitoIdentityUserPool.init(forKey: AWSCognitoUserPoolsSignInProviderKey)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let signUpConfirmationViewController = segue.destination as? ConfirmSignUpViewController {
signUpConfirmationViewController.sentTo = self.sentTo
signUpConfirmationViewController.user = self.pool?.getUser(self.username.text!)
}
}
#IBAction func signUp(_ sender: AnyObject) {
guard let userNameValue = self.username.text, !userNameValue.isEmpty,
let passwordValue = self.password.text, !passwordValue.isEmpty else {
let alertController = UIAlertController(title: "Missing Required Fields",
message: "Username / Password are required for registration.",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
return
}
var attributes = [AWSCognitoIdentityUserAttributeType]()
if let phoneValue = self.phone.text, !phoneValue.isEmpty {
let phone = AWSCognitoIdentityUserAttributeType()
phone?.name = "phone_number"
phone?.value = phoneValue
attributes.append(phone!)
}
if let emailValue = self.email.text, !emailValue.isEmpty {
let email = AWSCognitoIdentityUserAttributeType()
email?.name = "email"
email?.value = emailValue
attributes.append(email!)
}
//sign up the user
self.pool?.signUp(userNameValue, password: passwordValue, userAttributes: attributes, validationData: nil).continueWith {[weak self] (task) -> Any? in
guard let strongSelf = self else { return nil }
DispatchQueue.main.async(execute: {
if let error = task.error as? NSError {
let alertController = UIAlertController(title: error.userInfo["__type"] as? String,
message: error.userInfo["message"] as? String,
preferredStyle: .alert)
let retryAction = UIAlertAction(title: "Retry", style: .default, handler: nil)
alertController.addAction(retryAction)
self?.present(alertController, animated: true, completion: nil)
} else if let result = task.result {
// handle the case where user has to confirm his identity via email / SMS
if (result.user.confirmedStatus != AWSCognitoIdentityUserStatus.confirmed) {
strongSelf.sentTo = result.codeDeliveryDetails?.destination
strongSelf.performSegue(withIdentifier: "confirmSignUpSegue", sender:sender)
} else {
let _ = strongSelf.navigationController?.popToRootViewController(animated: true)
}
}
})
return nil
}
}
}

Password is getting cached somewhere, need to clear it

I am working on an app that accesses a REST API Webservice. Everything is working great, except I recently started working on the the ability to logout and switch users and I've run into a strange situation. If I log out, and then click login again without entering the password it's working. I've even debugged the code and see that the password is blank, but the authentication is still working. Here is the code:
import UIKit
import LocalAuthentication
var userName = String()
var password = String()
var server = String()
var port = String()
var myUser = User()
var myExtensions = [ExtensionListItem]()
var myDevices = [Device]()
class LoginViewController: UIViewController, NSURLSessionDelegate, UITextFieldDelegate {
let authContext: LAContext = LAContext()
var logOutUser = Bool()
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var serverNameField: UITextField!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet var loginEnable: UIButton!
var userPasswordString = NSString()
let userRequest = NSMutableURLRequest()
var userSession = NSURLSession()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(logoff), name: "logoff", object: nil)
if logOutUser {
NSUserDefaults.standardUserDefaults().setValue("", forKey: "password")
NSURLCache.sharedURLCache().removeAllCachedResponses()
userPasswordString = NSString()
}
//Determine if the user has a stored Username and populate the usernameField if possible
if NSUserDefaults.standardUserDefaults().objectForKey("userName") != nil{
usernameField.text = NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String}
//Determine if the user has a stored ServerName and populate the serverNameField if possible.
if NSUserDefaults.standardUserDefaults().objectForKey("serverName") != nil{
serverNameField.text = NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String}
//Determin if the user has requested to use Touch ID
if (NSUserDefaults.standardUserDefaults().objectForKey("useTouchID") != nil) {
if NSUserDefaults.standardUserDefaults().valueForKey("useTouchID") as! Bool == true && CheckTouchIDCapable(){
//Trigger Touch ID
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
TouchIDCall()
}
}
// Do any additional setup after loading the view.
}
func logoff(){
NSURLCache.sharedURLCache().removeAllCachedResponses()
userSession.invalidateAndCancel()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
NSURLCache.sharedURLCache().removeAllCachedResponses()
// Dispose of any resources that can be recreated.
}
#IBAction func loginButton(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setObject(usernameField.text, forKey: "userName")
NSUserDefaults.standardUserDefaults().setObject(passwordField.text, forKey: "password")
NSUserDefaults.standardUserDefaults().setObject(serverNameField.text, forKey: "serverName")
if NSUserDefaults.standardUserDefaults().valueForKey("touchIDPreferenceSet") == nil && CheckTouchIDCapable() {
DisplayTouchIDQuestion("Use Touch ID?", message: "Would you like to use touch ID to login?")
}else{
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
CheckUser()
}
print("Password: \(password)")
print("Stored Password: \(NSUserDefaults.standardUserDefaults().valueForKey("password"))")
print("?? \(NSUserDefaults.standardUserDefaults().objectForKey("password"))")
}
func CheckUser(){
userName = (NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String)!
if !logOutUser{
password = (NSUserDefaults.standardUserDefaults().objectForKey("password") as? String)!
}
server = (NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String)!
port = "8443"
// set up the base64-encoded credentials
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
userPasswordString = NSString(format: "%#:%#", userName, password)
let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders?.removeAll()
config.HTTPAdditionalHeaders = ["Authorization" : authString]
config.timeoutIntervalForRequest = 10.0
// create the user request
let userUrlString = NSString(format: "https://%#:%#/webserver/user/%#", server, port, userName)
let userUrl = NSURL(string: userUrlString as String)
userRequest.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
userRequest.URL = userUrl!
userRequest.HTTPMethod = "GET"
userRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
userSession = NSURLSession(configuration: config, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
//Send User Request to the server and populate labels with response.
_ = userSession.dataTaskWithRequest(userRequest) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error?.code != nil{
print("ERROR: \(error!.localizedDescription)")
self.DisplayAlert("Error", message: error!.localizedDescription)
}else{
_ = NSString (data: data!, encoding: NSUTF8StringEncoding)
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let accessDenied = Bool(dataString?.rangeOfString("HTTP Status 403").location != NSNotFound)
let authFailure = Bool(dataString?.rangeOfString("HTTP Status 401").location != NSNotFound)
if (authFailure || accessDenied) {
print("\(NSDate()): Unsuccessful Password Authentication Attempt for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.DisplayAlert("Access Denied", message: "Please Verify Your Credentials")
}else{
print("\(NSDate()): Successful Password Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.performSegueWithIdentifier("authenticated", sender: self)
}
}
})
}.resume()
}
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}
override func prefersStatusBarHidden() -> Bool {
return true
}
// MARK: - Keyboard Functions
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
if textField == passwordField && usernameField.text != "" && serverNameField.text != ""{
loginButton(self)
}
return true
}
func ReEnableLogin(){
self.activityIndicator.hidesWhenStopped = true
self.activityIndicator.stopAnimating()
self.usernameField.enabled = true
self.passwordField.enabled = true
self.serverNameField.enabled = true
}
func DisplayAlert(title: String, message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
self.ReEnableLogin()
}
func DisplayTouchIDQuestion(title: String, message: String){
let alertControllerQuestion = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alertControllerQuestion.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "useTouchID")
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
NSUserDefaults.standardUserDefaults().setValue(self.passwordField.text, forKey: "touchIDCachedCredential")
self.CheckUser()
}))
alertControllerQuestion.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
NSUserDefaults.standardUserDefaults().setValue(false, forKey: "useTouchID")
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
self.CheckUser()
}))
self.presentViewController(alertControllerQuestion, animated: true, completion: nil)
}
func CheckTouchIDCapable()-> Bool {
var error: NSError?
var touchEnabledDevice: Bool = false
if authContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error){
touchEnabledDevice = true
}
return touchEnabledDevice
}
func TouchIDCall(){
authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Place your finger on the Home button to log into Collaboration User Tools", reply: { (wasSuccessful, error) in
if wasSuccessful{
print("\(NSDate()): Successful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
NSUserDefaults.standardUserDefaults().setValue(NSUserDefaults.standardUserDefaults().valueForKey("touchIDCachedCredential"), forKey: "password")
self.CheckUser()
}else{
print("\(NSDate()): Error: \(error!.code)")
print("\(NSDate()): Unsuccessful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
let qualityOfServiceClass = QOS_CLASS_USER_INTERACTIVE
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.activityIndicator.stopAnimating()
})
})
self.ReEnableLogin()
}
})
}
}
I've tried:
NSURLCache.sharedURLCache().removeAllCachedResponses()
userSession.invalidatedAndCancel()
The logout table view controller calls this method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row{
case 0:
myUser = User()
myExtensions.removeAll()
myDevices.removeAll()
NSUserDefaults.standardUserDefaults().setObject("", forKey: "password")
userName = ""
password = ""
NSURLCache.sharedURLCache().removeAllCachedResponses()
NSNotificationCenter.defaultCenter().postNotificationName("logoff", object: nil)
performSegueWithIdentifier("logout", sender: self)
default:
break
}
}
I don't know where the password is being cached. Any ideas?
I think your issue lies on part of your logic when handling your password. First, in your func CheckUser() you assign the value of var password if !logOutUser from your user defaults, however this property (password) is not getting cleared at any point, so if !logOutUser is false (which it looks like always is, as its not getting set anywhere), and your input fields are empty, then it will use the previous value that you had store in there.
So if I am correct, and the culprit here is that the password field is storing its data, a quick, dirty fix would be to simply clear these fields (username and password) after you perform your request. A better fix would be to directly pass the usernameField.text value directly and clear it after its done. (I'm unsure why you are storing your user's password in your app, which I would recommend reconsidering, if you need it for validating a session you should be using authentication tokens)
// set up the base64-encoded credentials
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
userPasswordString = NSString(format: "%#:%#", userName, password)
userName = ""
password = ""
I would also like to point out that you should be using optionals for these fields, you should be using optional unwrapping for your user defaults and also adding a validation mechanism so that you do not submit requests with empty fields, ideally your button would be disabled or you would alert your user of an invalid field.
Good Luck!
EDIT
Try this approach: rather than using a class property for the values of password username and server. Use method variables to set your values, this way these values will get disposed when the method terminates. (This is a bit of a shot in the dark as i dont have a compiler at hand so there might be some minor syntax errors). - note the method signature
func CheckUser(username: String, password: String, server: String){
let port = "8443"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let userPasswordString = NSString(format: "%#:%#", username, password)
let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders?.removeAll()
config.HTTPAdditionalHeaders = ["Authorization" : authString]
config.timeoutIntervalForRequest = 10.0
// create the user request
let userUrlString = NSString(format: "https://%#:%#/webserver/user/%#", server, port, username)
let userUrl = NSURL(string: userUrlString as String)
userRequest.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
userRequest.URL = userUrl!
userRequest.HTTPMethod = "GET"
userRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
userSession = NSURLSession(configuration: config, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
//Send User Request to the server and populate labels with response.
let task = userSession.dataTaskWithRequest(userRequest) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error?.code != nil{
print("ERROR: \(error!.localizedDescription)")
self.DisplayAlert("Error", message: error!.localizedDescription)
}else{
_ = NSString (data: data!, encoding: NSUTF8StringEncoding)
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let accessDenied = Bool(dataString?.rangeOfString("HTTP Status 403").location != NSNotFound)
let authFailure = Bool(dataString?.rangeOfString("HTTP Status 401").location != NSNotFound)
if (authFailure || accessDenied) {
print("\(NSDate()): Unsuccessful Password Authentication Attempt for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.DisplayAlert("Access Denied", message: "Please Verify Your Credentials")
}else{
print("\(NSDate()): Successful Password Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.performSegueWithIdentifier("authenticated", sender: self)
}
}
})
}.resume()
}
Then you can call your method as so:
if NSUserDefaults.standardUserDefaults().valueForKey("touchIDPreferenceSet") == nil && CheckTouchIDCapable() {
DisplayTouchIDQuestion("Use Touch ID?", message: "Would you like to use touch ID to login?")
}else{
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
CheckUser(usernameField.text, password: passwordField.text, server: serverNameField.text)
}
My problem was never related to password caching. Most likely due to my relatively amateur experience level, I never considered the fact that it might be COOKIES keeping the session up. That's exactly what it ended up being. I solved the situation simply by deleting all cookies during the logout procedure. I added the following to my logout code and it's working perfectly.
print("\(NSDate()): Logout Requested, Deleting Cookies")
let cookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
let cookies = cookieStorage.cookies! as [NSHTTPCookie]
print("\(NSDate()): Cookie count: \(cookies.count)")
for cookie in cookies{
print("\(NSDate()): Deleting Cookie name: \(cookie.name) value: \(cookie.value)")
NSHTTPCookieStorage.sharedHTTPCookieStorage().deleteCookie(cookie)
}