Skip to content

Commit

Permalink
feat(ConnectWalletForm): ask consent for automatic key addition
Browse files Browse the repository at this point in the history
don't save consent; ask each time

nit: define component like rest of components

move copy into _locales

style improvements
  • Loading branch information
sidvishnoi committed Oct 2, 2024
1 parent 1edee22 commit ef86b18
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 6 deletions.
12 changes: 12 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,21 @@
"connectWallet_error_grantRejected": {
"message": "Connect wallet cancelled. You rejected the request."
},
"connectWalletKeyService_text_consent": {
"message": "By agreeing, you provide us consent to automatically access your wallet to securely add a key. Please note, this process does not involve accessing or handling your funds."
},
"connectWalletKeyService_label_conceptAccept": {
"message": "Accept"
},
"connectWalletKeyService_label_conceptDecline": {
"message": "Decline"
},
"connectWalletKeyService_error_notImplemented": {
"message": "Automatic key addition is not implemented for given wallet provider yet."
},
"connectWalletKeyService_error_noConsent": {
"message": "You declined consent for automatic key addition."
},
"connectWalletKeyService_error_failed": {
"message": "Automatic key addition failed at step “$STEP_ID$” with message “$MESSAGE$”.",
"placeholders": {
Expand Down
9 changes: 9 additions & 0 deletions src/background/services/keyAutoAdd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ export class KeyAutoAddService {
const state = status ? { status } : null;
this.storage.setPopupTransientState('connect', () => state);
}

static supports(walletAddress: WalletAddress): boolean {
try {
void walletAddressToProvider(walletAddress);
return true;
} catch {
return false;
}
}
}

export function walletAddressToProvider(walletAddress: WalletAddress): {
Expand Down
16 changes: 14 additions & 2 deletions src/background/services/openPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ export class OpenPaymentsService {
walletAddressUrl,
amount,
recurring,
skipAutoKeyShare,
autoKeyAdd,
autoKeyAddConsent,
}: ConnectWalletPayload) {
const walletAddress = await getWalletInformation(walletAddressUrl);
const exchangeRates = await getExchangeRates();
Expand Down Expand Up @@ -380,8 +381,19 @@ export class OpenPaymentsService {
} catch (error) {
if (
error.message === this.t('connectWallet_error_invalidClient') &&
!skipAutoKeyShare
autoKeyAdd
) {
if (!KeyAutoAddService.supports(walletAddress)) {
this.setConnectState('error');
throw new ErrorWithKey(
'connectWalletKeyService_error_notImplemented',
);
}
if (!autoKeyAddConsent) {
this.setConnectState('error');
throw new ErrorWithKey('connectWalletKeyService_error_noConsent');
}

// add key to wallet and try again
try {
const tabId = await this.addPublicKeyToWallet(walletAddress);
Expand Down
58 changes: 55 additions & 3 deletions src/popup/components/ConnectWalletForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface Inputs {
walletAddressUrl: string;
amount: string;
recurring: boolean;
autoKeyAddConsent: boolean;
}

interface ConnectWalletFormProps {
Expand Down Expand Up @@ -60,7 +61,12 @@ export const ConnectWalletForm = ({
const [recurring, setRecurring] = React.useState<Inputs['recurring']>(
defaultValues.recurring || false,
);

const [autoKeyShareFailed, setAutoKeyShareFailed] = React.useState(false);
const [showConsent, setShowConsent] = React.useState(false);
const autoKeyAddConsent = React.useRef<boolean>(
defaultValues.autoKeyAddConsent || false,
);

const [walletAddressInfo, setWalletAddressInfo] =
React.useState<WalletAddress | null>(null);
Expand Down Expand Up @@ -136,8 +142,8 @@ export const ConnectWalletForm = ({
[saveValue, currencySymbol, t],
);

const handleSubmit = async (ev: React.FormEvent<HTMLFormElement>) => {
ev.preventDefault();
const handleSubmit = async (ev?: React.FormEvent<HTMLFormElement>) => {
ev?.preventDefault();
if (!walletAddressInfo) {
setErrors((_) => ({ ..._, walletAddressUrl: 'Not fetched yet?!' }));
return;
Expand Down Expand Up @@ -166,14 +172,19 @@ export const ConnectWalletForm = ({
walletAddressUrl: toWalletAddressUrl(walletAddressUrl),
amount,
recurring,
skipAutoKeyShare,
autoKeyAdd: !skipAutoKeyShare,
autoKeyAddConsent: autoKeyAddConsent.current,
});
if (res.success) {
onConnect();
} else {
if (isErrorWithKey(res.error)) {
const error = res.error;
if (error.key.startsWith('connectWalletKeyService_error_')) {
if (error.key === 'connectWalletKeyService_error_noConsent') {
setShowConsent(true);
return;
}
setErrors((_) => ({ ..._, keyPair: t(error) }));
} else {
setErrors((_) => ({ ..._, connect: t(error) }));
Expand Down Expand Up @@ -203,6 +214,26 @@ export const ConnectWalletForm = ({
}
}, [defaultValues.walletAddressUrl, handleWalletAddressUrlChange]);

if (showConsent) {
return (
<AutoKeyAddConsent
onAccept={() => {
autoKeyAddConsent.current = true;
// saveValue('autoKeyAddConsent', true);
setShowConsent(false);
handleSubmit();
}}
onDecline={() => {
setErrors((_) => ({
..._,
keyPair: t('connectWalletKeyService_error_noConsent'),
}));
setShowConsent(false);
}}
/>
);
}

return (
<form
data-testid="connect-wallet-form"
Expand Down Expand Up @@ -366,6 +397,27 @@ export const ConnectWalletForm = ({
);
};

const AutoKeyAddConsent: React.FC<{
onAccept: () => void;
onDecline: () => void;
}> = ({ onAccept, onDecline }) => {
const t = useTranslation();
return (
<form className="space-y-4" data-testid="connect-wallet-auto-key-consent">
<p className="text-medium">{t('connectWalletKeyService_text_consent')}</p>

<div className="mx-auto flex w-3/4 justify-around gap-4">
<Button onClick={onAccept}>
{t('connectWalletKeyService_label_conceptAccept')}
</Button>
<Button onClick={onDecline} variant="destructive">
{t('connectWalletKeyService_label_conceptDecline')}
</Button>
</div>
</form>
);
};

const ManualKeyPairNeeded: React.FC<{
error: { message: string; details: string; whyText: string };
hideError?: boolean;
Expand Down
3 changes: 3 additions & 0 deletions src/popup/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export const Component = () => {
amount: localStorage?.getItem('connect.amount') || undefined,
walletAddressUrl:
localStorage?.getItem('connect.walletAddressUrl') || undefined,
autoKeyAddConsent:
localStorage?.getItem('connect.autoKeyAddConsent') === 'true' ||
false,
}}
saveValue={(key, val) => {
localStorage?.setItem(`connect.${key}`, val.toString());
Expand Down
3 changes: 2 additions & 1 deletion src/shared/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ export interface ConnectWalletPayload {
walletAddressUrl: string;
amount: string;
recurring: boolean;
skipAutoKeyShare: boolean;
autoKeyAdd: boolean;
autoKeyAddConsent: boolean | null;
}

export interface AddFundsPayload {
Expand Down

0 comments on commit ef86b18

Please sign in to comment.