WorldPay AccessCheckoutSDK IOS "generateSession" gives "Identity is invalid" error - ios

I am trying to integrate WorldPay's "AccessCheckoutSDK" in my IOS Application using Swift by following
https://developer.worldpay.com/docs/access-worldpay/checkout/ios/card-only
while generating session it give me "Identity is invalid" error .
Here is the code i tried
func initializedSDK() -> AccessCheckoutClient? {
let accessCheckoutClient = try?
AccessCheckoutClientBuilder().accessBaseUrl(WORLDPAY_BASE_URL)
.merchantId(WORLDPAY_MERCHANT_ID)
.build()
return accessCheckoutClient
}
func createCardDetails(CardNumber : String , CardExpiry : String , CardCVC : String) -> CardDetails? {
let cardDetails = try? CardDetailsBuilder().pan(CardNumber)
.expiryDate(CardExpiry)
.cvc(CardCVC)
.build()
return cardDetails
}
func CreateSession(CardNumber : String , CardExpiry : String , CardCVC : String) {
guard let accessCheckoutClient = initializedSDK() else {
// not going here so accessCheckoutClient is initialized
return
}
guard let cardDetails = createCardDetails(CardNumber: CardNumber, CardExpiry: CardExpiry, CardCVC: CardCVC) else {
// Not going here , so card details are valid
return
}
try? accessCheckoutClient.generateSessions(cardDetails: cardDetails, sessionTypes: [SessionType.card , .cvc ]) { result in
DispatchQueue.main.async {
switch result {
case .success(let sessions):
// The session is returned in a Dictionary[SessionType:String]
//not going here
let cardSession = sessions[SessionType.card]
let cvcSession = sessions[SessionType.cvc]
case .failure(let error):
// The error returned is of type AccessCheckoutError
print("error \(error)")
// It is going here and prints this error below
}
}
}
}
I am getting this error
AccessCheckoutError(errorName: "bodyDoesNotMatchSchema", message: "bodyDoesNotMatchSchema : The json body provided does not match the expected schema", validationErrors: [AccessCheckoutSDK.AccessCheckoutError.AccessCheckoutValidationError(errorName: "fieldHasInvalidValue", message: "Identity is invalid", jsonPath: "$.identity")])
WORLDPAY_BASE_URL = "https://try.access.worldpay.com/"
Note : I am using worldPay in testMode and didn't activated live mode yet and made sure that WORLDPAY_MERCHANT_ID is correct.

After all the research on worldPay , i decide to mail to worldPay support, After a brief chat with them and after they went through my worldPay account, this was their final reply :
"Your account status, "basic", "free tier" does not permit you to have access to this endpoint."
I decided to answer my own question so that if anyone have the same problem while integrating WorldPay with test Account, This would help them. I still think WorldPay developer can handle this scenario better by returning this exact string straightforward in the api response instead of throwing a 500 server error.
I welcome other answers and information on this post as well. If you have something informative about worldPay integration to IOS, please feel free to comment or answer this question.

Related

How to access JSON response in Swift using AWS API Gateway-generated iOS SDK

