diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAPIClient.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAPIClient.swift index 7a1a74c641f..beeeb98e87e 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAPIClient.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAPIClient.swift @@ -252,7 +252,8 @@ protocol FinancialConnectionsAPI { phoneNumber: String?, country: String?, consumerSessionClientSecret: String?, - clientSecret: String + clientSecret: String, + isRelink: Bool ) -> Future func disableNetworking( @@ -768,7 +769,8 @@ extension FinancialConnectionsAPIClient: FinancialConnectionsAPI { phoneNumber: String?, country: String?, consumerSessionClientSecret: String?, - clientSecret: String + clientSecret: String, + isRelink: Bool ) -> Future { let saveAccountsToLinkHandler: () -> Future = { return self.saveAccountsToLink( @@ -780,10 +782,11 @@ extension FinancialConnectionsAPIClient: FinancialConnectionsAPI { clientSecret: clientSecret ) .chained { manifest in + let customSuccessPaneMessage = isRelink ? nil : manifest.displayText?.successPane?.subCaption return Promise( value: ( manifest: manifest, - customSuccessPaneMessage: manifest.displayText?.successPane?.subCaption + customSuccessPaneMessage: customSuccessPaneMessage ) ) } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient+Legacy.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient+Legacy.swift index 92fa6544bff..bc4eb9109e2 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient+Legacy.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient+Legacy.swift @@ -252,7 +252,8 @@ extension FinancialConnectionsAsyncAPIClient: FinancialConnectionsAPI { phoneNumber: String?, country: String?, consumerSessionClientSecret: String?, - clientSecret: String + clientSecret: String, + isRelink: Bool ) -> Future<(manifest: FinancialConnectionsSessionManifest, customSuccessPaneMessage: String?)> { wrapAsyncToFuture { try await self.saveAccountsToNetworkAndLink( @@ -262,7 +263,8 @@ extension FinancialConnectionsAsyncAPIClient: FinancialConnectionsAPI { phoneNumber: phoneNumber, country: country, consumerSessionClientSecret: consumerSessionClientSecret, - clientSecret: clientSecret + clientSecret: clientSecret, + isRelink: isRelink ) } } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient.swift index f97d02b4f8a..91b13c603ec 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/API Bindings/FinancialConnectionsAsyncAPIClient.swift @@ -272,7 +272,8 @@ protocol FinancialConnectionsAsyncAPI { phoneNumber: String?, country: String?, consumerSessionClientSecret: String?, - clientSecret: String + clientSecret: String, + isRelink: Bool ) async throws -> ( manifest: FinancialConnectionsSessionManifest, customSuccessPaneMessage: String? @@ -713,7 +714,8 @@ extension FinancialConnectionsAsyncAPIClient: FinancialConnectionsAsyncAPI { phoneNumber: String?, country: String?, consumerSessionClientSecret: String?, - clientSecret: String + clientSecret: String, + isRelink: Bool ) async throws -> ( manifest: FinancialConnectionsSessionManifest, customSuccessPaneMessage: String? @@ -730,10 +732,12 @@ extension FinancialConnectionsAsyncAPIClient: FinancialConnectionsAsyncAPI { consumerSessionClientSecret: consumerSessionClientSecret, clientSecret: clientSecret ) + + let customSuccessPaneMessage = isRelink ? nil : manifest.displayText?.successPane?.subCaption return ( manifest: manifest, - customSuccessPaneMessage: manifest.displayText?.successPane?.subCaption + customSuccessPaneMessage: customSuccessPaneMessage ) } if diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/AccountPicker/AccountPickerDataSource.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/AccountPicker/AccountPickerDataSource.swift index 5a7daa407ec..3ac9b59eb19 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/AccountPicker/AccountPickerDataSource.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/AccountPicker/AccountPickerDataSource.swift @@ -49,6 +49,7 @@ final class AccountPickerDataSourceImplementation: AccountPickerDataSource { let reduceManualEntryProminenceInErrors: Bool let dataAccessNotice: FinancialConnectionsDataAccessNotice? let consumerSessionClientSecret: String? + private let isRelink: Bool private(set) var selectedAccounts: [FinancialConnectionsPartnerAccount] = [] { didSet { @@ -67,7 +68,8 @@ final class AccountPickerDataSourceImplementation: AccountPickerDataSource { analyticsClient: FinancialConnectionsAnalyticsClient, reduceManualEntryProminenceInErrors: Bool, dataAccessNotice: FinancialConnectionsDataAccessNotice?, - consumerSessionClientSecret: String? + consumerSessionClientSecret: String?, + isRelink: Bool ) { self.apiClient = apiClient self.clientSecret = clientSecret @@ -79,6 +81,7 @@ final class AccountPickerDataSourceImplementation: AccountPickerDataSource { self.reduceManualEntryProminenceInErrors = reduceManualEntryProminenceInErrors self.dataAccessNotice = dataAccessNotice self.consumerSessionClientSecret = consumerSessionClientSecret + self.isRelink = isRelink } func pollAuthSessionAccounts() -> Future { @@ -117,7 +120,8 @@ final class AccountPickerDataSourceImplementation: AccountPickerDataSource { phoneNumber: nil, country: nil, consumerSessionClientSecret: consumerSessionClientSecret, - clientSecret: clientSecret + clientSecret: clientSecret, + isRelink: isRelink ) .chained { (_, customSuccessPaneMessage) in return Promise(value: customSuccessPaneMessage) diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift index f916f501ced..f03537b00a2 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift @@ -393,9 +393,7 @@ extension NativeFlowController { ) finishAuthSession(.failed(error: FinancialConnectionsCustomManualEntryRequiredError())) } else { - if !session.accounts.data.isEmpty || session.paymentAccount != nil - || session.bankAccountToken != nil - { + if session.didCompleteSuccessfully || dataManager.pendingRelinkAuthorization != nil { if dataManager.manifest.isProductInstantDebits { // For Instant Debits, create a payment method and complete with it. createPaymentMethod(for: session) { result in @@ -1176,7 +1174,7 @@ extension NativeFlowController: LinkAccountPickerViewControllerDelegate { forAuthorization authorization: String ) { dataManager.institution = institution - dataManager.pendingRepairAuthorization = authorization + dataManager.pendingRelinkAuthorization = authorization pushPane(.bankAuthRepair, animated: true, clearNavigationStack: true) } @@ -1388,7 +1386,8 @@ private func CreatePaneViewController( analyticsClient: dataManager.analyticsClient, reduceManualEntryProminenceInErrors: dataManager.reduceManualEntryProminenceInErrors, dataAccessNotice: dataManager.consentPaneModel?.dataAccessNotice, - consumerSessionClientSecret: dataManager.consumerSession?.clientSecret + consumerSessionClientSecret: dataManager.consumerSession?.clientSecret, + isRelink: dataManager.pendingRelinkAuthorization != nil ) let accountPickerViewController = AccountPickerViewController(dataSource: accountPickerDataSource) accountPickerViewController.delegate = nativeFlowController @@ -1422,12 +1421,12 @@ private func CreatePaneViewController( viewController = nil } case .bankAuthRepair: - if let institution = dataManager.institution, let coreAuthorization = dataManager.pendingRepairAuthorization { + if let institution = dataManager.institution, let relinkAuthorization = dataManager.pendingRelinkAuthorization { let partnerAuthDataSource = PartnerAuthDataSourceImplementation( authSession: dataManager.authSession, institution: institution, manifest: dataManager.manifest, - repairSessionPayload: RelinkSessionPayload(coreAuthorization: coreAuthorization), + relinkAuthorization: relinkAuthorization, returnURL: dataManager.returnURL, apiClient: dataManager.apiClient, clientSecret: dataManager.clientSecret, @@ -1603,7 +1602,7 @@ private func CreatePaneViewController( authSession: dataManager.authSession, institution: institution, manifest: dataManager.manifest, - repairSessionPayload: nil, + relinkAuthorization: nil, returnURL: dataManager.returnURL, apiClient: dataManager.apiClient, clientSecret: dataManager.clientSecret, @@ -1765,3 +1764,10 @@ private func ShouldHideLogoInNavigationBar( return reducedBranding } } + +private extension StripeAPI.FinancialConnectionsSession { + + var didCompleteSuccessfully: Bool { + return !accounts.data.isEmpty || paymentAccount != nil || bankAccountToken != nil + } +} diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowDataManager.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowDataManager.swift index 126c877af13..19811703fa7 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowDataManager.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowDataManager.swift @@ -36,7 +36,7 @@ protocol NativeFlowDataManager: AnyObject { var lastPaneLaunched: FinancialConnectionsSessionManifest.NextPane? { get set } var customSuccessPaneCaption: String? { get set } var customSuccessPaneSubCaption: String? { get set } - var pendingRepairAuthorization: String? { get set } + var pendingRelinkAuthorization: String? { get set } func createPaymentDetails( consumerSessionClientSecret: String, @@ -99,7 +99,7 @@ class NativeFlowAPIDataManager: NativeFlowDataManager { var lastPaneLaunched: FinancialConnectionsSessionManifest.NextPane? var customSuccessPaneCaption: String? var customSuccessPaneSubCaption: String? - var pendingRepairAuthorization: String? + var pendingRelinkAuthorization: String? var consumerSession: ConsumerSessionData? { didSet { diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkSignupPane/NetworkingLinkSignupDataSource.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkSignupPane/NetworkingLinkSignupDataSource.swift index 0399ddb28cb..fe05391bd5e 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkSignupPane/NetworkingLinkSignupDataSource.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkSignupPane/NetworkingLinkSignupDataSource.swift @@ -111,7 +111,8 @@ final class NetworkingLinkSignupDataSourceImplementation: NetworkingLinkSignupDa phoneNumber: nil, country: nil, consumerSessionClientSecret: response.consumerSession.clientSecret, - clientSecret: clientSecret + clientSecret: clientSecret, + isRelink: false ) } .chained { (_, customSuccessPaneMessage) in @@ -125,7 +126,8 @@ final class NetworkingLinkSignupDataSourceImplementation: NetworkingLinkSignupDa phoneNumber: phoneNumber, country: countryCode, // ex. "US" consumerSessionClientSecret: nil, - clientSecret: clientSecret + clientSecret: clientSecret, + isRelink: false ).chained { (_, customSuccessPaneMessage) in return Promise(value: customSuccessPaneMessage) } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingSaveToLinkVerification/NetworkingSaveToLinkVerificationDataSource.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingSaveToLinkVerification/NetworkingSaveToLinkVerificationDataSource.swift index 1448a6b2d22..36e5152304a 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingSaveToLinkVerification/NetworkingSaveToLinkVerificationDataSource.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingSaveToLinkVerification/NetworkingSaveToLinkVerificationDataSource.swift @@ -70,7 +70,8 @@ final class NetworkingSaveToLinkVerificationDataSourceImplementation: Networking phoneNumber: nil, country: nil, consumerSessionClientSecret: consumerSession.clientSecret, - clientSecret: clientSecret + clientSecret: clientSecret, + isRelink: false ) .chained { (_, customSuccessPaneMessage) in return Promise(value: customSuccessPaneMessage) diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthDataSource.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthDataSource.swift index b571880430d..d692a8d3c12 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthDataSource.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthDataSource.swift @@ -25,10 +25,6 @@ protocol PartnerAuthDataSource: AnyObject { func retrieveAuthSession(_ authSession: FinancialConnectionsAuthSession) -> Future } -struct RelinkSessionPayload { - let coreAuthorization: String -} - final class PartnerAuthDataSourceImplementation: PartnerAuthDataSource { let institution: FinancialConnectionsInstitution @@ -36,14 +32,14 @@ final class PartnerAuthDataSourceImplementation: PartnerAuthDataSource { let returnURL: String? private let apiClient: any FinancialConnectionsAPI private let clientSecret: String - private let relinkSessionPayload: RelinkSessionPayload? + private let relinkAuthorization: String? let analyticsClient: FinancialConnectionsAnalyticsClient var disableAuthSessionRetrieval: Bool { return manifest.features?["bank_connections_disable_defensive_auth_session_retrieval_on_complete"] == true } var isNetworkingRelinkSession: Bool { - return relinkSessionPayload != nil + return relinkAuthorization != nil } // a "pending" auth session is a session which has started @@ -57,7 +53,7 @@ final class PartnerAuthDataSourceImplementation: PartnerAuthDataSource { authSession: FinancialConnectionsAuthSession?, institution: FinancialConnectionsInstitution, manifest: FinancialConnectionsSessionManifest, - repairSessionPayload: RelinkSessionPayload?, + relinkAuthorization: String?, returnURL: String?, apiClient: any FinancialConnectionsAPI, clientSecret: String, @@ -70,14 +66,14 @@ final class PartnerAuthDataSourceImplementation: PartnerAuthDataSource { self.apiClient = apiClient self.clientSecret = clientSecret self.analyticsClient = analyticsClient - self.relinkSessionPayload = repairSessionPayload + self.relinkAuthorization = relinkAuthorization } func createAuthSession() -> Future { - if let relinkSessionPayload { + if let relinkAuthorization { return apiClient.repairAuthSession( clientSecret: clientSecret, - coreAuthorization: relinkSessionPayload.coreAuthorization + coreAuthorization: relinkAuthorization ).chained { [weak self] (repairSession: FinancialConnectionsRepairSession) in let authSession = FinancialConnectionsAuthSession( id: repairSession.id,