mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-02-14 23:18:54 +00:00
Handle multiple visits to Paypal approval return URI
This commit is contained in:
@@ -262,12 +262,34 @@ export async function approvePaypalPayment({
|
||||
|
||||
try {
|
||||
const existing = _getWorkflowFromRedux();
|
||||
const lastReturnToken = _getLastReturnTokenFromRedux();
|
||||
|
||||
if (!existing) {
|
||||
// This can happen if after you finished a Paypal donation, but you go back to
|
||||
// the Paypal website and click Return to Signal again.
|
||||
if (returnToken === lastReturnToken) {
|
||||
if (!isDonationPageVisible()) {
|
||||
redirectToPage(SettingsPage.Donations);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'approvePaypalPayment: Cannot finish nonexistent workflow!'
|
||||
);
|
||||
}
|
||||
|
||||
// If you visit the approval link twice in succession, this can happen
|
||||
if (isPaypalAlreadyApproved(existing)) {
|
||||
log.warn(
|
||||
'approvePaypalPayment: Existing workflow already approved, not trying to approve again'
|
||||
);
|
||||
if (!isDonationPageVisible()) {
|
||||
redirectToPage(SettingsPage.Donations);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (payerId == null || paymentToken == null) {
|
||||
throw new Error(
|
||||
'approvePaypalPayment: payerId or paymentToken are missing'
|
||||
@@ -296,15 +318,20 @@ export async function cancelPaypalPayment(_returnToken: string): Promise<void> {
|
||||
log.info(`${logId}: User visited PayPal cancel URI, showing donate flow`);
|
||||
|
||||
if (!isDonationPageVisible()) {
|
||||
window.reduxActions.nav.changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: SettingsPage.DonationsDonateFlow,
|
||||
},
|
||||
});
|
||||
redirectToPage(SettingsPage.DonationsDonateFlow);
|
||||
}
|
||||
}
|
||||
|
||||
function isPaypalAlreadyApproved(workflow: DonationWorkflow): boolean {
|
||||
const { type } = workflow;
|
||||
return (
|
||||
type === donationStateSchema.Enum.PAYPAL_APPROVED ||
|
||||
type === donationStateSchema.Enum.PAYMENT_CONFIRMED ||
|
||||
type === donationStateSchema.Enum.RECEIPT ||
|
||||
type === donationStateSchema.Enum.DONE
|
||||
);
|
||||
}
|
||||
|
||||
export async function clearDonation(): Promise<void> {
|
||||
runDonationAbortController?.abort();
|
||||
await _saveWorkflow(undefined);
|
||||
@@ -531,12 +558,7 @@ export async function _runDonationWorkflow(): Promise<void> {
|
||||
} else if (type === donationStateSchema.Enum.DONE) {
|
||||
if (isDonationPageVisible()) {
|
||||
if (isDonationsDonateFlowVisible()) {
|
||||
window.reduxActions.nav.changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: SettingsPage.Donations,
|
||||
},
|
||||
});
|
||||
redirectToPage(SettingsPage.Donations);
|
||||
}
|
||||
} else {
|
||||
log.info(
|
||||
@@ -1178,6 +1200,9 @@ async function _saveWorkflow(
|
||||
await _saveWorkflowToStorage(workflow);
|
||||
_saveWorkflowToRedux(workflow);
|
||||
}
|
||||
export function _getLastReturnTokenFromRedux(): string | undefined {
|
||||
return window.reduxStore.getState().donations.lastReturnToken;
|
||||
}
|
||||
export function _getWorkflowFromRedux(): DonationWorkflow | undefined {
|
||||
return window.reduxStore.getState().donations.currentWorkflow;
|
||||
}
|
||||
@@ -1283,6 +1308,20 @@ function isDonationsDonateFlowVisible() {
|
||||
);
|
||||
}
|
||||
|
||||
function redirectToPage(
|
||||
page:
|
||||
| SettingsPage.Donations
|
||||
| SettingsPage.DonationsDonateFlow
|
||||
| SettingsPage.DonationsReceiptList
|
||||
) {
|
||||
window.reduxActions.nav.changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Working with zkgroup receipts
|
||||
|
||||
function getServerPublicParams(): ServerPublicParams {
|
||||
|
||||
@@ -26,6 +26,7 @@ export function getDonationsForRedux(): DonationsStateType {
|
||||
currentWorkflow,
|
||||
didResumeWorkflowAtStartup: Boolean(currentWorkflow),
|
||||
lastError: undefined,
|
||||
lastReturnToken: undefined,
|
||||
receipts: donationReceipts,
|
||||
configCache: undefined,
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ export type DonationsStateType = ReadonlyDeep<{
|
||||
currentWorkflow: DonationWorkflow | undefined;
|
||||
didResumeWorkflowAtStartup: boolean;
|
||||
lastError: DonationErrorType | undefined;
|
||||
lastReturnToken: string | undefined;
|
||||
receipts: Array<DonationReceipt>;
|
||||
configCache: OneTimeDonationHumanAmounts | undefined;
|
||||
}>;
|
||||
@@ -435,6 +436,7 @@ export function getEmptyState(): DonationsStateType {
|
||||
currentWorkflow: undefined,
|
||||
didResumeWorkflowAtStartup: false,
|
||||
lastError: undefined,
|
||||
lastReturnToken: undefined,
|
||||
receipts: [],
|
||||
configCache: undefined,
|
||||
};
|
||||
@@ -475,6 +477,14 @@ export function reducer(
|
||||
if (action.type === UPDATE_WORKFLOW) {
|
||||
const { nextWorkflow } = action.payload;
|
||||
|
||||
let lastReturnToken: string | undefined;
|
||||
const { currentWorkflow } = state;
|
||||
if (currentWorkflow && 'returnToken' in currentWorkflow) {
|
||||
lastReturnToken = currentWorkflow.returnToken;
|
||||
} else {
|
||||
lastReturnToken = state.lastReturnToken;
|
||||
}
|
||||
|
||||
// If we've cleared the workflow or are starting afresh, we clear the startup flag
|
||||
const didResumeWorkflowAtStartup =
|
||||
!nextWorkflow || nextWorkflow.type === donationStateSchema.Enum.INTENT
|
||||
@@ -485,6 +495,7 @@ export function reducer(
|
||||
...state,
|
||||
didResumeWorkflowAtStartup,
|
||||
currentWorkflow: nextWorkflow,
|
||||
lastReturnToken,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ window.testUtilities = {
|
||||
currentWorkflow: undefined,
|
||||
didResumeWorkflowAtStartup: false,
|
||||
lastError: undefined,
|
||||
lastReturnToken: undefined,
|
||||
receipts: [],
|
||||
configCache: undefined,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user