Skip to content

Commit

Permalink
Merge pull request #81 from tonkeeper/feature/global-auth
Browse files Browse the repository at this point in the history
Update unlock for wallet with global auth
  • Loading branch information
KuznetsovNikita authored May 7, 2024
2 parents a2655bb + fb57e33 commit db09107
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 40 deletions.
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@tonkeeper/desktop",
"license": "Apache-2.0",
"version": "3.11.0",
"version": "3.12.0",
"description": "Your desktop wallet on The Open Network",
"main": ".webpack/main",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tonkeeper/web",
"version": "3.11.0",
"version": "3.12.0",
"author": "Nikita Kuznetsov <[email protected]>",
"description": "Your web wallet on The Open Network",
"dependencies": {
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/service/accountService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AppKey } from '../Keys';
import { IStorage } from '../Storage';
import { encrypt } from './cryptoService';
import { getWalletMnemonic, validateWalletMnemonic } from './mnemonicService';
import { getWalletStateOrDie } from './wallet/storeService';

export const getAccountState = async (storage: IStorage) => {
const state = await storage.get<AccountState>(AppKey.ACCOUNT);
Expand Down Expand Up @@ -169,3 +170,19 @@ export const accountValidatePassword = (password: string, confirm: string) => {
}
return undefined;
};

export const getWalletWithGlobalAuth = async (storage: IStorage) => {
const account = await getAccountState(storage);
if (account.publicKeys.length === 0) {
throw new Error('Missing wallets');
}

for (const key of account.publicKeys) {
const wallet = await getWalletStateOrDie(storage, key);
if (wallet.auth === undefined) {
return key;
}
}

throw new Error('Missing wallet with global auth.');
};
4 changes: 0 additions & 4 deletions packages/core/src/service/wallet/storeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ export const getWalletStateOrDie = async (storage: IStorage, publicKey: string)
throw new Error(`Missing wallet state: ${publicKey}`);
}
return state;
}

export const getWalletStateByAddress = async (storage: IStorage, rawAddress: string) => {
return null;
};

