sync_apply overwrites local password when encrypt-on-disk is true

This commit is contained in:
Lex Berezhny 2019-10-16 09:18:28 -04:00
parent 1075cd9995
commit bcd69f812e
3 changed files with 25 additions and 49 deletions

View file

@ -1618,10 +1618,15 @@ class Daemon(metaclass=JSONRPCServerType):
return hexlify(wallet.hash).decode()
@requires("wallet", conditions=[WALLET_IS_UNLOCKED])
async def jsonrpc_sync_apply(self, password, data=None, encrypt_password=None, wallet_id=None, blocking=False):
async def jsonrpc_sync_apply(self, password, data=None, wallet_id=None, blocking=False):
"""
Apply incoming synchronization data, if provided, and then produce a sync hash and
an encrypted wallet.
Apply incoming synchronization data, if provided, and return a sync hash and update wallet data.
Wallet must be unlocked to perform this operation.
If "encrypt-on-disk" preference is True and supplied password is different from local password,
or there is no local password (because local wallet was not encrypted), then the supplied password
will be used for local encryption (overwriting previous local encryption password).
Usage:
sync_apply <password> [--data=<data>] [--wallet_id=<wallet_id>] [--blocking]

View file

@ -82,10 +82,7 @@ class WalletEncryptionAndSynchronization(CommandTestCase):
daemon = self.daemon
wallet = daemon.wallet_manager.default_wallet
self.assertEqual(
daemon.jsonrpc_wallet_status(),
{'is_locked': False, 'is_encrypted': False}
)
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': False})
self.assertIsNone(daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK))
self.assertWalletEncrypted(wallet.storage.path, False)
@ -97,39 +94,23 @@ class WalletEncryptionAndSynchronization(CommandTestCase):
daemon.jsonrpc_wallet_decrypt() # already not encrypted
daemon.jsonrpc_wallet_encrypt('password')
self.assertEqual(
daemon.jsonrpc_wallet_status(),
{'is_locked': False, 'is_encrypted': True}
)
self.assertEqual(
daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK),
{'encrypt-on-disk': True}
)
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': True})
self.assertEqual(daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK), {'encrypt-on-disk': True})
self.assertWalletEncrypted(wallet.storage.path, True)
daemon.jsonrpc_wallet_lock()
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': True, 'is_encrypted': True})
self.assertEqual(
daemon.jsonrpc_wallet_status(),
{'is_locked': True, 'is_encrypted': True}
)
# can't sign transactions with locked wallet
with self.assertRaises(error.ComponentStartConditionNotMet):
await daemon.jsonrpc_channel_create('@foo', '1.0')
daemon.jsonrpc_wallet_unlock('password')
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': True})
await daemon.jsonrpc_channel_create('@foo', '1.0')
daemon.jsonrpc_wallet_decrypt()
self.assertEqual(
daemon.jsonrpc_wallet_status(),
{'is_locked': False, 'is_encrypted': False}
)
self.assertEqual(
daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK),
{'encrypt-on-disk': False}
)
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': False})
self.assertEqual(daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK), {'encrypt-on-disk': False})
self.assertWalletEncrypted(wallet.storage.path, False)
async def test_sync_with_encryption_and_password_change(self):
@ -137,42 +118,32 @@ class WalletEncryptionAndSynchronization(CommandTestCase):
wallet, wallet2 = daemon.wallet_manager.default_wallet, daemon2.wallet_manager.default_wallet
daemon.jsonrpc_wallet_encrypt('password')
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': True})
self.assertEqual(daemon2.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': False})
self.assertEqual(daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK), {'encrypt-on-disk': True})
self.assertIsNone(daemon2.jsonrpc_preference_get(ENCRYPT_ON_DISK))
self.assertWalletEncrypted(wallet.storage.path, True)
self.assertWalletEncrypted(wallet2.storage.path, False)
self.assertEqual(wallet.encryption_password, 'password')
data = await daemon2.jsonrpc_sync_apply('password2')
with self.assertRaises(ValueError): # wrong password
await daemon.jsonrpc_sync_apply('password', data=data['data'], blocking=True)
await daemon.jsonrpc_sync_apply('password2', data=data['data'], blocking=True)
# encryption did not change from before sync_apply
# password changed
self.assertEqual(wallet.encryption_password, 'password2')
self.assertEqual(daemon.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': True})
self.assertEqual(daemon.jsonrpc_preference_get(ENCRYPT_ON_DISK), {'encrypt-on-disk': True})
self.assertWalletEncrypted(wallet.storage.path, True)
# old password is still used
daemon.jsonrpc_wallet_lock()
self.assertFalse(daemon.jsonrpc_wallet_unlock('password2'))
self.assertTrue(daemon.jsonrpc_wallet_unlock('password'))
# encrypt using new password
daemon.jsonrpc_wallet_encrypt('password2')
# check new password is active
daemon.jsonrpc_wallet_lock()
self.assertFalse(daemon.jsonrpc_wallet_unlock('password'))
self.assertTrue(daemon.jsonrpc_wallet_unlock('password2'))
# propagate disk encryption to daemon2
data = await daemon.jsonrpc_sync_apply('password2')
self.assertEqual(wallet2.encryption_password, None)
await daemon2.jsonrpc_sync_apply('password2', data=data['data'], blocking=True)
# wallet2 is now encrypted using new password
self.assertEqual(wallet.encryption_password, 'password2')
self.assertEqual(daemon2.jsonrpc_wallet_status(), {'is_locked': False, 'is_encrypted': True})
self.assertEqual(daemon2.jsonrpc_preference_get(ENCRYPT_ON_DISK), {'encrypt-on-disk': True})
self.assertWalletEncrypted(wallet.storage.path, True)
self.assertWalletEncrypted(wallet2.storage.path, True)
daemon2.jsonrpc_wallet_lock()
self.assertTrue(daemon2.jsonrpc_wallet_unlock('password2'))

View file

@ -178,7 +178,7 @@ class Wallet:
added_accounts = []
decrypted_data = self.unpack(password, data)
self.preferences.merge(decrypted_data.get('preferences', {}))
if not self.encryption_password and self.preferences.get(ENCRYPT_ON_DISK, False):
if self.preferences.get(ENCRYPT_ON_DISK, False):
self.encryption_password = password
for account_dict in decrypted_data['accounts']:
ledger = manager.get_or_create_ledger(account_dict['ledger'])