diff --git a/app/main.ts b/app/main.ts index 0725706521..3561f577f9 100644 --- a/app/main.ts +++ b/app/main.ts @@ -2917,6 +2917,7 @@ function handleSignalRoute(route: ParsedSignalRoute) { showWindow(); } else if (route.key === 'donationValidationComplete') { log.info('donationValidationComplete route handled'); + mainWindow.webContents.send('donation-validation-complete', route.args); } else { log.info('handleSignalRoute: Unknown signal route:', route.key); mainWindow.webContents.send('unknown-sgnl-link'); diff --git a/ts/services/donations.ts b/ts/services/donations.ts index 8ea3eb8042..8c48742e6a 100644 --- a/ts/services/donations.ts +++ b/ts/services/donations.ts @@ -113,12 +113,22 @@ export async function finishDonationWithCard( } export async function finish3dsValidation(token: string): Promise { - const existing = _getWorkflowFromRedux(); - if (!existing) { - throw new Error('finish3dsValidation: Cannot finish nonexistent workflow!'); + let workflow: DonationWorkflow; + + try { + const existing = _getWorkflowFromRedux(); + if (!existing) { + throw new Error( + 'finish3dsValidation: Cannot finish nonexistent workflow!' + ); + } + + workflow = await _completeValidationRedirect(existing, token); + } catch (error) { + await failDonation(donationErrorTypeSchema.Enum.Failed3dsValidation); + throw error; } - const workflow = await _completeValidationRedirect(existing, token); await _saveAndRunWorkflow(workflow); } @@ -681,7 +691,8 @@ async function failDonation(errorType: DonationErrorType): Promise { if ( workflow && workflow.type !== donationStateSchema.Enum.INTENT_METHOD && - workflow.type !== donationStateSchema.Enum.INTENT + workflow.type !== donationStateSchema.Enum.INTENT && + workflow.type !== donationStateSchema.Enum.INTENT_REDIRECT ) { await _saveWorkflow(undefined); } diff --git a/ts/signal.ts b/ts/signal.ts index 9d387d9848..4865d527ea 100644 --- a/ts/signal.ts +++ b/ts/signal.ts @@ -464,9 +464,9 @@ export const setup = (options: { initializeGroupCredentialFetcher, initializeNetworkObserver, initializeUpdateListener, + donations, // Testing - donations, storage, }; diff --git a/ts/types/Donations.ts b/ts/types/Donations.ts index 0ab5ca7569..a2f64b6293 100644 --- a/ts/types/Donations.ts +++ b/ts/types/Donations.ts @@ -17,6 +17,8 @@ export const donationErrorTypeSchema = z.enum([ 'PaymentDeclined', // Only used if we can't support 3DS validation for our first release 'CardNotSupported', + // Used if the user is redirected back from validation, but continuing forward fails + 'Failed3dsValidation', // Any other HTTPError during the process 'DonationProcessingError', // Any other error diff --git a/ts/window.d.ts b/ts/window.d.ts index d11f51ebd1..b1398cf572 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -21,6 +21,7 @@ import type { import type AccountManager from './textsecure/AccountManager'; import type { WebAPIConnectType } from './textsecure/WebAPI'; import type { CallingClass } from './services/calling'; +import type * as Donations from './services/donations'; import type * as StorageService from './services/storage'; import type { BackupsService } from './services/backups'; import type * as Groups from './groups'; @@ -164,6 +165,7 @@ export type SignalCoreType = { lightSessionResetQueue?: PQueue; retryPlaceholders?: RetryPlaceholders; storage: typeof StorageService; + donations: typeof Donations; }; SettingsWindowProps?: SettingsWindowPropsType; Migrations: ReturnType; diff --git a/ts/windows/main/phase1-ipc.ts b/ts/windows/main/phase1-ipc.ts index e2e21314fc..f4ff963ca3 100644 --- a/ts/windows/main/phase1-ipc.ts +++ b/ts/windows/main/phase1-ipc.ts @@ -373,6 +373,10 @@ ipc.on('cancel-presenting', () => { window.reduxActions?.calling?.cancelPresenting(); }); +ipc.on('donation-validation-complete', (_event, { token }) => { + drop(window.Signal.Services.donations.finish3dsValidation(token)); +}); + ipc.on('show-conversation-via-token', (_event, token: string) => { const { showConversationViaToken } = window.Events; if (showConversationViaToken) {