Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
"keyRevoked_action_reconnectBtn": {
"message": "Reconnect"
},
"disconnectWallet_error_generic": {
"message": "We were unable to disconnect your wallet ($ERROR$).",
"placeholders": {
"ERROR": { "content": "$1", "example": "Internal server error" }
}
},
"pay_action_pay": {
"message": "Send now"
},
Expand Down
4 changes: 2 additions & 2 deletions src/background/services/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,12 @@ export class Background {
return;

case 'DISCONNECT_WALLET':
await this.walletService.disconnectWallet();
await this.walletService.disconnectWallet(message.payload.force);
this.tabState.clearAllState('disconnect');
await this.browser.alarms.clear(ALARM_RESET_OUT_OF_FUNDS);
await this.updateVisualIndicatorsForCurrentTab();
this.sendToPopup.send('SET_STATE', { state: {}, prevState: {} });
return;
return success(undefined);

case 'TOGGLE_CONTINUOUS_PAYMENTS': {
await this.monetizationService.toggleContinuousPayments();
Expand Down
2 changes: 1 addition & 1 deletion src/background/services/openPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export class OpenPaymentsService {
}
}

const isOpenPaymentsClientError = (error: unknown) =>
export const isOpenPaymentsClientError = (error: unknown) =>
error instanceof OpenPaymentsClientError;

export const isKeyRevokedError = (error: unknown) => {
Expand Down
37 changes: 31 additions & 6 deletions src/background/services/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import {
} from '@/background/utils';
import { KeyAutoAddService } from '@/background/services/keyAutoAdd';
import { generateEd25519KeyPair, exportJWK } from '@/shared/crypto';
import { isInvalidClientError } from '@/background/services/openPayments';
import {
isInvalidClientError,
isOpenPaymentsClientError,
} from '@/background/services/openPayments';
import { APP_URL } from '@/background/constants';
import { bytesToHex } from '@noble/hashes/utils';
import type { Cradle } from '@/background/container';
Expand All @@ -37,6 +40,7 @@ export class WalletService {
private storage: Cradle['storage'];
private events: Cradle['events'];
private browser: Cradle['browser'];
private logger: Cradle['logger'];
private appName: Cradle['appName'];
private browserName: Cradle['browserName'];
private t: Cradle['t'];
Expand All @@ -47,6 +51,7 @@ export class WalletService {
storage,
events,
browser,
logger,
appName,
browserName,
t,
Expand All @@ -57,6 +62,7 @@ export class WalletService {
storage,
events,
browser,
logger,
appName,
browserName,
t,
Expand Down Expand Up @@ -245,22 +251,41 @@ export class WalletService {
this.resetConnectState();
}

async disconnectWallet() {
async disconnectWallet(force = false) {
const { recurringGrant, oneTimeGrant } = await this.storage.get([
'recurringGrant',
'oneTimeGrant',
]);
if (!recurringGrant && !oneTimeGrant) {
return;
}

const handleError = (
err: unknown,
grantType: 'recurring' | 'oneTime',
force: boolean,
) => {
this.logger.error(`Could not cancel ${grantType} grant`, { err });
if (force) return;

if (isOpenPaymentsClientError(err)) {
throw new ErrorWithKey('disconnectWallet_error_generic', [
err.status ? `HTTP ${err.status} - ${err.message}` : err.message,
]);
}
throw err;
};

if (recurringGrant) {
await this.outgoingPaymentGrantService.cancelGrant(
recurringGrant.continue,
);
await this.outgoingPaymentGrantService
.cancelGrant(recurringGrant.continue)
.catch((err) => handleError(err, 'recurring', force));
this.outgoingPaymentGrantService.disableRecurringGrant();
}
if (oneTimeGrant) {
await this.outgoingPaymentGrantService.cancelGrant(oneTimeGrant.continue);
await this.outgoingPaymentGrantService
.cancelGrant(oneTimeGrant.continue)
.catch((err) => handleError(err, 'recurring', force));
this.outgoingPaymentGrantService.disableOneTimeGrant();
}
await this.storage.clear();
Expand Down
4 changes: 2 additions & 2 deletions src/pages/popup/components/ErrorKeyRevoked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { ReconnectWalletPayload, Response } from '@/shared/messages';

interface Props {
info: Pick<PopupStore, 'publicKey' | 'walletAddress'>;
disconnectWallet: () => Promise<Response>;
disconnectWallet: (force: boolean) => Promise<Response>;
reconnectWallet: (data: ReconnectWalletPayload) => Promise<Response>;
onReconnect?: () => void;
onDisconnect?: () => void;
Expand Down Expand Up @@ -90,7 +90,7 @@ const MainScreen = ({
setErrorMsg('');
try {
setIsLoading(true);
await disconnectWallet();
await disconnectWallet(true);
onDisconnect?.();
} catch (error) {
setErrorMsg(error.message);
Expand Down
44 changes: 39 additions & 5 deletions src/pages/popup/components/Settings/WalletInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Input } from '@/pages/shared/components/ui/Input';
import { Label } from '@/pages/shared/components/ui/Label';
import { Code } from '@/pages/shared/components/ui/Code';
import { Button } from '@/pages/shared/components/ui/Button';
import { useMessage } from '@/popup/lib/context';
import { toErrorInfoFactory } from '@/pages/shared/lib/utils';
import { useMessage, useTranslation } from '@/popup/lib/context';
import { ROUTES_PATH } from '@/popup/Popup';
import { useLocation } from 'wouter';
import type { PopupStore } from '@/shared/types';
Expand All @@ -18,9 +19,32 @@ export const WalletInformation = ({
publicKey,
walletAddress,
}: WalletInformationProps) => {
const t = useTranslation();
const message = useMessage();
const [_location, navigate] = useLocation();
const [disconnectError, setDisconnectError] = React.useState<string>('');
const [isSubmitting, setIsSubmitting] = React.useState(false);
const toErrorInfo = toErrorInfoFactory(t);

const disconnectWallet = async (force = false) => {
setIsSubmitting(true);
setDisconnectError('');
try {
const res = await message.send('DISCONNECT_WALLET', { force });
if (!res.success) {
if (res.error) {
throw new Error(toErrorInfo(res.error)!.message);
}
throw new Error(res.message);
}
navigate(ROUTES_PATH.HOME);
window.location.reload();
} catch (error) {
setDisconnectError(error.message);
} finally {
setIsSubmitting(false);
}
};

return (
<div className="flex h-full flex-col gap-8">
Expand All @@ -29,10 +53,7 @@ export const WalletInformation = ({
className="space-y-4"
onSubmit={async (ev) => {
ev.preventDefault();
setIsSubmitting(true);
await message.send('DISCONNECT_WALLET');
navigate(ROUTES_PATH.HOME);
window.location.reload();
await disconnectWallet();
}}
>
<Input
Expand All @@ -58,6 +79,19 @@ export const WalletInformation = ({
>
Disconnect
</Button>

{disconnectError && (
<p className="text-sm text-error !mt-1">
{disconnectError}
<button
type="button"
onClick={() => disconnectWallet(true)}
className="ml-1 inline-block underline"
>
Force disconnect?
</button>
</p>
)}
</form>

<details className="border-t">
Expand Down
2 changes: 1 addition & 1 deletion src/pages/popup/pages/ErrorKeyRevoked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default () => {
info={{ publicKey, walletAddress }}
reconnectWallet={(data) => message.send('RECONNECT_WALLET', data)}
onReconnect={onReconnect}
disconnectWallet={() => message.send('DISCONNECT_WALLET')}
disconnectWallet={(force) => message.send('DISCONNECT_WALLET', { force })}
onDisconnect={onDisconnect}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion src/shared/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export type PopupToBackgroundMessage = {
output: never;
};
DISCONNECT_WALLET: {
input: never;
input: { force: boolean };
output: never;
};
TOGGLE_CONTINUOUS_PAYMENTS: {
Expand Down