I have a working REST API based on this API Gateway tutorial. I'm able to successfully invoke it via the test functionality of the AWS Console; and I'm able to successfully invoke it via my simple iOS Swift 4.2 Xcode application using the iPhone XR simulator.
I know it's working via a real, live external call because I can see the Cloudwatch logs which always register a 200 response and is sending the results back to the Client.
My problem is really in understanding the Swift code, and I'm hoping that a Swift expert can help me understand how to unpack result in the code below.
Here's my code in ViewController.swift for invoking the REST API and attempting to print result to the console:
#IBAction func userInvokeApi(_ sender: UIButton) {
print("You clicked invoke api...")
let client = SVTLambdaGateClient.default()
client.calcGet(operand2: "3", _operator: "+", operand1: "5").continueWith{ (task: AWSTask?) -> AnyObject? in
if let error = task?.error {
print("Error occurred: \(error)")
return nil
}
if let result = task?.result {
// Do something with result
print("The result is... \(result)")
}
return nil
}
}
As pointed out in the comments below, I'm getting the following result because it's printing out the address of the object:
You clicked invoke api...
The result is... <AmplifyRestApiTest.Empty: 0x600002020770> {
}
(where AmplifyRestApiTest is the name of my Xcode project.)
UPDATE When I set a breakpoint on the print statement, this is what I see in the Debug pane:
UPDATE 2
When I type task?.result there are two viable properties as per this answer from the Amplify team: error and result. So, since my API responds successfully I am assuming I just don't know how to view result.
Can someone help me understand what steps I must take to access members of this class object?
Here is the corresponding method in the API Gateway-generated iOS Swift SDK code:
/*
#param operand2
#param _operator
#param operand1
return type: Empty
*/
public func calcGet(operand2: String, _operator: String, operand1: String) -> AWSTask<Empty> {
let headerParameters = [
"Content-Type": "application/json",
"Accept": "application/json",
]
var queryParameters:[String:Any] = [:]
queryParameters["operand2"] = operand2
queryParameters["operator"] = _operator
queryParameters["operand1"] = operand1
let pathParameters:[String:Any] = [:]
return self.invokeHTTPRequest("GET", urlString: "/calc", pathParameters: pathParameters, queryParameters: queryParameters, headerParameters: headerParameters, body: nil, responseClass: Empty.self) as! AWSTask<Empty>
}
I'm fairly certain this return type of Empty refers to the Empty model defined for the REST API as shown in the screenshot below. I think it's "empty" because the API doesn't alter the response from the Lambda function back to the Client. So, it's all pass-through. Indeed, the tutorial explains that the other models -- Output and Result -- are not used because it "relies on the passthrough behavior and does not use this model."
Any thoughts?

How to safely handle multiple writes in firebase which must all happen

I want to handle a friend request in my app written in Swift using Firebase. In my database, this means that the user sending the request needs to add the other user to their "sentRequests" dictionary, and the user receiving the request needs to add the user sending the requests to their "receivedRequests" dictionary. The problem is, if the user sending the request has a faulty connection and only does the first part, then it might cause issues. Either both writes should happen or none. What can I do to fix this? I included my code below for reference, but honestly if someone just sends me a good tutorial or answer here that would be just has helpful as correctly rewriting my code.
static func sendRequestFromCurrentUser(toUser userThatRequestWasSentTo : User, succeeded : #escaping (Bool)->Void ){
let ref = Database.database().reference().child("users").child(User.current.uid).child("sentRequests").child(userThatRequestWasSentTo.uid)
ref.setValue(userThatRequestWasSentTo.toDictionary(), withCompletionBlock: {(error, ref) in
if error == nil{
let currentUserRef = Database.database().reference().child("users").child(userThatRequestWasSentTo.uid).child("receivedRequests").child(User.current.uid)
currentUserRef.setValue(User.current.toDictionary(), withCompletionBlock: {(error, ref) in
if error == nil{
succeeded(true)
}
else{
succeeded(false)
}
})
}
else{
succeeded(false)
}
})
}
So I stole this from the Firebase blog and got it to match my code. The answer is fairly intuitive, I just hadn't considered it. Basically you just create a reference to the top level of your database and specify the paths you want to write to in the dictionary (so not by creating specific references with child()), and then just call updateChildValues().
static func sendRequestFromCurrentUser(toUser userThatRequestWasSentTo : User, succeeded : #escaping (Bool)->Void ){
let ref = Database.database().reference()
// Create the data we want to update
var updatedUserData : [String : Any] = [:]
updatedUserData["users/\(User.current.uid)/sentRequests/\(userThatRequestWasSentTo.uid)"] = userThatRequestWasSentTo.toDictionary()
updatedUserData["users/\(userThatRequestWasSentTo.uid)/receivedRequests/\(User.current.uid)"] = User.current.toDictionary()
// Do a deep-path update
ref.updateChildValues(updatedUserData, withCompletionBlock: { (error, ref) in
if let error = error {
print("Error updating data: \(error.localizedDescription)")
succeeded(false)
}
else{
succeeded(true)
}
})
}

In Swift-iOS How I catch User Authentication erros in AWS Cognito?

