Skip to content

Commit 695df0b

Browse files
authored
refactor(bg): remove redirect logic from outgoingPaymentGrant (#1321)
1 parent 623ac6d commit 695df0b

3 files changed

Lines changed: 78 additions & 62 deletions

File tree

src/_locales/en/messages.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@
205205
"connectWallet_error_timeout": {
206206
"message": "Connecting to wallet took too long. Please try again."
207207
},
208+
"connectWallet_error_hashFailed": {
209+
"message": "Connection failed. Please try again."
210+
},
211+
"connectWallet_error_continuationFailed": {
212+
"message": "Connection failed. Please try again."
213+
},
214+
"connectWallet_error_grantInvalid": {
215+
"message": "Connection failed. Please try again."
216+
},
208217
"connectWalletKeyService_text_consentP1": {
209218
"message": "We will automatically connect with your wallet provider."
210219
},

src/background/services/outgoingPaymentGrant.ts

Lines changed: 18 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,7 @@ import {
2121
isInvalidContinuationError,
2222
isNotFoundError,
2323
} from '@/background/services/openPayments';
24-
import {
25-
createTabIfNotExists,
26-
ErrorCode,
27-
GrantResult,
28-
InteractionIntent,
29-
redirectToWelcomeScreen,
30-
} from '@/background/utils';
24+
import { createTabIfNotExists, InteractionIntent } from '@/background/utils';
3125

3226
interface InteractionParams {
3327
interactRef: string;
@@ -132,14 +126,13 @@ export class OutgoingPaymentGrantService {
132126
walletAmount: WalletAmount,
133127
walletAddress: WalletAddress,
134128
{ grant, nonce }: Awaited<ReturnType<this['createOutgoingPaymentGrant']>>,
135-
intent: InteractionIntent,
136129
onTabOpen: (tabId: TabId) => void,
137130
existingTabId?: TabId,
138131
timeout = ACCEPT_GRANT_TIMEOUT,
139132
): Promise<GrantDetails> {
140133
const signal = AbortSignal.timeout(timeout);
141134

142-
const { interactRef, hash, tabId } = await this.getInteractionInfo(
135+
const { interactRef, hash } = await this.getInteractionInfo(
143136
grant.interact.redirect,
144137
onTabOpen,
145138
signal,
@@ -152,17 +145,10 @@ export class OutgoingPaymentGrantService {
152145
interactRef,
153146
hash,
154147
walletAddress.authServer,
155-
intent,
156-
tabId,
157148
);
158149
signal.throwIfAborted();
159150

160-
const continuation = await this.continueGrant(
161-
grant,
162-
interactRef,
163-
intent,
164-
tabId,
165-
);
151+
const continuation = await this.continueGrant(grant, interactRef);
166152
if (!isFinalizedGrantWithAccessToken(continuation)) {
167153
throw new Error(
168154
'Expected finalized grant. Received non-finalized grant.',
@@ -173,13 +159,6 @@ export class OutgoingPaymentGrantService {
173159
this.grant = this.buildGrantDetails(continuation, walletAmount);
174160
await this.persistGrantDetails(this.grant);
175161

176-
await redirectToWelcomeScreen(
177-
this.browser,
178-
tabId,
179-
GrantResult.GRANT_SUCCESS,
180-
intent,
181-
);
182-
183162
return this.grant;
184163
}
185164

@@ -336,6 +315,8 @@ export class OutgoingPaymentGrantService {
336315
resolve({ interactRef, hash, tabId });
337316
} else if (result === 'grant_rejected') {
338317
reject(new ErrorWithKey('connectWallet_error_grantRejected'));
318+
} else if (result === 'grant_invalid') {
319+
reject(new ErrorWithKey('connectWallet_error_grantInvalid'));
339320
}
340321
} catch {
341322
/* do nothing */
@@ -354,29 +335,17 @@ export class OutgoingPaymentGrantService {
354335
interactRef: string,
355336
hash: string,
356337
authServer: string,
357-
intent: InteractionIntent,
358-
tabId: TabId,
359338
) {
360339
const computeHash = (authServer: string) =>
361340
this.computeHash(clientNonce, interactionNonce, interactRef, authServer);
362-
try {
363-
if (hash === (await computeHash(authServer))) return;
364-
// See https://github.com/interledger/web-monetization-extension/pull/1230
365-
this.logger.warn(
366-
'verifyInteractionHash failed with authServer without trailing slash',
367-
);
368-
if (hash === (await computeHash(ensureEnd(authServer, '/')))) return;
369-
throw new Error('Invalid interaction hash');
370-
} catch (error) {
371-
await redirectToWelcomeScreen(
372-
this.browser,
373-
tabId,
374-
GrantResult.GRANT_ERROR,
375-
intent,
376-
ErrorCode.HASH_FAILED,
377-
);
378-
throw error;
379-
}
341+
342+
if (hash === (await computeHash(authServer))) return;
343+
// See https://github.com/interledger/web-monetization-extension/pull/1230
344+
this.logger.warn(
345+
'verifyInteractionHash failed with authServer without trailing slash',
346+
);
347+
if (hash === (await computeHash(ensureEnd(authServer, '/')))) return;
348+
throw new ErrorWithKey('connectWallet_error_hashFailed');
380349
}
381350

382351
private computeHash = async (
@@ -392,12 +361,7 @@ export class OutgoingPaymentGrantService {
392361
return btoa(String.fromCharCode.apply(null, new Uint8Array(digest)));
393362
};
394363

395-
private async continueGrant(
396-
grant: PendingGrant,
397-
interactRef: string,
398-
intent: InteractionIntent,
399-
tabId: TabId,
400-
) {
364+
private async continueGrant(grant: PendingGrant, interactRef: string) {
401365
try {
402366
const continuation = await this.openPaymentsService.client.grant.continue(
403367
{
@@ -409,14 +373,10 @@ export class OutgoingPaymentGrantService {
409373

410374
return continuation;
411375
} catch (error) {
412-
await redirectToWelcomeScreen(
413-
this.browser,
414-
tabId,
415-
GrantResult.GRANT_ERROR,
416-
intent,
417-
ErrorCode.CONTINUATION_FAILED,
418-
);
419-
throw error;
376+
this.logger.error('connectWallet_error_continuationFailed', {
377+
cause: error,
378+
});
379+
throw new ErrorWithKey('connectWallet_error_continuationFailed');
420380
}
421381
}
422382

src/background/services/wallet.ts

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ export class WalletService {
183183
walletAmount,
184184
walletAddress,
185185
grant,
186-
intent,
187186
(openedTabId) => {
188187
tabId = openedTabId;
189188
cleanupListeners = highlightTabOnPopupOpen(browser, tabId);
@@ -195,11 +194,19 @@ export class WalletService {
195194
cleanupListeners();
196195
if (isAbortSignalTimeout(error)) {
197196
onTimeoutAbort();
197+
} else if (isErrorWithKey(error)) {
198+
await this.handleGrantCompletionError(error, intent, tabId!);
198199
}
199200
this.setConnectStateError(error);
200201
throw error;
201202
}
202203

204+
await redirectToWelcomeScreen(
205+
this.browser,
206+
tabId,
207+
GrantResult.GRANT_SUCCESS,
208+
intent,
209+
);
203210
await this.storage.set({
204211
walletAddress,
205212
rateOfPay,
@@ -317,7 +324,6 @@ export class WalletService {
317324
walletAmount,
318325
walletAddress,
319326
grant,
320-
intent,
321327
(openedTabId) => {
322328
tabId = openedTabId;
323329
},
@@ -326,12 +332,21 @@ export class WalletService {
326332
if (isAbortSignalTimeout(error)) {
327333
await this.redirectOnTimeout(intent, tabId);
328334
throw new ErrorWithKey('connectWallet_error_timeout');
335+
} else if (isErrorWithKey(error)) {
336+
await this.handleGrantCompletionError(error, intent, tabId!);
329337
}
330338
throw error;
331339
}
332340

333341
await this.storage.setState({ out_of_funds: false });
334342

343+
await redirectToWelcomeScreen(
344+
this.browser,
345+
tabId,
346+
GrantResult.GRANT_SUCCESS,
347+
intent,
348+
);
349+
335350
// cancel existing grants of same type, if any
336351
if (grants.oneTimeGrant && !recurring) {
337352
await this.outgoingPaymentGrantService.cancelGrant(
@@ -372,7 +387,6 @@ export class WalletService {
372387
walletAmount,
373388
walletAddress,
374389
grant,
375-
intent,
376390
(openedTabId) => {
377391
tabId = openedTabId;
378392
},
@@ -381,10 +395,19 @@ export class WalletService {
381395
if (isAbortSignalTimeout(error)) {
382396
await this.redirectOnTimeout(intent, tabId);
383397
throw new ErrorWithKey('connectWallet_error_timeout');
398+
} else if (isErrorWithKey(error)) {
399+
await this.handleGrantCompletionError(error, intent, tabId!);
384400
}
385401
throw error;
386402
}
387403

404+
await redirectToWelcomeScreen(
405+
this.browser,
406+
tabId,
407+
GrantResult.GRANT_SUCCESS,
408+
intent,
409+
);
410+
388411
// Revoke all existing grants.
389412
// Note: Clear storage only if new grant type is not same as previous grant
390413
// type (as completeGrant already sets new grant state)
@@ -461,7 +484,7 @@ export class WalletService {
461484
: ErrorCode.KEY_ADD_FAILED,
462485
);
463486
}
464-
if (error instanceof ErrorWithKey) {
487+
if (isErrorWithKey(error)) {
465488
throw error;
466489
} else {
467490
// TODO: check if need to handle errors here
@@ -528,6 +551,30 @@ export class WalletService {
528551
);
529552
}
530553

554+
private async handleGrantCompletionError(
555+
error: ErrorWithKeyLike,
556+
intent: InteractionIntent,
557+
tabId: TabId,
558+
) {
559+
if (error.key === 'connectWallet_error_tabClosed') {
560+
return;
561+
}
562+
563+
let code: ErrorCode | undefined;
564+
if (error.key === 'connectWallet_error_hashFailed') {
565+
code = ErrorCode.HASH_FAILED;
566+
} else if (error.key === 'connectWallet_error_continuationFailed') {
567+
code = ErrorCode.CONTINUATION_FAILED;
568+
}
569+
await redirectToWelcomeScreen(
570+
this.browser,
571+
tabId,
572+
GrantResult.GRANT_ERROR,
573+
intent,
574+
code,
575+
);
576+
}
577+
531578
public resetConnectState() {
532579
this.storage.setTransientState('connect', () => null);
533580
}

0 commit comments

Comments
 (0)