export const setWalletState = (storage: IStorage, state: WalletState) => {
Expand Down
32 changes: 25 additions & 7 deletions packages/uikit/src/components/connect/TonConnectNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import styled from 'styled-components';
import { useWalletContext } from '../../hooks/appContext';
import { useAppSdk } from '../../hooks/appSdk';
import { useTranslation } from '../../hooks/translation';
import { TxConfirmationCustomError } from '../../libs/errors/TxConfirmationCustomError';
import { QueryKey } from '../../libs/queryKey';
import { useIsActiveWalletLedger } from '../../state/ledger';
import { signTonConnectOver } from '../../state/mnemonic';
import { CheckmarkCircleIcon } from '../Icon';
import { CheckmarkCircleIcon, ExclamationMarkCircleIcon } from '../Icon';
import { Notification, NotificationBlock } from '../Notification';
import { Body2, Body3, H2, Label2 } from '../Text';
import { Button } from '../fields/Button';
import { ResultButton } from '../transfer/common';
import { useIsActiveWalletLedger } from '../../state/ledger';

const useConnectMutation = (
request: ConnectRequest,
Expand All @@ -36,6 +37,7 @@ const useConnectMutation = (
const wallet = useWalletContext();
const sdk = useAppSdk();
const client = useQueryClient();
const { t } = useTranslation();

return useMutation<ConnectItemReply[], Error>(async () => {
const params = await getTonConnectParams(request);
Expand All @@ -47,7 +49,7 @@ const useConnectMutation = (
result.push(toTonAddressItemReply(wallet));
}
if (item.name === 'ton_proof') {
const signTonConnect = signTonConnectOver(sdk, wallet.publicKey);
const signTonConnect = signTonConnectOver(sdk, wallet.publicKey, t);
const proof = tonConnectProofPayload(
webViewUrl ?? manifest.url,
wallet.active.rawAddress,
Expand Down Expand Up @@ -164,13 +166,19 @@ const ConnectContent: FC<{
}
}, []);

const [error, setError] = useState<Error | null>(null);
const { mutateAsync, isLoading } = useConnectMutation(params, manifest, origin);

const onSubmit: React.FormEventHandler<HTMLFormElement> = async e => {
e.preventDefault();
const result = await mutateAsync();
setDone(true);
setTimeout(() => handleClose(result, manifest), 300);
try {
const result = await mutateAsync();
setDone(true);
setTimeout(() => handleClose(result, manifest), 300);
} catch (e) {
setDone(true);
setError(e as Error);
}
};

const address = formatAddress(wallet.active.rawAddress, wallet.network);
Expand Down Expand Up @@ -199,12 +207,22 @@ const ConnectContent: FC<{
</div>

<>
{done && (
{done && !error && (
<ResultButton done>
<CheckmarkCircleIcon />
<Label2>{t('ton_login_success')}</Label2>
</ResultButton>
)}
{done && error && (
<ResultButton>
<ExclamationMarkCircleIcon />
<Label2>
{error instanceof TxConfirmationCustomError
? error.message
: t('error_occurred')}
</Label2>
</ResultButton>
)}
{!done && (
<Button
size="large"
Expand Down
12 changes: 2 additions & 10 deletions packages/uikit/src/pages/home/Unlock.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMutation } from '@tanstack/react-query';
import { getWalletWithGlobalAuth } from '@tonkeeper/core/dist/service/accountService';
import { validateWalletMnemonic } from '@tonkeeper/core/dist/service/mnemonicService';
import { getWalletState } from '@tonkeeper/core/dist/service/wallet/storeService';
import React, { FC, useEffect, useRef, useState } from 'react';
import styled, { css } from 'styled-components';
import { TonkeeperIcon } from '../../components/Icon';
Expand Down Expand Up @@ -41,18 +41,10 @@ const Logo = styled.div`
`;

const useMutateUnlock = () => {
const { account } = useAppContext();
const sdk = useAppSdk();

return useMutation<void, Error, string>(async password => {
if (account.publicKeys.length === 0) {
throw new Error('Missing wallets');
}
const [publicKey] = account.publicKeys;
const wallet = await getWalletState(sdk.storage, publicKey);
if (!wallet) {
throw new Error('Missing wallet');
}
const publicKey = await getWalletWithGlobalAuth(sdk.storage);

const isValid = await validateWalletMnemonic(sdk.storage, publicKey, password);
if (!isValid) {
Expand Down
16 changes: 5 additions & 11 deletions packages/uikit/src/pages/home/UnlockNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useMutation } from '@tanstack/react-query';
import { GetPasswordParams, IAppSdk, KeyboardParams } from '@tonkeeper/core/dist/AppSdk';
import { AuthState } from '@tonkeeper/core/dist/entries/password';
import { MinPasswordLength, getAccountState } from '@tonkeeper/core/dist/service/accountService';
import {
MinPasswordLength,
getWalletWithGlobalAuth
} from '@tonkeeper/core/dist/service/accountService';
import { validateWalletMnemonic } from '@tonkeeper/core/dist/service/mnemonicService';
import { getWalletState } from '@tonkeeper/core/dist/service/wallet/storeService';
import { debounce } from '@tonkeeper/core/dist/utils/common';
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useLocation } from 'react-router-dom';
Expand All @@ -30,15 +32,7 @@ const Block = styled.form<{ padding: number }>`

export const useMutateUnlock = (sdk: IAppSdk, requestId?: number) => {
return useMutation<void, Error, string>(async password => {
const account = await getAccountState(sdk.storage);
if (account.publicKeys.length === 0) {
throw new Error('Missing wallets');
}
const [publicKey] = account.publicKeys;
const wallet = await getWalletState(sdk.storage, publicKey);
if (!wallet) {
throw new Error('Missing wallet');
}
const publicKey = await getWalletWithGlobalAuth(sdk.storage);

const isValid = await validateWalletMnemonic(sdk.storage, publicKey, password);
if (!isValid) {
Expand Down
22 changes: 17 additions & 5 deletions packages/uikit/src/state/mnemonic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Cell } from '@ton/core';
import { mnemonicToPrivateKey, sha256_sync, sign } from '@ton/crypto';
import { IAppSdk } from '@tonkeeper/core/dist/AppSdk';
import { AuthState } from '@tonkeeper/core/dist/entries/password';
import { CellSigner, Signer } from '@tonkeeper/core/dist/entries/signer';
import { LedgerTransaction } from '@tonkeeper/core/dist/service/ledger/connector';
import { getWalletMnemonic } from '@tonkeeper/core/dist/service/mnemonicService';
import {
parseSignerSignature,
Expand All @@ -10,18 +12,28 @@ import {
import { getWalletAuthState } from '@tonkeeper/core/dist/service/walletService';
import { delay } from '@tonkeeper/core/dist/utils/common';
import nacl from 'tweetnacl';
import { LedgerTransaction } from '@tonkeeper/core/dist/service/ledger/connector';
import { CellSigner, Signer } from '@tonkeeper/core/dist/entries/signer';
import { TxConfirmationCustomError } from '../libs/errors/TxConfirmationCustomError';

export const signTonConnectOver = (sdk: IAppSdk, publicKey: string) => {
export const signTonConnectOver = (
sdk: IAppSdk,
publicKey: string,
t: (text: string) => string
) => {
return async (bufferToSign: Buffer) => {
const auth = await getWalletAuthState(sdk.storage, publicKey);
switch (auth.kind) {
case 'signer': {
throw new Error('Signer linked by QR is not support sign buffer.');
throw new TxConfirmationCustomError(
'Signer linked by QR is not support sign buffer.'
);
}
case 'signer-deeplink': {
throw new Error('Signer linked by deep link is not support sign buffer.');
throw new TxConfirmationCustomError(
'Signer linked by deep link is not support sign buffer.'
);
}
case 'ledger': {
throw new TxConfirmationCustomError(t('ledger_operation_not_supported'));
}
default: {
const mnemonic = await getMnemonic(sdk, publicKey);
Expand Down
3 changes: 2 additions & 1 deletion packages/uikit/src/state/pro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ export const useProState = () => {
export const useSelectWalletMutation = () => {
const sdk = useAppSdk();
const client = useQueryClient();
const { t } = useTranslation();
return useMutation<void, Error, string>(async publicKey => {
const state = await getWalletState(sdk.storage, publicKey);
if (!state) {
throw new Error('Missing wallet state');
}
await authViaTonConnect(state, signTonConnectOver(sdk, publicKey));
await authViaTonConnect(state, signTonConnectOver(sdk, publicKey, t));

await client.invalidateQueries([QueryKey.pro]);
});
Expand Down

0 comments on commit db09107

Please sign in to comment.