I'm trying aws cognito user pool and got stacked in the user sign up process. I already configured my user pool and are executing the sign-up method, but I can find a way to get the error code returned by aws services. Here my user pool instantiation, that is working fine:
let poolConfig = AWSCognitoIdentityUserPoolConfiguration(
clientId: userPool_clientId,
clientSecret: userPool_secret,
poolId: userPool_id)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPool(with: poolConfig,
forKey: userPoll_App)
userPool = AWSCognitoIdentityUserPool(forKey: userPoll_App)
Then, in my view controller I have a Button whit a #IBAction with this:
if userPool != nil {
let attName = AWSCognitoIdentityUserAttributeType()!
attName.name = "name"
attName.value = userNome
let attLast = AWSCognitoIdentityUserAttributeType()!
attLast.name = "family name"
attLast.value = userSobrenome
let attEmail = AWSCognitoIdentityUserAttributeType()!
attEmail.name = "email"
attEmail.value = userEmail
var result:Bool = false
userPool!.signUp(userNome,
password: userPwd,
userAttributes: [attName, attLast, attEmail],
validationData: nil).continue({(task:AWSTask!) in
if (task.error != nil) {
print (task.error!)
result = false
} else {
result = true
}
return nil
})
After that code, I test the result to see if it is true or false and take the appropriate action. But...
I'm having different errors in this process and I need to evaluate this errors in development time. For example, the first error that I got was because I misconfigured the AWS region. Ok! Game on!! But the second error was because the password informed by the user did not passed the validation of the pool. In this case, I want to know the error was because the validation process and inform the user to take the appropriate action. I do not want to have this logic in the iOS app. The task.error object just give a localized description property and it is not very helpful.
By the way: I'm using Swift 3.2, iOS 10.2, aws-ios-sdk2 and Xcode 8.
I would like to expand on behrooziAWS's answer.
In Swift 4 you can match the error code with enums like AWSCognitoIdentityProviderErrorType.TheErrorType.rawValue.
Here's a tip for searching your error type, just type "AWSErrorType" and Xcode's autocomplete would show all the enums and then you can look through them.
Here's a code I use.
AWSobject.AWSfunction().continueWith { task -> Any? in
if let err = task.error as NSError? {
switch err.code {
case: AWSCognitoIdentityProviderErrorType.userNotFound.rawValue:
// Handle case
default:
// Handle all other cases here
return nil
}
// Do stuff on success!
}
task.error.code will contain a code you can compare to values in this enum. Look here for the particular error codes that can be returned by SignUp.

Unit Testing private functions that require keychain authentication in swift

Thanks in advance for any advice!
I'm setting up some unit tests in swift for iOS development. The method requires a call to the keychain to create an authToken to successfully run the function. I'm not sure how to approach creating a unit test for this kind of environment. Do I mock up a local file that I can use to bypass the authentication? Do I try to skip the authentication step entirely?
The function I'm testing is a private function as well and I'm having a hard time conceptualizing how I can test it through the public methods. Here is the code I'm working with:
override func viewDidLoad() {
super.viewDidLoad()
self.setMyDoctorsNavBarTitle()
self.setBackgroundWaterMark()
self.getDoctors()
//self.refreshControl?.addTarget(self, action: #selector(MyDoctorsViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
private func getDoctors() {
let authToken: [String: AnyObject] = [ "Authorization": keychain["Authorization"]!, // creates an authToken with the current values stored in
"UUID": keychain["UUID"]!, "LifeTime": keychain["LifeTime"]! ] // the keychain
RestApiManager.sharedInstance.postMyDocs(authToken) { (json, statusCode) in // passes the created authToken to postMyDocs in RestAPI to see if
if statusCode == 200 { // the token matches what's on the server
if let results = json["Doctors"].array { // If the credentials pass, we grab the json file and create an array of Doctors
for entry in results {
self.buildDoctorObject(entry) // Doctors information is parsed into individual objects
}
}
} else if statusCode == 401 {
/* If statucCode is 401, the user's AuthToken has expired. The historical AuthToken data will be removed from the iOS KeyChain and the user will be redirected to the login screen to reauthorize with the API
*/
self.keychain["Authorization"] = nil
self.keychain["UUID"] = nil
self.keychain["LifeTime"] = nil
let loginController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as! LoginViewController
NSOperationQueue.mainQueue().addOperationWithBlock {
self.presentViewController(loginController, animated: true, completion: nil)
}
} else if statusCode == 503 {
print("Service Unavailable Please Try Again Later")
}
}
}
private func buildDoctorObject(json: JSON){
let fName = json["FirstName"].stringValue
let lName = json["LastName"].stringValue
let city = json["City"].stringValue
let phNum = json["PhoneNumber"].stringValue
let faxNum = json["FaxNumber"].stringValue
let state = json["State"].stringValue
let addr = json["Address"].stringValue
let img = json["Image"].stringValue
let zip = json["Zip"].stringValue
let tax = json["Taxonomy"].stringValue
let docObj = DoctorObject(fName: fName, lName: lName, addr: addr, city: city, state: state, zip: zip, phNum: phNum, faxNum: faxNum, img: img, tax: tax)
self.docs.append(docObj)
self.tableView.reloadData()
}
I want to be able to Unit Test the getDoctors() and buildDoctorObject() functions, but I can only do that indirectly through viewDidLoad() since they're private.
I want to be able to test that the statusCode is being brought down correctly from the server and the appropriate steps take place if it comes back as 200 or 401.
I'm not necessarily looking for complete code, but simply a way to approach the problem. If you know of resources that might be helpful I would be grateful. I'm very new to this and I tried looking into resources online but couldn't find anything. A lot of what I found was you don't want to test private functions directly, and isn't advised to change the functions to public for the sake of testing.
Thanks again for looking into it!
Sean W.
Define that private method in the Test Class, with the same signature. Just try to call that method it will call your actual class method.

How do I run a Cloud Code on Heroku?

With the Parse's announcement of their retirement, I have migrated my Parse Server onto Heroku. With my still neophyte knowledge of Heroku, I do not know if they have a similar function to that of Cloud Code, but I do know that a few months ago Parse Introduced a Heroku + Parse feature that allows you to run Cloud Code on any node.js environment, particularly Heroku.
My dilemma is, I have already migrated my server from parse to Heroku prior to learning about this feature :/ , so I cannot run any parse cloud code form my terminal because there is no existing server there anymore. So the question is, how can I emulate this following Cloud Code in Heroku & How do I adjust my swift?
Cloud Code:
// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Parse.Cloud.define("isLoginRedundant", function(request, response) {
Parse.Cloud.useMasterKey();
var sessionQuery = new Parse.Query(Parse.Session);
sessionQuery.equalTo("user", request.user);
sessionQuery.find().then(function(sessions) {
response.success( { isRedundant: sessions.length>1 } );
}, function(error) {
response.error(error);
});
});
and here is my swift back in xcode:
PFUser.logInWithUsernameInBackground(userName!, password: passWord!) {
(user, error) -> Void in
if (user != nil) {
// don't do the segue until we know it's unique login
// pass no params to the cloud in swift (not sure if [] is the way to say that)
PFCloud.callFunctionInBackground("isLoginRedundant", withParameters: [:]) {
(response: AnyObject?, error: NSError?) -> Void in
let dictionary = response as! [String:Bool]
var isRedundant : Bool
isRedundant = dictionary["isRedundant"]!
if (isRedundant) {
// I think you can adequately undo everything about the login by logging out
PFUser.logOutInBackgroundWithBlock() { (error: NSError?) -> Void in
// update the UI to say, login rejected because you're logged in elsewhere
// maybe do a segue here?
let redundantSession: String = "you are already logged in on another device"
self.failedMessage(redundantSession)
self.activityIND.stopAnimating()
self.loginSecond.userInteractionEnabled = true
}
} else {
// good login and non-redundant, do the segue
self.performSegueWithIdentifier("loginSuccess", sender: self)
}
}
} else {
// login failed for typical reasons, update the UI
dispatch_async(dispatch_get_main_queue()) {
self.activityIND.stopAnimating()
self.loginSecond.userInteractionEnabled = true
if let message = error?.userInfo["error"] as? String
where message == "invalid login parameters" {
let localizedMessage = NSLocalizedString(message, comment: "Something isn't right, check the username and password fields and try again")
print(localizedMessage)
self.failedMessage(localizedMessage)
}else if let secondMessage = error?.userInfo["error"] as? String
where secondMessage == "The Internet connection appears to be offline." {
self.failedMessage(secondMessage)
}
}
}
}
I would first checkout the example repo and read the parse-server documentation. Parse server supports cloud code out of the box and you simply specify which file contains your functions and triggers in the parse-server config. The link you posted with the integration between parse and heroku is not relevant for parse-server.

Resources