Merge branch 'torba-encryption'

This commit is contained in:
Jack Robison 2018-09-25 14:59:54 -04:00
commit 202a957a1a
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
3 changed files with 67 additions and 63 deletions

View file

@ -175,7 +175,7 @@ class DHTHasContacts(RequiredCondition):
return len(component.contacts) > 0
class WalletIsLocked(RequiredCondition):
class WalletIsUnlocked(RequiredCondition):
name = WALLET_IS_UNLOCKED
component = WALLET_COMPONENT
message = "your wallet is locked"
@ -1361,64 +1361,77 @@ class Daemon(AuthJSONRPCServer):
return result
@requires(WALLET_COMPONENT)
@defer.inlineCallbacks
def jsonrpc_account_unlock(self, password):
def jsonrpc_account_unlock(self, password, account_id=None):
"""
Unlock an encrypted account
Usage:
account_unlock (<password> | --password=<password>)
account_unlock (<password> | --password=<password>) [<account_id> | --account_id=<account_id>]
Options:
--password=<password> : (str) password for unlocking wallet
--account_id=<account_id> : (str) id for the account to unlock
Returns:
(bool) true if account is unlocked, otherwise false
"""
# the check_locked() in the if statement is needed because that is what sets
# the wallet_unlocked_d deferred ¯\_(ツ)_/¯
if not self.wallet_manager.check_locked():
d = self.wallet_manager.wallet_unlocked_d
d.callback(password)
result = yield d
else:
result = True
response = yield self._render_response(result)
defer.returnValue(response)
return self.wallet_manager.unlock_account(
password, self.get_account_or_default(account_id, lbc_only=False)
)
@requires(WALLET_COMPONENT)
def jsonrpc_account_lock(self, account_id=None):
"""
Lock an unlocked account
Usage:
account_lock [<account_id> | --account_id=<account_id>]
Options:
--account_id=<account_id> : (str) id for the account to lock
Returns:
(bool) true if account is locked, otherwise false
"""
return self.wallet_manager.lock_account(self.get_account_or_default(account_id, lbc_only=False))
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
def jsonrpc_account_decrypt(self):
def jsonrpc_account_decrypt(self, account_id=None):
"""
Decrypt an encrypted account, this will remove the wallet password
Usage:
account_decrypt
account_decrypt [<account_id> | --account_id=<account_id>]
Options:
None
--account_id=<account_id> : (str) id for the account to decrypt
Returns:
(bool) true if wallet is decrypted, otherwise false
"""
return self.wallet_manager.decrypt_wallet()
return self.wallet_manager.decrypt_account(self.get_account_or_default(account_id, lbc_only=False))
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
def jsonrpc_account_encrypt(self, new_password):
def jsonrpc_account_encrypt(self, new_password, account_id=None):
"""
Encrypt a wallet with a password, if the wallet is already encrypted this will update
the password
Encrypt an unencrypted account with a password
Usage:
wallet_encrypt (<new_password> | --new_password=<new_password>)
wallet_encrypt (<new_password> | --new_password=<new_password>) [<account_id> | --account_id=<account_id>]
Options:
--new_password=<new_password> : (str) password string to be used for encrypting wallet
--account_id=<account_id> : (str) id for the account to encrypt
Returns:
(bool) true if wallet is decrypted, otherwise false
"""
return self.wallet_manager.encrypt_wallet(new_password)
return self.wallet_manager.encrypt_account(
new_password,
self.get_account_or_default(account_id, lbc_only=False)
)
@requires("wallet")
def jsonrpc_account_max_address_gap(self, account_id):

View file

@ -12,6 +12,7 @@ from .account import generate_certificate
from .transaction import Transaction
from .database import WalletDatabase
log = logging.getLogger(__name__)
@ -54,8 +55,7 @@ class LbryWalletManager(BaseWalletManager):
@property
def use_encryption(self):
# TODO: implement this
return False
return self.default_account.serialize_encrypted
@property
def is_first_run(self):
@ -63,10 +63,35 @@ class LbryWalletManager(BaseWalletManager):
@property
def is_wallet_unlocked(self):
return True
return not self.default_account.encrypted
def check_locked(self):
return defer.succeed(False)
return defer.succeed(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()
return account.encrypted and 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
@staticmethod
def migrate_lbryum_to_torba(path):

View file

@ -247,37 +247,3 @@ class WalletTest(unittest.TestCase):
self.assertFailure(d, InsufficientFundsError)
return d
class WalletEncryptionTests(unittest.TestCase):
skip = "Needs to be ported to the new wallet."
def setUp(self):
user_dir = tempfile.mkdtemp()
self.wallet = MocLbryumWallet(user_dir)
return self.wallet.setup(password="password")
def tearDown(self):
return self.wallet.stop()
def test_unlock_wallet(self):
self.wallet._cmd_runner = Commands(
self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password")
cmd_runner = self.wallet.get_cmd_runner()
cmd_runner.unlock_wallet("password")
self.assertIsNone(cmd_runner.new_password)
self.assertEqual(cmd_runner._password, "password")
def test_encrypt_decrypt_wallet(self):
self.wallet._cmd_runner = Commands(
self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password")
self.wallet.encrypt_wallet("secret2", False)
self.wallet.decrypt_wallet()
def test_update_password_keyring_off(self):
self.wallet.config.use_keyring = False
self.wallet._cmd_runner = Commands(
self.wallet.config, self.wallet.wallet, self.wallet.network, None, "password")
# no keyring available, so ValueError is expected
with self.assertRaises(ValueError):
self.wallet.encrypt_wallet("secret2", True)