Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ad-hoc): backport reworked 3DS #354

Merged
merged 18 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ final class AlternativePaymentsInteractor {
source: response.gatewayToken,
allowFallbackToSale: true
)
let threeDSService = POTest3DSService(returnUrl: Example.Constants.returnUrl)
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(request: authorizationRequest, threeDSService: threeDSService)
}

Expand All @@ -132,7 +132,7 @@ final class AlternativePaymentsInteractor {
tokenId: token.id,
source: try await alternativePaymentsService.tokenize(request: tokenizationRequest).gatewayToken
)
let threeDSService = POTest3DSService(returnUrl: Example.Constants.returnUrl)
let threeDSService = POTest3DSService()
return try await tokensService.assignCustomerToken(request: tokenAssignRequest, threeDSService: threeDSService)
}

Expand All @@ -142,7 +142,7 @@ final class AlternativePaymentsInteractor {
source: customerToken.id,
allowFallbackToSale: true
)
let threeDSService = POTest3DSService(returnUrl: Example.Constants.returnUrl)
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(request: invoiceAuthorizationRequest, threeDSService: threeDSService)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ final class ApplePayViewModel: ObservableObject {
let authorizationRequest = POInvoiceAuthorizationRequest(
invoiceId: invoice.id, source: card.id
)
let threeDSService = POTest3DSService(returnUrl: Constants.returnUrl)
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(
request: authorizationRequest, threeDSService: threeDSService
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Combine
import SwiftUI
@_spi(PO) import ProcessOut
import ProcessOutUI
import ProcessOutCheckout3DS

@MainActor
final class CardPaymentViewModel: ObservableObject {
Expand Down Expand Up @@ -38,7 +37,7 @@ final class CardPaymentViewModel: ObservableObject {
private func commonInit() {
state = .init(
authenticationService: .init(
sources: [.test, .checkout], id: \.self, selection: .test
sources: [.test], id: \.self, selection: .test
),
cardTokenization: nil
)
Expand Down Expand Up @@ -92,36 +91,12 @@ extension CardPaymentViewModel: POCardTokenizationDelegate {
saveSource: save,
clientSecret: invoice.clientSecret
)
let threeDSService: PO3DSService
switch state.authenticationService.selection {
case .test:
threeDSService = POTest3DSService(returnUrl: Constants.returnUrl)
case .checkout:
threeDSService = POCheckout3DSServiceBuilder()
.with(delegate: self)
.with(environment: .sandbox)
.build()
}
// todo(andrii-vysotskyi): allow selecting Checkout 3DS service when build issue is resolved.
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(request: invoiceAuthorizationRequest, threeDSService: threeDSService)
}
}

extension CardPaymentViewModel: POCheckout3DSServiceDelegate {

func handle(redirect: PO3DSRedirect, completion: @escaping (Result<String, POFailure>) -> Void) {
Task { @MainActor in
let session = POWebAuthenticationSession(
redirect: redirect, returnUrl: Constants.returnUrl, completion: completion
)
if await session.start() {
return
}
let failure = POFailure(message: "Unable to process redirect", code: .generic(.mobile))
completion(.failure(failure))
}
}
}

extension CardPaymentViewModel {

/// Convenience initializer that resolves its dependencies automatically.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ extension DynamicCheckoutViewModel: PODynamicCheckoutDelegate {

func dynamicCheckout(
willAuthorizeInvoiceWith request: inout POInvoiceAuthorizationRequest
) async -> any PO3DSService {
POTest3DSService(returnUrl: Constants.returnUrl)
) async -> any PO3DS2Service {
POTest3DSService()
}

func dynamicCheckout(willAuthorizeInvoiceWith request: PKPaymentRequest) async {
Expand Down
6 changes: 3 additions & 3 deletions Example/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ settings:
packages:
ProcessOutUI:
path: ../
ProcessOutCheckout3DS:
path: ../
# ProcessOutCheckout3DS:
# path: ../

targets:
Example:
Expand All @@ -34,7 +34,7 @@ targets:
PRODUCT_BUNDLE_IDENTIFIER: com.processout.processout-example
dependencies:
- package: ProcessOutUI
- package: ProcessOutCheckout3DS
# - package: ProcessOutCheckout3DS
ExampleUiTests:
type: bundle.ui-testing
sources: ExampleUiTests
Expand Down
13 changes: 8 additions & 5 deletions Sources/ProcessOut/Sources/Api/ProcessOut.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public final class ProcessOut {
/// Returns invoices service.
public private(set) lazy var invoices: POInvoicesService = {
let repository = HttpInvoicesRepository(connector: httpConnector)
return DefaultInvoicesService(repository: repository, threeDSService: threeDSService, logger: serviceLogger)
return DefaultInvoicesService(
repository: repository, customerActionsService: customerActionsService, logger: serviceLogger
)
}()

/// Returns alternative payment methods service.
Expand All @@ -37,7 +39,6 @@ public final class ProcessOut {
let configuration = self.configuration
return .init(projectId: configuration.projectId, baseUrl: configuration.environment.checkoutBaseUrl)
}
let webSession = DefaultWebAuthenticationSession()
return DefaultAlternativePaymentsService(
configuration: serviceConfiguration, webSession: webSession, logger: serviceLogger
)
Expand Down Expand Up @@ -69,7 +70,7 @@ public final class ProcessOut {
public private(set) lazy var customerTokens: POCustomerTokensService = {
let repository = HttpCustomerTokensRepository(connector: httpConnector)
return DefaultCustomerTokensService(
repository: repository, threeDSService: threeDSService, logger: serviceLogger
repository: repository, customerActionsService: customerActionsService, logger: serviceLogger
)
}()

Expand Down Expand Up @@ -144,15 +145,17 @@ public final class ProcessOut {
)
}()

private lazy var threeDSService: ThreeDSService = {
private lazy var customerActionsService: CustomerActionsService = {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .useDefaultKeys
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .base64
encoder.keyEncodingStrategy = .useDefaultKeys
return DefaultThreeDSService(decoder: decoder, encoder: encoder)
return DefaultCustomerActionsService(decoder: decoder, encoder: encoder, webSession: webSession)
}()

private let webSession = DefaultWebAuthenticationSession()

// MARK: - Private Methods

private init(configuration: ProcessOutConfiguration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ public final class POTest3DSService: PO3DSService {

/// Creates service instance.
@_disfavoredOverload
public init(returnUrl: URL) {
self.returnUrl = returnUrl
@available(*, deprecated, message: "Use init that doesn't require arguments.")
public nonisolated init(returnUrl: URL) {
// Ignored
}

nonisolated init() {
// Ignored
}

/// View controller to use for presentations.
Expand Down Expand Up @@ -51,21 +56,4 @@ public final class POTest3DSService: PO3DSService {
alertController.addAction(rejectAction)
viewController.present(alertController, animated: true)
}

public func handle(redirect: PO3DSRedirect, completion: @escaping (Result<String, POFailure>) -> Void) {
let viewController = PO3DSRedirectViewControllerBuilder()
.with(redirect: redirect)
.with(returnUrl: returnUrl)
.with { [weak self] result in
self?.viewController.presentedViewController?.dismiss(animated: true) {
completion(result)
}
}
.build()
self.viewController.present(viewController, animated: true)
}

// MARK: - Private Properties

private let returnUrl: URL
}
4 changes: 2 additions & 2 deletions Sources/ProcessOut/Sources/Generated/Sourcery+Generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ extension POCustomerTokensService {
@discardableResult
public func assignCustomerToken(
request: POAssignCustomerTokenRequest,
threeDSService: PO3DSService,
threeDSService: PO3DS2Service,
completion: @escaping (Result<POCustomerToken, POFailure>) -> Void
) -> POCancellable {
invoke(completion: completion) {
Expand Down Expand Up @@ -318,7 +318,7 @@ extension POInvoicesService {
@discardableResult
public func authorizeInvoice(
request: POInvoiceAuthorizationRequest,
threeDSService: PO3DSService,
threeDSService: PO3DS2Service,
completion: @escaping (Result<Void, POFailure>) -> Void
) -> POCancellable {
invoke(completion: completion) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
struct AssignCustomerTokenResponse: Decodable {

/// Optional customer action.
let customerAction: ThreeDSCustomerAction?
let customerAction: _CustomerAction?

/// Token information.
let token: POCustomerToken?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ final class HttpInvoicesRepository: InvoicesRepository {
return try await connector.execute(request: httpRequest).invoice
}

func authorizeInvoice(request: POInvoiceAuthorizationRequest) async throws -> ThreeDSCustomerAction? {
func authorizeInvoice(request: POInvoiceAuthorizationRequest) async throws -> _CustomerAction? {
struct Response: Decodable {
let customerAction: ThreeDSCustomerAction?
let customerAction: _CustomerAction?
}
let headers = [
"X-Processout-Client-Secret": request.clientSecret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protocol InvoicesRepository: PORepository {
func invoice(request: POInvoiceRequest) async throws -> POInvoice

/// Performs invoice authorization with given request.
func authorizeInvoice(request: POInvoiceAuthorizationRequest) async throws -> ThreeDSCustomerAction?
func authorizeInvoice(request: POInvoiceAuthorizationRequest) async throws -> _CustomerAction?

/// Captures native alternative payment.
func captureNativeAlternativePayment(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//
// ThreeDSCustomerAction.swift
// CustomerAction.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 18.10.2022.
//

import Foundation

struct ThreeDSCustomerAction: Decodable {
// todo(andrii-vysotskyi): remove underscore when legacy codebase is removed.
struct _CustomerAction: Decodable { // swiftlint:disable:this type_name

enum ActionType: String, Decodable {

Expand Down
58 changes: 0 additions & 58 deletions Sources/ProcessOut/Sources/Services/3DS/PO3DSService.swift

This file was deleted.

17 changes: 0 additions & 17 deletions Sources/ProcessOut/Sources/Services/3DS/ThreeDSService.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// CustomerActionsService.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 02.11.2022.
//

protocol CustomerActionsService {

/// Implementation should attempt to handle given customer action.
/// - Parameters:
/// - action: customer action to handle.
/// - threeDSService: delegate that would perform 3DS2 handling
func handle(action: _CustomerAction, threeDSService: PO3DS2Service) async throws -> String
}
Loading
Loading