diff --git a/SwedbankPaySDK/Classes/Api/Helpers/TimeZone+OffsetFromGMT.swift b/SwedbankPaySDK/Classes/Api/Helpers/TimeZone+OffsetFromGMT.swift index 254de26..4d9f6814 100644 --- a/SwedbankPaySDK/Classes/Api/Helpers/TimeZone+OffsetFromGMT.swift +++ b/SwedbankPaySDK/Classes/Api/Helpers/TimeZone+OffsetFromGMT.swift @@ -22,4 +22,9 @@ extension TimeZone { localTimeZoneFormatter.dateFormat = "Z" return localTimeZoneFormatter.string(from: Date()) } + + func minutesFromGMT() -> String { + let minutes = (secondsFromGMT() / 60) + return String(minutes) + } } diff --git a/SwedbankPaySDK/Classes/Api/Models/IntegrationTask.swift b/SwedbankPaySDK/Classes/Api/Models/IntegrationTask.swift index 82a927f..c54927b 100644 --- a/SwedbankPaySDK/Classes/Api/Models/IntegrationTask.swift +++ b/SwedbankPaySDK/Classes/Api/Models/IntegrationTask.swift @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + struct IntegrationTask: Codable, Hashable { let rel: IntegrationTaskRel? let href: String? @@ -60,3 +62,20 @@ struct ExpectationModel: Codable, Hashable { let type: String? let value: String? } + +extension Array where Element == ExpectationModel { + var httpBody: Data? { + return self.filter({ $0.type == "string" }) + .compactMap({ + guard let name = $0.name else { + return nil + } + + let value = $0.value?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "" + + return name + "=" + value + }) + .joined(separator: "&") + .data(using: .utf8) + } +} diff --git a/SwedbankPaySDK/Classes/Api/Models/OperationOutputModel.swift b/SwedbankPaySDK/Classes/Api/Models/OperationOutputModel.swift index 081683e..0397133 100644 --- a/SwedbankPaySDK/Classes/Api/Models/OperationOutputModel.swift +++ b/SwedbankPaySDK/Classes/Api/Models/OperationOutputModel.swift @@ -19,6 +19,7 @@ struct OperationOutputModel: Codable, Hashable { let method: String? let next: Bool? let tasks: [IntegrationTask]? + let expects: [ExpectationModel]? } extension OperationOutputModel { diff --git a/SwedbankPaySDK/Classes/Api/Models/ProblemDetails.swift b/SwedbankPaySDK/Classes/Api/Models/ProblemDetails.swift index a7c3d7b..e224b15 100644 --- a/SwedbankPaySDK/Classes/Api/Models/ProblemDetails.swift +++ b/SwedbankPaySDK/Classes/Api/Models/ProblemDetails.swift @@ -20,6 +20,7 @@ public extension SwedbankPaySDK { public let title: String? public let status: Int32? public let detail: String? + public let originalDetail: String? let operation: OperationOutputModel? } diff --git a/SwedbankPaySDK/Classes/Api/SwedbankPayAPIConstants.swift b/SwedbankPaySDK/Classes/Api/SwedbankPayAPIConstants.swift index db0cb3a..c680243 100644 --- a/SwedbankPaySDK/Classes/Api/SwedbankPayAPIConstants.swift +++ b/SwedbankPaySDK/Classes/Api/SwedbankPayAPIConstants.swift @@ -22,8 +22,6 @@ struct SwedbankPayAPIConstants { static var requestTimeoutInterval = 10.0 static var sessionTimeoutInterval = 20.0 static var creditCardTimoutInterval = 30.0 - - static var notificationUrl = "https://fake.payex.com/notification" } private enum HTTPHeaderField: String { diff --git a/SwedbankPaySDK/Classes/Api/SwedbankPayAPIEnpointRouter.swift b/SwedbankPaySDK/Classes/Api/SwedbankPayAPIEnpointRouter.swift index c4a8003..d422c0d 100644 --- a/SwedbankPaySDK/Classes/Api/SwedbankPayAPIEnpointRouter.swift +++ b/SwedbankPaySDK/Classes/Api/SwedbankPayAPIEnpointRouter.swift @@ -16,6 +16,23 @@ import Foundation import UIKit +struct Endpoint { + let router: EnpointRouter? + let href: String? + let method: String? +} + +enum EnpointRouter { + case expandMethod(instrument: SwedbankPaySDK.PaymentAttemptInstrument) + case startPaymentAttempt(instrument: SwedbankPaySDK.PaymentAttemptInstrument, culture: String?) + case createAuthentication(methodCompletionIndicator: String, notificationUrl: String) + case completeAuthentication(cRes: String) + case getPayment + case preparePayment + case acknowledgeFailedAttempt + case abortPayment +} + protocol EndpointRouterProtocol { var body: [String: Any?]? { get } var requestTimeoutInterval: TimeInterval { get } @@ -23,19 +40,14 @@ protocol EndpointRouterProtocol { } struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { - let model: OperationOutputModel - let culture: String? - let instrument: SwedbankPaySDK.PaymentAttemptInstrument? - let methodCompletionIndicator: String? - let cRes: String? - + let endpoint: Endpoint let sessionStartTimestamp: Date var body: [String: Any?]? { - switch model.rel { - case .expandMethod: - return ["instrumentName": instrument?.identifier] - case .startPaymentAttempt: + switch endpoint.router { + case .expandMethod(instrument: let instrument): + return ["instrumentName": instrument.identifier] + case .startPaymentAttempt(let instrument, let culture): switch instrument { case .swish(let msisdn): return ["culture": culture, @@ -58,14 +70,6 @@ struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { "screenWidth": String(Int32(UIScreen.main.nativeBounds.width)), "screenColorDepth": String(24)] ] - case .none: - return ["culture": culture, - "client": ["userAgent": SwedbankPaySDK.VersionReporter.userAgent, - "ipAddress": NetworkStatusProvider.getAddress(for: .wifi) ?? NetworkStatusProvider.getAddress(for: .cellular) ?? "", - "screenHeight": String(Int32(UIScreen.main.nativeBounds.height)), - "screenWidth": String(Int32(UIScreen.main.nativeBounds.width)), - "screenColorDepth": String(24)] - ] } case .preparePayment: return ["integration": "HostedView", @@ -76,15 +80,15 @@ struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { "screenWidth": String(Int32(UIScreen.main.nativeBounds.width)), "screenColorDepth": String(24)], "browser": ["acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "languageHeader": Locale.current.identifier, - "timeZoneOffset": TimeZone.current.offsetFromGMT(), + "languageHeader": Locale.current.identifier.replacingOccurrences(of: "_", with: "-"), + "timeZoneOffset": TimeZone.current.minutesFromGMT(), "javascriptEnabled": true], "service": ["name": "SwedbankPaySDK-iOS", "version": SwedbankPaySDK.VersionReporter.currentVersion] ] - case .createAuthentication: - return ["methodCompletionIndicator": methodCompletionIndicator ?? "N", - "notificationUrl": SwedbankPayAPIConstants.notificationUrl, + case .createAuthentication(let methodCompletionIndicator, let notificationUrl): + return ["methodCompletionIndicator": methodCompletionIndicator, + "notificationUrl": notificationUrl, "requestWindowSize": "FULLSCREEN", "client": ["userAgent": SwedbankPaySDK.VersionReporter.userAgent, "ipAddress": NetworkStatusProvider.getAddress(for: .wifi) ?? NetworkStatusProvider.getAddress(for: .cellular) ?? "", @@ -92,12 +96,12 @@ struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { "screenWidth": String(Int32(UIScreen.main.nativeBounds.width)), "screenColorDepth": String(24)], "browser": ["acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "languageHeader": Locale.current.identifier, - "timeZoneOffset": TimeZone.current.offsetFromGMT(), + "languageHeader": Locale.current.identifier.replacingOccurrences(of: "_", with: "-"), + "timeZoneOffset": TimeZone.current.minutesFromGMT(), "javascriptEnabled": true] ] - case .completeAuthentication: - return ["cRes": cRes ?? "", + case .completeAuthentication(let cRes): + return ["cRes": cRes, "client": ["userAgent": SwedbankPaySDK.VersionReporter.userAgent, "ipAddress": NetworkStatusProvider.getAddress(for: .wifi) ?? NetworkStatusProvider.getAddress(for: .cellular) ?? ""], ] @@ -107,8 +111,8 @@ struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { } var requestTimeoutInterval: TimeInterval { - switch model.rel { - case .startPaymentAttempt: + switch endpoint.router { + case .startPaymentAttempt(let instrument, _): switch instrument { case .creditCard: return SwedbankPayAPIConstants.creditCardTimoutInterval @@ -124,8 +128,8 @@ struct SwedbankPayAPIEnpointRouter: EndpointRouterProtocol { } var sessionTimeoutInterval: TimeInterval { - switch model.rel { - case .startPaymentAttempt: + switch endpoint.router { + case .startPaymentAttempt(let instrument, _): switch instrument { case .creditCard: return SwedbankPayAPIConstants.creditCardTimoutInterval @@ -174,7 +178,7 @@ extension SwedbankPayAPIEnpointRouter { } private func requestWithDataResponse(requestStartTimestamp: Date, handler: @escaping (Result) -> Void) { - guard let href = model.href, + guard let href = endpoint.href, var components = URLComponents(string: href) else { handler(.failure(SwedbankPayAPIError.invalidUrl)) return @@ -190,7 +194,7 @@ extension SwedbankPayAPIEnpointRouter { } var request = URLRequest(url: url) - request.httpMethod = model.method + request.httpMethod = endpoint.method request.allHTTPHeaderFields = SwedbankPayAPIConstants.commonHeaders request.timeoutInterval = requestTimeoutInterval @@ -213,8 +217,8 @@ extension SwedbankPayAPIEnpointRouter { } BeaconService.shared.log(type: .httpRequest(duration: Int32((Date().timeIntervalSince(requestStartTimestamp) * 1000.0).rounded()), - requestUrl: model.href ?? "", - method: model.method ?? "", + requestUrl: endpoint.href ?? "", + method: endpoint.method ?? "", responseStatusCode: responseStatusCode, values: values)) diff --git a/SwedbankPaySDK/Classes/SwedbankPayPaymentSession.swift b/SwedbankPaySDK/Classes/SwedbankPayPaymentSession.swift index d590d27..5dddd2d 100644 --- a/SwedbankPaySDK/Classes/SwedbankPayPaymentSession.swift +++ b/SwedbankPaySDK/Classes/SwedbankPayPaymentSession.swift @@ -73,6 +73,7 @@ public extension SwedbankPaySDK { private var hasShownProblemDetails: [ProblemDetails] = [] private var scaMethodRequestDataPerformed: [(name: String, value: String)] = [] private var scaRedirectDataPerformed: [(name: String, value: String)] = [] + private var notificationUrl: String? = nil private var sessionStartTimestamp = Date() @@ -107,6 +108,7 @@ public extension SwedbankPaySDK { hasShownProblemDetails = [] scaMethodRequestDataPerformed = [] scaRedirectDataPerformed = [] + notificationUrl = nil hasShownAvailableInstruments = false if automaticConfiguration { @@ -117,10 +119,11 @@ public extension SwedbankPaySDK { href: sessionURL.absoluteString, method: "GET", next: nil, - tasks: nil) + tasks: nil, + expects: nil) sessionStartTimestamp = Date() - makeRequest(operationOutputModel: model) + makeRequest(router: nil, operation: model) BeaconService.shared.clear() BeaconService.shared.log(type: .sdkMethodInvoked(name: "startPaymentSession", @@ -152,10 +155,17 @@ public extension SwedbankPaySDK { .first(where: { $0.rel == .expandMethod || $0.rel == .startPaymentAttempt || $0.rel == .getPayment }) { sessionStartTimestamp = Date() - makeRequest(operationOutputModel: operation, culture: ongoingModel.paymentSession.culture) - - if operation.rel == .startPaymentAttempt { + + switch operation.rel { + case .expandMethod: + makeRequest(router: .expandMethod(instrument: instrument), operation: operation) + case .startPaymentAttempt: + makeRequest(router: .startPaymentAttempt(instrument: instrument, culture: ongoingModel.paymentSession.culture), operation: operation) self.instrument = nil + case .getPayment: + makeRequest(router: .getPayment, operation: operation) + default: + fatalError("Operantion rel is not supported for makeNativePaymentAttempt: \(String(describing: operation.rel))") } succeeded = true @@ -249,7 +259,7 @@ public extension SwedbankPaySDK { if let operation = ongoingModel.operations? .first(where: { $0.rel == .abortPayment }) { sessionStartTimestamp = Date() - makeRequest(operationOutputModel: operation, culture: ongoingModel.paymentSession.culture) + makeRequest(router: .abortPayment, operation: operation) succeeded = true } @@ -258,17 +268,13 @@ public extension SwedbankPaySDK { values: nil)) } - private func makeRequest(operationOutputModel: OperationOutputModel, culture: String? = nil, methodCompletionIndicator: String? = nil, cRes: String? = nil) { - SwedbankPayAPIEnpointRouter(model: operationOutputModel, - culture: culture, - instrument: instrument, - methodCompletionIndicator: methodCompletionIndicator, - cRes: cRes, + private func makeRequest(router: EnpointRouter?, operation: OperationOutputModel) { + SwedbankPayAPIEnpointRouter(endpoint: Endpoint(router: router, href: operation.href, method: operation.method), sessionStartTimestamp: sessionStartTimestamp).makeRequest { result in switch result { case .success(let success): if let paymentOutputModel = success { - if self.automaticConfiguration, operationOutputModel.rel == nil { + if self.automaticConfiguration, router == nil { guard let urls = paymentOutputModel.paymentSession.urls, urls.completeUrl != nil, urls.hostUrls != nil else { self.delegate?.sdkProblemOccurred(problem: .automaticConfigurationFailed) @@ -299,11 +305,7 @@ public extension SwedbankPaySDK { let problem = SwedbankPaySDK.PaymentSessionProblem.paymentSessionAPIRequestFailed(error: failure, retry: { self.sessionStartTimestamp = Date() - self.makeRequest(operationOutputModel: operationOutputModel, - culture: culture, - methodCompletionIndicator: - methodCompletionIndicator, - cRes: cRes) + self.makeRequest(router: router, operation: operation) }) self.delegate?.sdkProblemOccurred(problem: problem) @@ -386,7 +388,8 @@ public extension SwedbankPaySDK { } } - makeRequest(operationOutputModel: problemOperation, culture: culture) + makeRequest(router: .acknowledgeFailedAttempt, operation: problemOperation) + } let operations = paymentOutputModel.prioritisedOperations @@ -394,14 +397,14 @@ public extension SwedbankPaySDK { print("\(operations.compactMap({ $0.rel }))") if let preparePayment = operations.first(where: { $0.rel == .preparePayment }) { - makeRequest(operationOutputModel: preparePayment, culture: culture) + makeRequest(router: .preparePayment, operation: preparePayment) } else if operations.contains(where: { $0.rel == .startPaymentAttempt }), let instrument = instrument, let startPaymentAttempt = ongoingModel?.paymentSession.methods? .first(where: { $0.name == instrument.identifier })?.operations? .first(where: { $0.rel == .startPaymentAttempt }) { - makeRequest(operationOutputModel: startPaymentAttempt, culture: culture) + makeRequest(router: .startPaymentAttempt(instrument: instrument, culture: culture), operation: startPaymentAttempt) self.instrument = nil } else if let launchClientApp = operations.first(where: { $0.firstTask(with: .launchClientApp) != nil }), let tasks = launchClientApp.firstTask(with: .launchClientApp), @@ -409,14 +412,15 @@ public extension SwedbankPaySDK { self.launchClientApp(task: launchClientApp.firstTask(with: .launchClientApp)!) } else if let scaMethodRequest = operations.first(where: { $0.firstTask(with: .scaMethodRequest) != nil }), let task = scaMethodRequest.firstTask(with: .scaMethodRequest), - !scaMethodRequestDataPerformed.contains(where: { $0.name == task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value }) { + task.href != nil, + !scaMethodRequestDataPerformed.contains(where: { $0.name == task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "null" }) { DispatchQueue.main.async { self.webViewService.load(task: task) { result in switch result { case .success: - self.scaMethodRequestDataPerformed.append((name: task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "", value: "Y")) + self.scaMethodRequestDataPerformed.append((name: task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "null", value: "Y")) case .failure(let error): - self.scaMethodRequestDataPerformed.append((name: task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "", value: "N")) + self.scaMethodRequestDataPerformed.append((name: task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "null", value: "N")) } if let model = self.ongoingModel { @@ -425,13 +429,23 @@ public extension SwedbankPaySDK { } } } else if let createAuthentication = operations.first(where: { $0.rel == .createAuthentication }), - let task = createAuthentication.firstTask(with: .scaMethodRequest), - let scaMethod = scaMethodRequestDataPerformed.first(where: { $0.name == task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value }) { - makeRequest(operationOutputModel: createAuthentication, culture: culture, methodCompletionIndicator: scaMethod.value) + let notificationUrl = createAuthentication.expects?.first(where: { $0.name == "NotificationUrl" })?.value { + self.notificationUrl = notificationUrl + + if let task = createAuthentication.firstTask(with: .scaMethodRequest), + let scaMethod = scaMethodRequestDataPerformed.first(where: { $0.name == task.expects?.first(where: { $0.name == "threeDSMethodData" })?.value ?? "null" }) { + makeRequest(router: .createAuthentication(methodCompletionIndicator: scaMethod.value, notificationUrl: notificationUrl), operation: createAuthentication) + } else if let methodCompletionIndicator = createAuthentication.expects?.first(where: { $0.name == "methodCompletionIndicator" })?.value { + makeRequest(router: .createAuthentication(methodCompletionIndicator: methodCompletionIndicator, notificationUrl: notificationUrl), operation: createAuthentication) + } else { + makeRequest(router: .createAuthentication(methodCompletionIndicator: "U", notificationUrl: notificationUrl), operation: createAuthentication) + } } else if let operation = operations.first(where: { $0.firstTask(with: .scaRedirect) != nil }), let task = operation.firstTask(with: .scaRedirect), !scaRedirectDataPerformed.contains(where: { $0.name == task.expects?.first(where: { $0.name == "creq" })?.value }) { DispatchQueue.main.async { + self.webViewController.notificationUrl = self.notificationUrl + self.delegate?.show3DSecureViewController(viewController: self.webViewController) BeaconService.shared.log(type: .sdkCallbackInvoked(name: "show3DSecureViewController", @@ -443,7 +457,7 @@ public extension SwedbankPaySDK { } else if let completeAuthentication = operations.first(where: { $0.rel == .completeAuthentication }), let task = completeAuthentication.tasks?.first(where: { $0.expects?.contains(where: { $0.name == "creq" } ) ?? false } ), let scaRedirect = scaRedirectDataPerformed.first(where: { $0.name == task.expects?.first(where: { $0.name == "creq" })?.value }) { - makeRequest(operationOutputModel: completeAuthentication, culture: culture, cRes: scaRedirect.value) + makeRequest(router: .completeAuthentication(cRes: scaRedirect.value), operation: completeAuthentication) } else if let redirectPayer = operations.first(where: { $0.rel == .redirectPayer }) { DispatchQueue.main.async { if redirectPayer.href == self.orderInfo?.cancelUrl?.absoluteString { @@ -471,6 +485,7 @@ public extension SwedbankPaySDK { hasShownProblemDetails = [] scaMethodRequestDataPerformed = [] scaRedirectDataPerformed = [] + notificationUrl = nil hasShownAvailableInstruments = false } else if (operations.contains(where: { $0.rel == .expandMethod }) || operations.contains(where: { $0.rel == .startPaymentAttempt })) && hasShownAvailableInstruments == false { @@ -497,7 +512,7 @@ public extension SwedbankPaySDK { } else if let getPayment = operations.first(where: { $0.rel == .getPayment }) { DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { self.sessionStartTimestamp = Date() - self.makeRequest(operationOutputModel: getPayment, culture: culture) + self.makeRequest(router: .getPayment, operation: getPayment) } } else if !hasShowedError { DispatchQueue.main.async { @@ -510,7 +525,7 @@ public extension SwedbankPaySDK { } } - func handleCallbackUrl(_ url: URL) -> Bool { + internal func handleCallbackUrl(_ url: URL) -> Bool { guard url == orderInfo?.paymentUrl else { return false } @@ -519,7 +534,7 @@ public extension SwedbankPaySDK { if let operation = ongoingModel.paymentSession.allMethodOperations .first(where: { $0.rel == .getPayment }) { sessionStartTimestamp = Date() - makeRequest(operationOutputModel: operation, culture: ongoingModel.paymentSession.culture) + makeRequest(router: .getPayment, operation: operation) } } @@ -528,7 +543,7 @@ public extension SwedbankPaySDK { return true } - func scaRedirectDataPerformed(task: IntegrationTask, culture: String?) { + private func scaRedirectDataPerformed(task: IntegrationTask, culture: String?) { self.webViewController.load(task: task) { result in switch result { case .success(let value): diff --git a/SwedbankPaySDK/Classes/WebView/SCAWebViewService.swift b/SwedbankPaySDK/Classes/WebView/SCAWebViewService.swift index 356fa11..e933ab3 100644 --- a/SwedbankPaySDK/Classes/WebView/SCAWebViewService.swift +++ b/SwedbankPaySDK/Classes/WebView/SCAWebViewService.swift @@ -45,19 +45,8 @@ class SCAWebViewService: NSObject, WKNavigationDelegate { request.allHTTPHeaderFields = ["Content-Type": task.contentType ?? ""] request.timeoutInterval = SwedbankPayAPIConstants.creditCardTimoutInterval - if let bodyString = task.expects? - .filter({ $0.type == "string" }) - .compactMap({ - guard let name = $0.name, - let value = $0.value?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else { - return nil - } - - return name + "=" + value - }) - .joined(separator: "&") { - - request.httpBody = bodyString.data(using: .utf8) + if let httpBody = task.expects?.httpBody { + request.httpBody = httpBody } webView?.navigationDelegate = self diff --git a/SwedbankPaySDK/Classes/WebView/SwedbankPaySCAWebViewController.swift b/SwedbankPaySDK/Classes/WebView/SwedbankPaySCAWebViewController.swift index c366619..768ecab 100644 --- a/SwedbankPaySDK/Classes/WebView/SwedbankPaySCAWebViewController.swift +++ b/SwedbankPaySDK/Classes/WebView/SwedbankPaySCAWebViewController.swift @@ -48,6 +48,8 @@ class SwedbankPaySCAWebViewController: UIViewController { let activityView = UIActivityIndicatorView() + var notificationUrl: String? + init() { let preferences = WKPreferences() preferences.javaScriptEnabled = true @@ -90,19 +92,8 @@ class SwedbankPaySCAWebViewController: UIViewController { request.allHTTPHeaderFields = ["Content-Type": task.contentType ?? ""] request.timeoutInterval = SwedbankPayAPIConstants.creditCardTimoutInterval - if let bodyString = task.expects? - .filter({ $0.type == "string" }) - .compactMap({ - guard let name = $0.name, - let value = $0.value?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else { - return nil - } - - return name + "=" + value - }) - .joined(separator: "&") { - - request.httpBody = bodyString.data(using: .utf8) + if let httpBody = task.expects?.httpBody { + request.httpBody = httpBody } let navigation = webView.load(request) @@ -159,7 +150,7 @@ extension SwedbankPaySCAWebViewController: WKNavigationDelegate { ) { let request = navigationAction.request - if request.url?.absoluteString == SwedbankPayAPIConstants.notificationUrl, + if request.url?.absoluteString == self.notificationUrl, let httpBody = request.httpBody, let bodyString = String(data: httpBody, encoding: .utf8), let urlComponents = URLComponents(string: "https://www.apple.com?\(bodyString)"),