mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-03 02:35:20 +00:00
Automate backups:
- backup wallet file on each channel creation - on android, a backup password is entered in settings - on desktop, the backup path is in settings
This commit is contained in:
parent
cee8607218
commit
2dad87cbb4
7 changed files with 64 additions and 25 deletions
|
@ -1199,21 +1199,31 @@ class ElectrumWindow(App):
|
|||
on_success=on_success, on_failure=on_failure, is_change=1)
|
||||
self._password_dialog.open()
|
||||
|
||||
def save_backup(self):
|
||||
def change_backup_password(self):
|
||||
from .uix.dialogs.password_dialog import PasswordDialog
|
||||
from electrum.util import get_backup_dir
|
||||
from electrum.storage import WalletStorage
|
||||
if self._password_dialog is None:
|
||||
self._password_dialog = PasswordDialog()
|
||||
message = _("Create backup.") + '\n' + _("Enter your current PIN:")
|
||||
def on_success(old_password, new_password):
|
||||
new_path = os.path.join(get_backup_dir(self.electrum_config), self.wallet.basename() + '.backup')
|
||||
self.wallet.save_backup(new_path, old_password=old_password, new_password=new_password)
|
||||
self.show_info(_("Backup saved:") + f"\n{new_path}")
|
||||
on_failure = lambda: self.show_error(_("PIN codes do not match"))
|
||||
backup_pubkey = WalletStorage.get_eckey_from_password(new_password).get_public_key_hex()
|
||||
# TODO: use a unique PIN for all wallets
|
||||
self.electrum_config.set_key('pin_code', old_password)
|
||||
self.electrum_config.set_key('backup_pubkey', backup_pubkey)
|
||||
self.show_info(_("Backup password set"))
|
||||
on_failure = lambda: self.show_error(_("Passwords do not match"))
|
||||
self._password_dialog.init(self, wallet=self.wallet, msg=message,
|
||||
on_success=on_success, on_failure=on_failure, is_change=1, is_backup=True)
|
||||
self._password_dialog.open()
|
||||
|
||||
def save_backup(self):
|
||||
new_path = self.wallet.save_backup()
|
||||
if new_path:
|
||||
self.show_info(_("Backup saved:") + f"\n{new_path}")
|
||||
else:
|
||||
self.show_error(_("Backup directory not configured"))
|
||||
|
||||
def export_private_keys(self, pk_label, addr):
|
||||
if self.wallet.is_watching_only():
|
||||
self.show_info(_('This is a watching-only wallet. It does not contain private keys.'))
|
||||
|
|
|
@ -82,6 +82,11 @@ Builder.load_string('''
|
|||
description: _("Send your change to separate addresses.")
|
||||
message: _('Send excess coins to change addresses')
|
||||
action: partial(root.boolean_dialog, 'use_change', _('Use change addresses'), self.message)
|
||||
CardSeparator
|
||||
SettingsItem:
|
||||
title: _('Backups')
|
||||
description: _("Set password for encrypted backups.")
|
||||
action: root.change_backup_password
|
||||
|
||||
# disabled: there is currently only one coin selection policy
|
||||
#CardSeparator
|
||||
|
@ -121,6 +126,9 @@ class SettingsDialog(Factory.Popup):
|
|||
def change_password(self, item, dt):
|
||||
self.app.change_password(self.update)
|
||||
|
||||
def change_backup_password(self, dt):
|
||||
self.app.change_backup_password()
|
||||
|
||||
def language_dialog(self, item, dt):
|
||||
if self._language_dialog is None:
|
||||
l = self.config.get('language', 'en_UK')
|
||||
|
|
|
@ -562,20 +562,15 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
self.gui_object.new_window(filename)
|
||||
|
||||
def backup_wallet(self):
|
||||
path = self.wallet.storage.path
|
||||
wallet_folder = os.path.dirname(path)
|
||||
filename, __ = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
|
||||
if not filename:
|
||||
return
|
||||
new_path = os.path.join(wallet_folder, filename)
|
||||
if new_path == path:
|
||||
return
|
||||
try:
|
||||
self.wallet.save_backup(new_path)
|
||||
new_path = self.wallet.save_backup()
|
||||
except BaseException as reason:
|
||||
self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup"))
|
||||
return
|
||||
self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created"))
|
||||
if new_path:
|
||||
self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created"))
|
||||
else:
|
||||
self.show_message(_("You need to configure a backup directory in your preferences"), title=_("Backup not created"))
|
||||
|
||||
def update_recently_visited(self, filename):
|
||||
recent = self.config.get('recently_open', [])
|
||||
|
@ -617,7 +612,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
self.recently_visited_menu = file_menu.addMenu(_("&Recently open"))
|
||||
file_menu.addAction(_("&Open"), self.open_wallet).setShortcut(QKeySequence.Open)
|
||||
file_menu.addAction(_("&New/Restore"), self.new_wallet).setShortcut(QKeySequence.New)
|
||||
file_menu.addAction(_("&Save Copy"), self.backup_wallet).setShortcut(QKeySequence.SaveAs)
|
||||
file_menu.addAction(_("&Save backup"), self.backup_wallet).setShortcut(QKeySequence.SaveAs)
|
||||
file_menu.addAction(_("Delete"), self.remove_wallet)
|
||||
file_menu.addSeparator()
|
||||
file_menu.addAction(_("&Quit"), self.close)
|
||||
|
|
|
@ -145,6 +145,14 @@ class SettingsDialog(WindowModalDialog):
|
|||
|
||||
# lightning
|
||||
lightning_widgets = []
|
||||
|
||||
backup_help = _("""A backup of your wallet file will be saved to that directory everytime you create a new channel. The backup cannot be used to perform lightning transactions; it may only be used to retrieve the funds in your open channels, using data loss protect (channels will be force closed).""")
|
||||
backup_dir = self.config.get('backup_dir')
|
||||
backup_dir_label = HelpLabel(_('Backup directory') + ':', backup_help)
|
||||
self.backup_dir_e = QPushButton(backup_dir)
|
||||
self.backup_dir_e.clicked.connect(self.select_backup_dir)
|
||||
lightning_widgets.append((backup_dir_label, self.backup_dir_e))
|
||||
|
||||
help_persist = _("""If this option is checked, Electrum will persist as a daemon after
|
||||
you close all your wallet windows. Your local watchtower will keep
|
||||
running, and it will protect your channels even if your wallet is not
|
||||
|
@ -546,6 +554,13 @@ that is always connected to the internet. Configure a port if you want it to be
|
|||
if alias:
|
||||
self.window.fetch_alias()
|
||||
|
||||
def select_backup_dir(self, b):
|
||||
name = self.config.get('backup_dir', '')
|
||||
dirname = QFileDialog.getExistingDirectory(self, "Select your SSL certificate file", name)
|
||||
if dirname:
|
||||
self.config.set_key('backup_dir', dirname)
|
||||
self.backup_dir_e.setText(dirname)
|
||||
|
||||
def select_ssl_certfile(self, b):
|
||||
name = self.config.get('ssl_certfile', '')
|
||||
filename, __ = QFileDialog.getOpenFileName(self, "Select your SSL certificate file", name)
|
||||
|
|
|
@ -842,6 +842,7 @@ class LNWallet(LNWorker):
|
|||
with self.lock:
|
||||
self.channels[chan.channel_id] = chan
|
||||
self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address())
|
||||
self.wallet.save_backup()
|
||||
|
||||
@log_exceptions
|
||||
async def add_peer(self, connect_str: str) -> Peer:
|
||||
|
|
|
@ -442,7 +442,7 @@ def android_data_dir():
|
|||
return PythonActivity.mActivity.getFilesDir().getPath() + '/data'
|
||||
|
||||
def get_backup_dir(config):
|
||||
return android_backup_dir() if 'ANDROID_DATA' in os.environ else config.path
|
||||
return android_backup_dir() if 'ANDROID_DATA' in os.environ else config.get('backup_dir')
|
||||
|
||||
|
||||
def ensure_sparse_file(filename):
|
||||
|
|
|
@ -51,7 +51,7 @@ from .util import (NotEnoughFunds, UserCancelled, profiler,
|
|||
WalletFileException, BitcoinException, MultipleSpendMaxTxOutputs,
|
||||
InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
|
||||
Fiat, bfh, bh2u, TxMinedInfo, quantize_feerate, create_bip21_uri, OrderedDictWithIndex)
|
||||
from .util import PR_TYPE_ONCHAIN, PR_TYPE_LN
|
||||
from .util import PR_TYPE_ONCHAIN, PR_TYPE_LN, get_backup_dir
|
||||
from .simple_config import SimpleConfig
|
||||
from .bitcoin import (COIN, is_address, address_to_script,
|
||||
is_minikey, relayfee, dust_threshold)
|
||||
|
@ -263,15 +263,25 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
|||
if self.storage:
|
||||
self.db.write(self.storage)
|
||||
|
||||
def save_backup(self, path, *, old_password=None, new_password=None):
|
||||
def save_backup(self):
|
||||
new_db = WalletDB(self.db.dump(), manual_upgrades=False)
|
||||
new_db.put('is_backup', True)
|
||||
new_storage = WalletStorage(path)
|
||||
new_storage._encryption_version = StorageEncryptionVersion.PLAINTEXT
|
||||
w2 = Wallet(new_db, new_storage, config=self.config)
|
||||
if new_password:
|
||||
w2.update_password(old_password, new_password, encrypt_storage=True)
|
||||
w2.save_db()
|
||||
new_path = os.path.join(get_backup_dir(self.config), self.basename() + '.backup')
|
||||
if new_path is None:
|
||||
return
|
||||
new_storage = WalletStorage(new_path)
|
||||
if 'ANDROID_DATA' in os.environ:
|
||||
pin_code = self.config.get('pin_code')
|
||||
w2 = Wallet(new_db, None, config=self.config)
|
||||
w2.update_password(pin_code, None)
|
||||
new_storage._encryption_version = StorageEncryptionVersion.USER_PASSWORD
|
||||
new_storage.pubkey = self.config.get('backup_pubkey')
|
||||
else:
|
||||
new_storage._encryption_version = self.storage._encryption_version
|
||||
new_storage.pubkey = self.storage.pubkey
|
||||
new_db.set_modified(True)
|
||||
new_db.write(new_storage)
|
||||
return new_path
|
||||
|
||||
def has_lightning(self):
|
||||
return bool(self.lnworker)
|
||||
|
|
Loading…
Add table
Reference in a new issue