// Copyright (c) 2020-2021 Drew Lemmy // This file is part of TenebraWeb 2 under AGPL-3.0. // Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt import { aesGcmDecrypt } from "@utils/crypto"; import { WalletAddressMap } from ".."; export interface EncryptedWallet { encPassword: string; encPrivatekey: string } export interface DecryptedWallet { password: string; privatekey: string } /** Decrypts a wallet's password and privatekey. */ export async function decryptWallet( masterPassword: string, wallet: EncryptedWallet ): Promise<DecryptedWallet | null> { try { const decPassword = await aesGcmDecrypt(wallet.encPassword, masterPassword); const decPrivatekey = await aesGcmDecrypt(wallet.encPrivatekey, masterPassword); return { password: decPassword, privatekey: decPrivatekey }; } catch (e) { // OperationError usually means decryption failure if (e.name === "OperationError") return null; console.error(e); return null; } } export const DecryptErrorGone = Symbol("KWDecryptErrorGone"); export const DecryptErrorFailed = Symbol("KWDecryptErrorFailed"); // TODO: use these in decryptWallet too (will require some refactoring) export type DecryptResult = DecryptedWallet | typeof DecryptErrorGone | typeof DecryptErrorFailed; export type DecryptedAddresses = Record<string, DecryptResult>; export type ValidDecryptedAddresses = Record<string, DecryptedWallet>; /** Decrypts an array of wallets by address at once. */ export async function decryptAddresses( masterPassword: string, walletAddressMap: WalletAddressMap, addresses: string[] ): Promise<DecryptedAddresses> { // Ensure the array of addresses is unique const uniqAddresses = [...new Set(addresses)]; const out: DecryptedAddresses = {}; // Try to decrypt each address for (const address of uniqAddresses) { // Find the wallet by address and verify it actually exists const wallet = walletAddressMap[address]; if (!wallet) { out[address] = DecryptErrorGone; continue; } // Decrypt the wallet, erroring if it fails const dec = await decryptWallet(masterPassword, wallet); if (!dec) { out[address] = DecryptErrorFailed; continue; } out[address] = dec; } return out; }