Use source loader for email sprite icons
[ProtonMail-WebClient.git] / packages / wallet / utils / wallet.ts
blob656dfe70f291372ffc1a52f13e0c9be894bdcc6b
1 import { c } from 'ttag';
3 import { type WasmApiWallet, type WasmApiWalletAccount } from '@proton/andromeda';
4 import { type DecryptedKey } from '@proton/shared/lib/interfaces';
6 import { type IWasmApiWalletData } from '../types';
7 import { decryptMnemonicWithUserKey, decryptWalletData, decryptWalletKey } from './crypto';
8 import { getPassphraseLocalStorageKey } from './localStorage';
10 export const buildMapFromWallets = (wallets: IWasmApiWalletData[] = []) => {
11     return wallets.reduce(
12         (acc, wallet) => ({
13             ...acc,
14             [wallet.Wallet.ID]: {
15                 wallet,
16                 accounts: wallet.WalletAccounts.reduce(
17                     (acc, walletAccount) => ({ ...acc, [walletAccount.ID]: walletAccount }),
18                     {}
19                 ),
20             },
21         }),
22         {}
23     );
26 export const getDefaultWalletName = (imported: boolean, wallets: IWasmApiWalletData[], index = 0): string => {
27     const indexStr = index ? ` ${index}` : '';
29     const name = imported
30         ? c('wallet_signup_2024:Wallet setup').t`My imported wallet${indexStr}`
31         : c('wallet_signup_2024:Wallet setup').t`My wallet${indexStr}`;
33     if (wallets.some((wallet) => wallet.Wallet.Name === name)) {
34         return getDefaultWalletName(imported, wallets, index + 1);
35     }
37     return name;
40 export const getDefaultWalletAccountName = (walletAccounts: WasmApiWalletAccount[], index = 2): string => {
41     const indexStr = index.toString();
42     const label = c('wallet_signup_2024:Wallet setup').t`Account ${indexStr}`;
44     if (walletAccounts.some((account) => account.Label === label)) {
45         return getDefaultWalletAccountName(walletAccounts, index + 1);
46     }
48     return label;
51 export const toWalletAccountSelectorOptions = (wallets: IWasmApiWalletData[]) =>
52     wallets?.map((wallet) => [wallet.Wallet, wallet.WalletAccounts] as [WasmApiWallet, WasmApiWalletAccount[]]) ?? [];
54 export const decryptWalletAccount = async ({
55     walletAccount,
56     walletKey,
57 }: {
58     walletAccount: WasmApiWalletAccount;
59     walletKey: CryptoKey;
60 }) => {
61     const [decryptedLabel] = await decryptWalletData([walletAccount.Label], walletKey);
63     return {
64         ...walletAccount,
65         ...(decryptedLabel && { Label: decryptedLabel }),
66     };
69 export const decryptWallet = async ({
70     apiWalletData,
71     userKeys,
72 }: {
73     apiWalletData: IWasmApiWalletData;
74     userKeys: DecryptedKey[];
75 }) => {
76     // A wallet normally cannot be created without a wallet key
77     if (!apiWalletData.WalletKey || !apiWalletData.WalletSettings) {
78         return null;
79     }
81     const { Wallet, WalletKey, WalletSettings, WalletAccounts } = apiWalletData;
83     try {
84         const decryptedWalletKey = await decryptWalletKey(WalletKey.WalletKey, WalletKey.WalletKeySignature, userKeys);
86         const encryptedPassphrase = Wallet.Fingerprint
87             ? localStorage.getItem(getPassphraseLocalStorageKey(Wallet.Fingerprint))
88             : null;
90         // Backward compatibility with mnemonic encrypted with user key in addition to the wallet key
91         const encryptedMnemonic = Wallet.Legacy
92             ? await decryptMnemonicWithUserKey(Wallet.Mnemonic, userKeys)
93             : Wallet.Mnemonic;
94         const [decryptedMnemonic, decryptedWalletName, decryptedPublickey, decryptedPassphrase] =
95             await decryptWalletData(
96                 [encryptedMnemonic, Wallet.Name, Wallet.PublicKey, encryptedPassphrase],
97                 decryptedWalletKey
98             );
100         const decryptedWallet = {
101             ...Wallet,
102             ...(decryptedWalletName && { Name: decryptedWalletName }),
103             ...(decryptedMnemonic && { Mnemonic: decryptedMnemonic }),
104             ...(decryptedPublickey && { PublicKey: decryptedPublickey }),
105             ...(decryptedPassphrase && { Passphrase: decryptedPassphrase }),
106         };
108         const decryptedAccounts = await Promise.all(
109             WalletAccounts.map((account) =>
110                 decryptWalletAccount({ walletAccount: account, walletKey: decryptedWalletKey })
111             )
112         );
114         const data: IWasmApiWalletData = {
115             Wallet: decryptedWallet,
116             WalletAccounts: decryptedAccounts,
117             WalletKey: { ...WalletKey, DecryptedKey: decryptedWalletKey },
118             WalletSettings: WalletSettings,
119         };
121         return data;
122     } catch (e) {
123         const data: IWasmApiWalletData = {
124             Wallet,
125             WalletKey,
126             WalletSettings,
127             WalletAccounts,
128             IsNotDecryptable: true,
129         };
131         return data;
132     }