From 270f77df2462af718f11af6bb9a1431fcb4c44f8 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Sun, 13 Oct 2019 23:43:06 -0400 Subject: [PATCH] wallet encryption --- lbry/lbry/extras/daemon/Components.py | 2 - lbry/lbry/extras/daemon/Daemon.py | 109 ++++---------------------- lbry/lbry/wallet/manager.py | 40 +--------- torba/torba/client/wallet.py | 37 +++++++++ 4 files changed, 55 insertions(+), 133 deletions(-) diff --git a/lbry/lbry/extras/daemon/Components.py b/lbry/lbry/extras/daemon/Components.py index f75260f3a..e0ad1a7c9 100644 --- a/lbry/lbry/extras/daemon/Components.py +++ b/lbry/lbry/extras/daemon/Components.py @@ -252,8 +252,6 @@ class WalletComponent(Component): 'blocks': max(local_height, 0), 'blocks_behind': max(remote_height - local_height, 0), 'best_blockhash': best_hash, - 'is_encrypted': self.wallet_manager.use_encryption, - 'is_locked': not self.wallet_manager.is_wallet_unlocked, } async def start(self): diff --git a/lbry/lbry/extras/daemon/Daemon.py b/lbry/lbry/extras/daemon/Daemon.py index 1d64e9e61..a0602aa50 100644 --- a/lbry/lbry/extras/daemon/Daemon.py +++ b/lbry/lbry/extras/daemon/Daemon.py @@ -1166,6 +1166,22 @@ class Daemon(metaclass=JSONRPCServerType): ) return dict_values_to_lbc(balance) + def jsonrpc_wallet_status(self, wallet_id=None): + """ + Status of wallet including encryption/lock state. + + Usage: + wallet_status [ | --wallet_id=] + + Options: + --wallet_id= : (str) status of specific wallet + + Returns: + Dictionary of wallet status information. + """ + wallet = self.wallet_manager.get_wallet_or_default(wallet_id) + return {'is_encrypted': wallet.is_encrypted, 'is_locked': wallet.is_locked} + @requires(WALLET_COMPONENT) def jsonrpc_wallet_unlock(self, password, wallet_id=None): """ @@ -1501,98 +1517,6 @@ class Daemon(metaclass=JSONRPCServerType): return account - @deprecated('wallet_unlock') - @requires(WALLET_COMPONENT) - def jsonrpc_account_unlock(self, password, account_id=None, wallet_id=None): - """ - Unlock an encrypted account - - Usage: - account_unlock ( | --password=) - [ | --account_id=] - [--wallet_id=] - - Options: - --password= : (str) password to use for unlocking - --account_id= : (str) id for the account to unlock, unlocks default account - if not provided - --wallet_id= : (str) restrict operation to specific wallet - - Returns: - (bool) true if account is unlocked, otherwise false - """ - wallet = self.wallet_manager.get_wallet_or_default(wallet_id) - return self.wallet_manager.unlock_account( - password, wallet.get_account_or_default(account_id) - ) - - @deprecated('wallet_lock') - @requires(WALLET_COMPONENT) - def jsonrpc_account_lock(self, account_id=None, wallet_id=None): - """ - Lock an unlocked account - - Usage: - account_lock [ | --account_id=] [--wallet_id=] - - Options: - --account_id= : (str) id for the account to lock - --wallet_id= : (str) restrict operation to specific wallet - - Returns: - (bool) true if account is locked, otherwise false - """ - wallet = self.wallet_manager.get_wallet_or_default(wallet_id) - return self.wallet_manager.lock_account( - wallet.get_account_or_default(account_id) - ) - - @deprecated('wallet_decrypt') - @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - def jsonrpc_account_decrypt(self, account_id=None, wallet_id=None): - """ - Decrypt an encrypted account, this will remove the wallet password. The account must be unlocked to decrypt it - - Usage: - account_decrypt [ | --account_id=] [--wallet_id=] - - Options: - --account_id= : (str) id for the account to decrypt - --wallet_id= : (str) restrict operation to specific wallet - - Returns: - (bool) true if wallet is decrypted, otherwise false - """ - wallet = self.wallet_manager.get_wallet_or_default(wallet_id) - return self.wallet_manager.decrypt_account( - wallet.get_account_or_default(account_id) - ) - - @deprecated('wallet_encrypt') - @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) - def jsonrpc_account_encrypt(self, new_password, account_id=None, wallet_id=None): - """ - Encrypt an unencrypted account with a password - - Usage: - account_encrypt ( | --new_password=) - [ | --account_id=] - [--wallet_id=] - - Options: - --new_password= : (str) password to encrypt account - --account_id= : (str) id for the account to encrypt, encrypts - default account if not provided - --wallet_id= : (str) restrict operation to specific wallet - - Returns: - (bool) true if wallet is decrypted, otherwise false - """ - wallet = self.wallet_manager.get_wallet_or_default(wallet_id) - return self.wallet_manager.encrypt_account( - new_password, wallet.get_account_or_default(account_id) - ) - @requires("wallet") def jsonrpc_account_max_address_gap(self, account_id, wallet_id=None): """ @@ -1720,6 +1644,7 @@ class Daemon(metaclass=JSONRPCServerType): """ wallet = self.wallet_manager.get_wallet_or_default(wallet_id) + assert not wallet.is_locked, "Cannot sync apply on a locked wallet." if data is not None: added_accounts = wallet.merge(self.wallet_manager, password, data) if added_accounts and self.ledger.network.is_connected: diff --git a/lbry/lbry/wallet/manager.py b/lbry/lbry/wallet/manager.py index 062a0eab4..d9e9f436c 100644 --- a/lbry/lbry/wallet/manager.py +++ b/lbry/lbry/wallet/manager.py @@ -26,42 +26,8 @@ class LbryWalletManager(BaseWalletManager): def db(self) -> WalletDatabase: return self.ledger.db - @property - def use_encryption(self): - return self.default_account.serialize_encrypted - - @property - def is_wallet_unlocked(self): - return not self.default_account.encrypted - def check_locked(self): - return self.default_account.encrypted - - def decrypt_account(self, account): - assert account.password is not None, "account is not unlocked" - assert not account.encrypted, "account is not unlocked" - account.serialize_encrypted = False - self.save() - return not account.encrypted and not account.serialize_encrypted - - def encrypt_account(self, password, account): - assert not account.encrypted, "account is already encrypted" - account.encrypt(password) - account.serialize_encrypted = True - self.save() - self.unlock_account(password, account) - return account.serialize_encrypted - - def unlock_account(self, password, account): - assert account.encrypted, "account is not locked" - account.decrypt(password) - return not account.encrypted - - def lock_account(self, account): - assert account.password is not None, "account is already locked" - assert not account.encrypted and account.serialize_encrypted, "account is not encrypted" - account.encrypt(account.password) - return account.encrypted + return self.default_wallet.is_locked @staticmethod def migrate_lbryum_to_torba(path): @@ -210,7 +176,3 @@ class LbryWalletManager(BaseWalletManager): tx = self.ledger.transaction_class(unhexlify(raw)) await self.ledger.maybe_verify_transaction(tx, height) return tx - - def save(self): - for wallet in self.wallets: - wallet.save() diff --git a/torba/torba/client/wallet.py b/torba/torba/client/wallet.py index 54355a797..12fac2efc 100644 --- a/torba/torba/client/wallet.py +++ b/torba/torba/client/wallet.py @@ -170,6 +170,43 @@ class Wallet: added_accounts.append(new_account) return added_accounts + @property + def is_locked(self) -> bool: + for account in self.accounts: + if account.encrypted: + return True + return False + + def unlock(self, password): + for account in self.accounts: + if account.encrypted: + account.decrypt(password) + + def lock(self): + for account in self.accounts: + if not account.encrypted: + account.encrypt(account.password) + + @property + def is_encrypted(self) -> bool: + for account in self.accounts: + if account.serialize_encrypted: + return True + return False + + def decrypt(self): + for account in self.accounts: + account.serialize_encrypted = False + self.save() + + def encrypt(self, password): + for account in self.accounts: + if not self.encrypted: + account.encrypt(password) + account.serialize_encrypted = True + self.save() + self.unlock(password) + class WalletStorage: