Browse Source

cleanup storage and fix tracvis test

283
ThomasV 8 years ago
parent
commit
411832c4ce
  1. 11
      electrum
  2. 3
      gui/qt/__init__.py
  3. 15
      gui/qt/installwizard.py
  4. 7
      gui/stdio.py
  5. 5
      gui/text.py
  6. 3
      lib/__init__.py
  7. 2
      lib/base_wizard.py
  8. 9
      lib/daemon.py
  9. 77
      lib/storage.py
  10. 1
      lib/wallet.py

11
electrum

@ -124,7 +124,7 @@ def run_non_RPC(config):
cmdname = config.get('cmd') cmdname = config.get('cmd')
storage = WalletStorage(config.get_wallet_path()) storage = WalletStorage(config.get_wallet_path())
if storage.file_exists: if storage.file_exists():
sys.exit("Error: Remove the existing wallet first!") sys.exit("Error: Remove the existing wallet first!")
def password_dialog(): def password_dialog():
@ -187,7 +187,7 @@ def run_non_RPC(config):
def init_daemon(config_options): def init_daemon(config_options):
config = SimpleConfig(config_options) config = SimpleConfig(config_options)
storage = WalletStorage(config.get_wallet_path()) storage = WalletStorage(config.get_wallet_path())
if not storage.file_exists: if not storage.file_exists():
print_msg("Error: Wallet file not found.") print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0) sys.exit(0)
@ -222,7 +222,7 @@ def init_cmdline(config_options, server):
# instanciate wallet for command-line # instanciate wallet for command-line
storage = WalletStorage(config.get_wallet_path()) storage = WalletStorage(config.get_wallet_path())
if cmd.requires_wallet and not storage.file_exists: if cmd.requires_wallet and not storage.file_exists():
print_msg("Error: Wallet file not found.") print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0) sys.exit(0)
@ -233,8 +233,6 @@ def init_cmdline(config_options, server):
print_stderr("Exposing a single private key can compromise your entire wallet!") print_stderr("Exposing a single private key can compromise your entire wallet!")
print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.") print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.")
if not storage.is_encrypted():
storage.read(None)
# commands needing password # commands needing password
if (cmd.requires_wallet and storage.is_encrypted() and server is None)\ if (cmd.requires_wallet and storage.is_encrypted() and server is None)\
or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())): or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())):
@ -263,7 +261,8 @@ def run_offline_command(config, config_options):
password = config_options.get('password') password = config_options.get('password')
if cmd.requires_wallet: if cmd.requires_wallet:
storage = WalletStorage(config.get_wallet_path()) storage = WalletStorage(config.get_wallet_path())
storage.read(password if storage.is_encrypted() else None) if storage.is_encrypted():
storage.decrypt(password)
wallet = Wallet(storage) wallet = Wallet(storage)
else: else:
wallet = None wallet = None

3
gui/qt/__init__.py

@ -162,13 +162,12 @@ class ElectrumGui:
wallet = self.daemon.get_wallet(path) wallet = self.daemon.get_wallet(path)
if not wallet: if not wallet:
storage = WalletStorage(path) storage = WalletStorage(path)
if not storage.file_exists or storage.is_encrypted(): if not storage.file_exists() or storage.is_encrypted():
wizard = InstallWizard(self.config, self.app, self.plugins, storage) wizard = InstallWizard(self.config, self.app, self.plugins, storage)
wallet = wizard.run_and_get_wallet() wallet = wizard.run_and_get_wallet()
if not wallet: if not wallet:
return return
else: else:
storage.read(None)
wallet = Wallet(storage) wallet = Wallet(storage)
wallet.start_threads(self.daemon.network) wallet.start_threads(self.daemon.network)
self.daemon.add_wallet(wallet) self.daemon.add_wallet(wallet)

15
gui/qt/installwizard.py

