-
Notifications
You must be signed in to change notification settings - Fork 0
/
ViewController.swift
318 lines (241 loc) · 12.5 KB
/
ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
//
// ViewController.swift
// FDAppleIpg
//
//
//
//
import UIKit
import PassKit
import CommonCrypto
extension Date {
func toMillis() -> Int64! {
return Int64(self.timeIntervalSince1970 * 1000)
}
}
class ViewController: UIViewController, PKPaymentAuthorizationViewControllerDelegate {
//All the variables required for the Apple Pay Payment Processing.
var amt:String = " "
var mchtId:String = " "
var transType:String = "WalletPreAuthTransaction"
var transactionId = " "
var status = " "
var walletType = "EncryptedApplePayWalletPaymentMethod";
var currency = "USD";
var paymentRequest = PKPaymentRequest()
var payload = " "
let alert = UIAlertController(title: "Transaction Result", message: "", preferredStyle: .alert)
let okAction: UIAlertAction = UIAlertAction(title:"OK", style: .default, handler: {(action: UIAlertAction) -> Void in
})
var base64:String = " "
var resString:String = " "
//Hmac variables
var timestamp = String(Date().toMillis())
var signature:String = " "
//Configuration Details required for the remote connection
var env:String = "CERT"
var apiKey:String = "First data provided api key"
var apiSecret:String = "First data provided api secret"
var url:String = "https://cert.api.firstdata.com/gateway/v2/payments"
//The outlets to the components in the View.l
@IBOutlet weak var merchant_id: UITextField!
@IBOutlet weak var amount: UITextField!
@IBOutlet weak var segControl: UISegmentedControl!
@objc func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
@objc func alertControllerBackgroundTapped()
{
self.dismiss(animated: true, completion: nil)
}
@objc func dismissOnTapOutside(){
self.dismiss(animated: true, completion: nil)
}
//Capture the mercchant id from the user.
@IBAction func getMerchantId(_ sender: Any) {
mchtId = merchant_id.text!
print(mchtId)
}
//Capture the Amount from the user.
@IBAction func getAmt(_ sender: Any) {
amt = amount.text!
print(amt)
}
//Caputre the transaction type (PreAuth/Sale)
@IBAction func tyepeSelect(_ sender: Any) {
let getIdx = segControl.selectedSegmentIndex;
switch (getIdx) {
case 0:
amt = amount.text!
print(amt)
transType = "WalletPreAuthTransaction"
print(transType)
case 1:
amt = amount.text!
print(amt)
transType = "WalletSaleTransaction"
print(transType)
default:
print("Enter the correct type")
}
}
//Authorize Apple pay after clicking the apple pay button.
@IBAction func applePayBtnTapped(_ sender: Any) {
amt = amount.text!
print(amt)
let paymentNetworks = [PKPaymentNetwork.amex, .masterCard, .visa,.discover]
if PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: paymentNetworks)
{
paymentRequest.currencyCode = "USD"
paymentRequest.countryCode = "US"
paymentRequest.merchantIdentifier = mchtId
paymentRequest.supportedNetworks = paymentNetworks
paymentRequest.merchantCapabilities = .capability3DS
paymentRequest.requiredShippingAddressFields = .all
paymentRequest.paymentSummaryItems = itemsToSell(shipping: Double(amt)!)
let appString = "RefCode:12345; TxID:34234089240982304823094823432"
paymentRequest.applicationData = Data(appString.utf8)
base64 = paymentRequest.applicationData!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
//print(base64)
let appStr = String(decoding: paymentRequest.applicationData!, as: UTF8.self)
print(appStr)
let sameDayShipping = PKShippingMethod(label: "Same Day", amount: 0.00)
sameDayShipping.detail = "Items shipped in the same day"
sameDayShipping.identifier = "sameDayShipping"
let twoDayShipping = PKShippingMethod(label: "twoDay", amount: 0.00)
twoDayShipping.detail = "Items will be shipped in two days"
twoDayShipping.identifier = "TwoDayShip"
let freeShipping = PKShippingMethod(label: "freeShiping", amount:0.00)
freeShipping.detail = "Free shipping"
freeShipping.identifier = "FreeShip"
paymentRequest.shippingMethods = [sameDayShipping,twoDayShipping,freeShipping]
let applePayVC = PKPaymentAuthorizationViewController(paymentRequest: paymentRequest)
applePayVC?.delegate = self
self.present(applePayVC!, animated: true, completion: nil)
}
else
{
print("Device cannot make Apple Pay payments.")
// self.alert.message = "Device cannot make Apple Pay payments."
// self.present(alert, animated: true, completion: nil)
}
}
func itemsToSell(shipping: Double)->[PKPaymentSummaryItem]{
let TShirt = PKPaymentSummaryItem(label: "TShirt", amount: NSDecimalNumber(string:"\(amt)"))
let discount = PKPaymentSummaryItem(label: "dicount", amount: 0.00)
let shipping = PKPaymentSummaryItem(label: "shipping", amount: 0.00)
let totalAmt = TShirt.amount.adding(discount.amount).adding(shipping.amount)
let totalPrice = PKPaymentSummaryItem(label: "ABC", amount: totalAmt)
return [TShirt,discount,shipping,totalPrice]
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: @escaping (PKPaymentAuthorizationStatus) -> Void) {
struct encryptedHeader: Decodable {
let applicationData: String
let ephemeralPublicKey: String
let publicKeyHash: String
let transactionId: String
init(jsonHead:[String:Any]){
applicationData = jsonHead["applicationData"] as? String ?? " "
ephemeralPublicKey = jsonHead["ephemeralPublicKey"] as? String ?? " "
publicKeyHash = jsonHead["publicKeyHash"] as? String ?? " "
transactionId = jsonHead["transactionId"] as?String ?? " "
}
}
struct encryptedPayload: Decodable {
let data: String
let signature: String
let version: String
let header: encryptedHeader
init(jsonEncBody:[String:Any]){
data = jsonEncBody["data"] as? String ?? " "
header = (jsonEncBody["header"]as? encryptedHeader ?? nil)!
version = jsonEncBody["version"] as? String ?? " "
signature = jsonEncBody["signature"] as? String ?? " "
}
}
let jsonBody = payment.token.paymentData
/*Tests for apple pay Payloads*/
// print("jsonBody = \(jsonBody)")
//let str = String(decoding:jsonBody, as: UTF8.self)
//let decryptedPaymentData:NSString! = NSString(data: jsonBody, encoding: String.Encoding.utf8.rawValue)*/
// print(str)
do{
let encry = try JSONDecoder().decode(encryptedPayload.self, from: jsonBody)
let json : [String:Any] =
["requestType":transType,"walletPaymentMethod":["walletType":"EncryptedApplePayWalletPaymentMethod","encryptedApplePay":["version":encry.version,"applicationData":base64,"header":["applicationDataHash":encry.header.applicationData,"ephemeralPublicKey":encry.header.ephemeralPublicKey,"publicKeyHash":encry.header.publicKeyHash,"transactionId":encry.header.transactionId],"signature":encry.signature,"data":encry.data,"merchantId":mchtId]],"transactionAmount":["total":amt,"currency":"USD"]]
do{
let jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
payload = String(decoding: jsonData, as: UTF8.self)
print(payload)
let uuid: CFUUID = CFUUIDCreate(nil)
let nonce: CFString = CFUUIDCreateString(nil, uuid)
//Remove this swift will manage the memory managment.This line is causing crash
print("createdNonce:\(nonce)")
//HMAC calculation:
let msg = apiKey+(nonce as String)+timestamp+payload
if let msgData = msg.data(using: .utf8)
{
if let apiSecData = apiSecret.data(using: .utf8){
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
let digestBytes = UnsafeMutablePointer<UInt8>.allocate(capacity:digestLength)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), [UInt8](apiSecData), apiSecData.count, [UInt8](msgData), msgData.count, digestBytes)
//base64 output
let hmacData = Data(bytes: digestBytes, count: digestLength)
signature = hmacData.base64EncodedString()
//print("The HMAC signature in base64 is " + signature)
}
}
/*Payload formation for IPG Rest API*/
var request = URLRequest(url:URL(string: url)!)
request.addValue(apiKey, forHTTPHeaderField: "Api-Key")
request.addValue((nonce as String), forHTTPHeaderField: "Client-Request-Id")
request.addValue(timestamp, forHTTPHeaderField: "Timestamp")
request.addValue(signature, forHTTPHeaderField: "Message-Signature")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = jsonData
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let resData = data{
do{
self.definesPresentationContext = true
let res = try JSONSerialization.jsonObject(with: resData, options:[])
self.resString = "\(res)"
print(self.resString)
self.present(self.alert, animated: true){
self.alert.view.superview?.isUserInteractionEnabled = true
self.alert.view.superview?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.alertControllerBackgroundTapped)))
}
} catch {print(error)}
}
}.resume()
}catch{print(error)}
}catch{print("error:")}
/*
let status = PKPaymentAuthorizationStatus(rawValue: 0)!
self.transactionId = payment.token.transactionIdentifier
switch status.rawValue {
case 0:
self.status = "approved"
default:
self.status = "failed"
}*/
}
override func viewDidLoad() {
super.viewDidLoad()
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
//tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didSelect shippingMethod: PKShippingMethod, completion: @escaping (PKPaymentAuthorizationStatus, [PKPaymentSummaryItem]) -> Void) {
completion(.success,itemsToSell(shipping: Double(truncating: shippingMethod.amount)))
}
func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
controller.dismiss(animated: true, completion: nil)
self.alert.message = self.resString
self.present(self.alert, animated: true, completion: nil)
}
}