@ -6,7 +6,7 @@ from PyQt4.QtCore import *
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
import electrum import electrum
from electrum.wallet import Wallet, WalletStorage from electrum import Wallet, WalletStorage
from electrum.util import UserCancelled, InvalidPassword from electrum.util import UserCancelled, InvalidPassword
from electrum.base_wizard import BaseWizard from electrum.base_wizard import BaseWizard
from electrum.i18n import _ from electrum.i18n import _
@ -167,12 +167,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
vbox.addLayout(hbox) vbox.addLayout(hbox)
self.pw_e = None self.pw_e = None
if not self.storage.file_exists: if not self.storage.file_exists():
msg = _("This file does not exist.") + '\n' \ msg = _("This file does not exist.") + '\n' \
+ _("Press 'Next' to create this wallet, or chose another file.") + _("Press 'Next' to create this wallet, or chose another file.")
vbox.addWidget(QLabel(msg)) vbox.addWidget(QLabel(msg))
elif self.storage.file_exists and self.storage.is_encrypted(): elif self.storage.file_exists() and self.storage.is_encrypted():
msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.') msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.')
vbox.addWidget(QLabel(msg)) vbox.addWidget(QLabel(msg))
hbox2 = QHBoxLayout() hbox2 = QHBoxLayout()
@ -195,20 +195,19 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
while True: while True:
update_layout() update_layout()
if self.storage.file_exists and not self.storage.is_encrypted(): if self.storage.file_exists() and not self.storage.is_encrypted():
self.storage.read(None)
break break
if not self.loop.exec_(): if not self.loop.exec_():
return return
if not self.storage.file_exists: if not self.storage.file_exists():
break break
if self.storage.file_exists and self.storage.is_encrypted(): if self.storage.file_exists() and self.storage.is_encrypted():
password = unicode(self.pw_e.text()) password = unicode(self.pw_e.text())
try: try:
self.storage.read(password) self.storage.decrypt(password)
break break
except InvalidPassword as e: except InvalidPassword as e:
QMessageBox.information(None, _('Error'), str(e), _('OK')) QMessageBox.information(None, _('Error'), str(e), _('OK'))

7
gui/stdio.py

@ -1,7 +1,7 @@
from decimal import Decimal from decimal import Decimal
_ = lambda x:x _ = lambda x:x
#from i18n import _ #from i18n import _
from electrum.wallet import WalletStorage, Wallet from electrum import WalletStorage, Wallet
from electrum.util import format_satoshis, set_verbosity, StoreDict from electrum.util import format_satoshis, set_verbosity, StoreDict
from electrum.bitcoin import is_valid, COIN, TYPE_ADDRESS from electrum.bitcoin import is_valid, COIN, TYPE_ADDRESS
from electrum.network import filter_protocol from electrum.network import filter_protocol
@ -19,8 +19,9 @@ class ElectrumGui:
if not storage.file_exists: if not storage.file_exists:
print "Wallet not found. try 'electrum create'" print "Wallet not found. try 'electrum create'"
exit() exit()
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None if storage.is_encrypted():
storage.read(password) password = getpass.getpass('Password:', stream=None)
storage.decrypt(password)
self.done = 0 self.done = 0
self.last_balance = "" self.last_balance = ""

5
gui/text.py

@ -22,8 +22,9 @@ class ElectrumGui:
if not storage.file_exists: if not storage.file_exists:
print "Wallet not found. try 'electrum create'" print "Wallet not found. try 'electrum create'"
exit() exit()
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None if storage.is_encrypted():
storage.read(password) password = getpass.getpass('Password:', stream=None)
storage.decrypt(password)
self.wallet = Wallet(storage) self.wallet = Wallet(storage)
self.wallet.start_threads(self.network) self.wallet.start_threads(self.network)
self.contacts = StoreDict(self.config, 'contacts') self.contacts = StoreDict(self.config, 'contacts')

3
lib/__init__.py

@ -1,6 +1,7 @@
from version import ELECTRUM_VERSION from version import ELECTRUM_VERSION
from util import format_satoshis, print_msg, print_error, set_verbosity from util import format_satoshis, print_msg, print_error, set_verbosity
from wallet import Synchronizer, WalletStorage, Wallet, Imported_Wallet from wallet import Synchronizer, Wallet, Imported_Wallet
from storage import WalletStorage
from coinchooser import COIN_CHOOSERS from coinchooser import COIN_CHOOSERS
from network import Network, pick_random_server from network import Network, pick_random_server
from interface import Connection, Interface from interface import Connection, Interface

2
lib/base_wizard.py

@ -26,7 +26,7 @@
import os import os
import bitcoin import bitcoin
import keystore import keystore
from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, WalletStorage, wallet_types from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types
from i18n import _ from i18n import _
from plugins import run_hook from plugins import run_hook

9
lib/daemon.py

@ -35,7 +35,8 @@ from version import ELECTRUM_VERSION
from network import Network from network import Network
from util import json_decode, DaemonThread from util import json_decode, DaemonThread
from util import print_msg, print_error, print_stderr, UserCancelled from util import print_msg, print_error, print_stderr, UserCancelled
from wallet import WalletStorage, Wallet from wallet import Wallet
from storage import WalletStorage
from commands import known_commands, Commands from commands import known_commands, Commands
from simple_config import SimpleConfig from simple_config import SimpleConfig
from plugins import run_hook from plugins import run_hook
@ -203,15 +204,13 @@ class Daemon(DaemonThread):
wallet = self.wallets[path] wallet = self.wallets[path]
return wallet return wallet
storage = WalletStorage(path) storage = WalletStorage(path)
if not storage.file_exists: if not storage.file_exists():
return return
if storage.is_encrypted(): if storage.is_encrypted():
password = password_getter() password = password_getter()
if not password: if not password:
raise UserCancelled() raise UserCancelled()
else: storage.decrypt(password)
password = None
storage.read(password)
if storage.requires_split(): if storage.requires_split():
return return
if storage.requires_upgrade(): if storage.requires_upgrade():

77
lib/storage.py

@ -64,52 +64,19 @@ def multisig_type(wallet_type):
class WalletStorage(PrintError): class WalletStorage(PrintError):
def __init__(self, path): def __init__(self, path):
self.print_error("wallet path", path)
self.lock = threading.RLock() self.lock = threading.RLock()
self.data = {} self.data = {}
self.path = path self.path = path
self.file_exists = self.path and os.path.exists(self.path)
self.modified = False self.modified = False
self.pubkey = None self.pubkey = None
if self.file_exists():
def decrypt(self, s, password):
# Note: hardware wallets should use a seed-derived key and not require a password.
# Thus, we need to expose keystore metadata
if password is None:
self.pubkey = None
return s
secret = pbkdf2.PBKDF2(password, '', iterations = 1024, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
ec_key = bitcoin.EC_KEY(secret)
self.pubkey = ec_key.get_public_key()
return zlib.decompress(ec_key.decrypt_message(s)) if s else None
def set_password(self, pw, encrypt):
"""Set self.pubkey"""
self.put('use_encryption', bool(pw))
self.decrypt(None, pw if encrypt else None)
def is_encrypted(self):
try:
with open(self.path, "r") as f: with open(self.path, "r") as f:
s = f.read(8) self.raw = f.read()
except IOError: if not self.is_encrypted():
return self.load_data(self.raw)
try:
return base64.b64decode(s).startswith('BIE1')
except:
return False
def read(self, password): def load_data(self, s):
"""Read the contents of the wallet file."""
self.print_error("wallet path", self.path)
try:
with open(self.path, "r") as f:
s = f.read()
except IOError:
return
if not s:
return
# Decrypt wallet.
s = self.decrypt(s, password)
try: try:
self.data = json.loads(s) self.data = json.loads(s)
except: except:
@ -119,6 +86,33 @@ class WalletStorage(PrintError):
l = plugin_loaders.get(t) l = plugin_loaders.get(t)
if l: l() if l: l()
def is_encrypted(self):
try:
return base64.b64decode(self.raw).startswith('BIE1')
except:
return False
def file_exists(self):
return self.path and os.path.exists(self.path)
def get_key(self, password):
secret = pbkdf2.PBKDF2(password, '', iterations = 1024, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
ec_key = bitcoin.EC_KEY(secret)
return ec_key
def decrypt(self, password):
ec_key = self.get_key(password)
s = zlib.decompress(ec_key.decrypt_message(self.raw)) if self.raw else None
self.load_data(s)
def set_password(self, password, encrypt):
self.put('use_encryption', bool(password))
if encrypt and password:
ec_key = self.get_key(password)
self.pubkey = ec_key.get_public_key()
else:
self.pubkey = None
def get(self, key, default=None): def get(self, key, default=None):
with self.lock: with self.lock:
v = self.data.get(key) v = self.data.get(key)
@ -150,7 +144,6 @@ class WalletStorage(PrintError):
self.put('seed_version', FINAL_SEED_VERSION) self.put('seed_version', FINAL_SEED_VERSION)
with self.lock: with self.lock:
self._write() self._write()
self.file_exists = True
def _write(self): def _write(self):
if threading.currentThread().isDaemon(): if threading.currentThread().isDaemon():
@ -230,7 +223,7 @@ class WalletStorage(PrintError):
return result return result
def requires_upgrade(self): def requires_upgrade(self):
return self.file_exists and self.get_seed_version() != FINAL_SEED_VERSION return self.file_exists() and self.get_seed_version() != FINAL_SEED_VERSION
def upgrade(self): def upgrade(self):
self.convert_imported() self.convert_imported()
@ -371,7 +364,7 @@ class WalletStorage(PrintError):
action = run_hook('get_action', self) action = run_hook('get_action', self)
if action: if action:
return action return action
if not self.file_exists: if not self.file_exists():
return 'new' return 'new'
def get_seed_version(self): def get_seed_version(self):

1
lib/wallet.py

@ -63,7 +63,6 @@ from mnemonic import Mnemonic
import paymentrequest import paymentrequest
from storage import WalletStorage
TX_STATUS = [ TX_STATUS = [
_('Replaceable'), _('Replaceable'),

Loading…
Cancel
Save