def __init__(self, **kwargs):
        '''Get app settings from options'''
        self.make_commit = kwargs.pop('make_commit')
        self.password = kwargs.pop('password')
        self.signing_key = kwargs.pop('signing_key')
        self.testnet = kwargs.pop('testnet')
        self.wallet_path = kwargs.pop('wallet')

        script_config = read_config()
        if script_config:
            self.make_commit = (self.make_commit
                                or script_config.get('make_commit', False))
            self.signing_key = (self.signing_key
                                or script_config.get('signing_key', False))
            self.testnet = (self.testnet
                            or script_config.get('testnet', False))
            self.wallet_path = (self.wallet_path
                                or script_config.get('wallet', False))
        if self.wallet_path:
            self.wallet_path = os.path.expanduser(self.wallet_path)
        self.config_options = {'cwd': os.getcwd()}
        self.config_options['password'] = self.password
        self.config_options['testnet'] = self.testnet
        self.config_options['wallet_path'] = self.wallet_path
        self.config = SimpleConfig(self.config_options)
        if self.config.get('testnet'):
            constants.set_testnet()
        self.storage = WalletStorage(self.config.get_wallet_path())
예제 #2
0
 def test_write(self):
     path = os.path.join(self.electrum_path, 'default_wallet')
     storage = WalletStorage(path)
     data = 'testdata'
     storage.write(data)
     with open(path, 'r') as fd:
         assert fd.read() == data
예제 #3
0
 def test_write_with_permission_error_fails(self):
     path = os.path.join(self.electrum_path, 'default_wallet')
     storage = WalletStorage(path)
     storage.write_attempts = 1
     data = 'testdata'
     with patch('os.replace', new_callable=ReplaceWithPermissionErrorMock):
         with self.assertRaises(PermissionError):
             storage.write(data)
예제 #4
0
 def test_write_with_permission_error_done(self):
     path = os.path.join(self.electrum_path, 'default_wallet')
     storage = WalletStorage(path)
     data = 'testdata'
     with patch('os.replace', new_callable=ReplaceWithPermissionErrorMock):
         storage.write(data)
     with open(path, 'r') as fd:
         assert fd.read() == data
예제 #5
0
    def test_read_dictionary_from_file(self):

        some_dict = {"a":"b", "c":"d"}
        contents = json.dumps(some_dict)
        with open(self.wallet_path, "w") as f:
            contents = f.write(contents)

        storage = WalletStorage(self.wallet_path)
        db = WalletDB(storage.read(), manual_upgrades=True)
        self.assertEqual("b", db.get("a"))
        self.assertEqual("d", db.get("c"))
예제 #6
0
    def test_check_need_confirm_password(self):
        wiz = self.wizard
        storage = WalletStorage(self.wallet_path)
        d = {'wallet_type': 'standard', "seed_version": FINAL_SEED_VERSION}
        d['wallet_type'] = '2of3'
        d['x1/'] = X1_VIEW_ONLY
        d['x2/'] = X2
        db = WalletDB(json.dumps(d), manual_upgrades=True)
        db.write(storage)
        storage = WalletStorage(self.wallet_path)
        wiz.continue_multisig_setup(storage)

        wiz.unfinished_check_password = storage.check_password
        assert wiz.check_need_confirm_password()
        wiz.unfinished_check_password = None
        assert not wiz.check_need_confirm_password()
        wiz.keystores[1].update_password(None, 'test')
        assert wiz.check_need_confirm_password()
예제 #7
0
    def test_continue_multisig_setup(self):
        wiz = self.wizard
        storage = WalletStorage(self.wallet_path)
        d = {'wallet_type': 'standard', "seed_version": FINAL_SEED_VERSION}
        d['wallet_type'] = '2of3'
        d['x1/'] = X1
        db = WalletDB(json.dumps(d), manual_upgrades=True)
        assert db.check_unfinished_multisig()
        db.write(storage)
        storage = WalletStorage(self.wallet_path)
        wiz.continue_multisig_setup(storage)
        assert wiz.unfinished_multisig
        assert wiz.unfinished_enc_version == StorageEncryptionVersion.PLAINTEXT
        assert not wiz.unfinished_check_password
        assert wiz.last_method == 'continue_multisig_setup_dialog'
        last_args = wiz.last_args
        assert last_args[0:2] == (2, 3)  # m, n
        assert last_args[2] == wiz.keystores  # keystores
        assert len(last_args[2]) == 1
        k1 = last_args[2][0]
        assert type(k1) == BIP32_KeyStore
        assert k1.get_root_fingerprint() == '3f635a63'
        assert last_args[3] == wiz.choose_keystore  # run_next

        d['x2/'] = X2
        db = WalletDB(json.dumps(d), manual_upgrades=True)
        assert db.check_unfinished_multisig()
        db.write(storage)
        storage = WalletStorage(self.wallet_path)
        wiz.continue_multisig_setup(storage)
        assert wiz.unfinished_multisig
        assert wiz.unfinished_enc_version == StorageEncryptionVersion.PLAINTEXT
        assert not wiz.unfinished_check_password
        assert wiz.last_method == 'continue_multisig_setup_dialog'
        last_args = wiz.last_args
        assert last_args[0:2] == (2, 3)  # m, n
        assert last_args[2] == wiz.keystores  # keystores
        assert len(last_args[2]) == 2
        k1, k2 = last_args[2]
        assert type(k1) == BIP32_KeyStore
        assert k1.get_root_fingerprint() == '3f635a63'
        assert type(k2) == BIP32_KeyStore
        assert k2.get_root_fingerprint() == 'e54b06c8'
        assert last_args[3] == wiz.choose_keystore  # run_next
예제 #8
0
 def test_encrypt_message(self):
     key = WalletStorage.get_eckey_from_password('secret_password77')
     msgs = [
         bytes([0] * 555),
         b'cannot think of anything funny'
     ]
     for plaintext in msgs:
         ciphertext1 = key.encrypt_message(plaintext)
         ciphertext2 = key.encrypt_message(plaintext)
         self.assertEqual(plaintext, key.decrypt_message(ciphertext1))
         self.assertEqual(plaintext, key.decrypt_message(ciphertext2))
         self.assertNotEqual(ciphertext1, ciphertext2)
예제 #9
0
    def test_update_password_with_app_restarts(self):
        wallet_str = '{"addr_history":{"Xcmu97gPDoJn6NELShGPRnaRDvbLWyN4ph":[],"Xetp3vzZd25tqMTHUs826okUcpnxAtG73J":[],"XpeViGqbFaUYUQYHeYx62tSBNfrctAu6er":[]},"addresses":{"change":[],"receiving":["Xcmu97gPDoJn6NELShGPRnaRDvbLWyN4ph","XpeViGqbFaUYUQYHeYx62tSBNfrctAu6er","Xetp3vzZd25tqMTHUs826okUcpnxAtG73J"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"XGw9fNSxGB9e7c9G1wHwMdVsfgvLZGxrUVDEiuozYtEJbQQ8Djc9","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"XHLdYVniEEZajZEreWmi6AwfqgzjJwKDAyZATAjVavZZ58gdjf38","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"7ri5P9aS73pjQp62MU6MdhNz2cp6XamakdXtp91aRLEJUtZLd1M"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}'
        db = WalletDB(wallet_str, manual_upgrades=False)
        storage = WalletStorage(self.wallet_path)
        wallet = Wallet(db, storage, config=self.config)
        asyncio.run_coroutine_threadsafe(wallet.stop(), self.asyncio_loop).result()

        storage = WalletStorage(self.wallet_path)
        # if storage.is_encrypted():
        #     storage.decrypt(password)
        db = WalletDB(storage.read(), manual_upgrades=False)
        wallet = Wallet(db, storage, config=self.config)

        wallet.check_password(None)

        wallet.update_password(None, "1234")
        with self.assertRaises(InvalidPassword):
            wallet.check_password(None)
        with self.assertRaises(InvalidPassword):
            wallet.check_password("wrong password")
        wallet.check_password("1234")
예제 #10
0
    def test_update_password_of_standard_wallet(self):
        wallet_str = '''{"addr_history":{"Xbv3X1eD4PWQ4Fm8yJ32f4shaLnNLKkXLc":[],"XcQFtHuHYnZi2sewUkAJpYU59zQNDAzRyP":[],"XcyHr5KQac62gRra6zR8QSBRFGBrQw3JPn":[],"XdS6ykw3GYehruoCMDL6isKAkQADt91sso":[],"Xe9Vt6NcF1k33P4eBf2sdhP5VdQoM82ra3":[],"XeNc2DCP6pzaht7DAKcGCz2PHd5Lj12iCK":[],"Xew7jYaKqb7c15Fno2T9i8WTSNvm3hRdL2":[],"XhV9qCJ3zPzgbALTBZUNmztsdx2hq5fL4D":[],"XiPDShPTx8q1Y2tcTYZepLqGW9wVCJV67t":[],"XiTzDWc5hUXnReDeF5XT6NEfYMnZmiEhD6":[],"XjFyxpK8chRxk9YJVP2uLc4x9HS72A6PDd":[],"XjftZGtEoJtcyMihTrWRjZrzoezouTEM9D":[],"XjjNH2aENdryvsMhqWD68Gs9MV91GxL38J":[],"XatcXWHv95EHJgJE7hcsvSiwMhyR74t4Mh":[],"XobfXwwNYgYakhEWbP3swAaXcMjtnV7KnJ":[],"XokpWh2CnDYd4L899597czi8gH99sMzMbQ":[],"Xr94GzQPZs9Aj7mm8Fp4Jh458XCVUPw8wx":[],"XrCgX57b8cfRCppFxnX2BweBMjxUXCGFj7":[],"XrPcfCVLCnqRXdES1gcaRUpRAHy7uaUUqj":[],"XsmJHj4DfesHP6oWxC47VXuorb5YdZQftK":[],"XtCpHFPtGR5pcR5ChNsWmT67zTQMHr4u81":[],"Xu68nscwNBVkfHsuLmcxgjqQBf7JWmGLej":[],"XuVoPvFvHauQ5fropq9oe7w1zSgc1FRCM3":[],"XuXL4eBXnJmWPYYTRVYYcNqqzNKZmrTTTV":[],"XwgwoU6SbpKCE6dnfP7j1re5UW4J93vYE9":[],"XySy8SMtS1SRoLzuif72fXwegQQPhDRtgp":[]},"addresses":{"change":["XrPcfCVLCnqRXdES1gcaRUpRAHy7uaUUqj","Xr94GzQPZs9Aj7mm8Fp4Jh458XCVUPw8wx","Xew7jYaKqb7c15Fno2T9i8WTSNvm3hRdL2","XjjNH2aENdryvsMhqWD68Gs9MV91GxL38J","XjftZGtEoJtcyMihTrWRjZrzoezouTEM9D","XtCpHFPtGR5pcR5ChNsWmT67zTQMHr4u81"],"receiving":["XeNc2DCP6pzaht7DAKcGCz2PHd5Lj12iCK","XcyHr5KQac62gRra6zR8QSBRFGBrQw3JPn","XjFyxpK8chRxk9YJVP2uLc4x9HS72A6PDd","XsmJHj4DfesHP6oWxC47VXuorb5YdZQftK","XySy8SMtS1SRoLzuif72fXwegQQPhDRtgp","XdS6ykw3GYehruoCMDL6isKAkQADt91sso","Xu68nscwNBVkfHsuLmcxgjqQBf7JWmGLej","Xbv3X1eD4PWQ4Fm8yJ32f4shaLnNLKkXLc","XcQFtHuHYnZi2sewUkAJpYU59zQNDAzRyP","Xe9Vt6NcF1k33P4eBf2sdhP5VdQoM82ra3","XuXL4eBXnJmWPYYTRVYYcNqqzNKZmrTTTV","XhV9qCJ3zPzgbALTBZUNmztsdx2hq5fL4D","XokpWh2CnDYd4L899597czi8gH99sMzMbQ","XiPDShPTx8q1Y2tcTYZepLqGW9wVCJV67t","XuVoPvFvHauQ5fropq9oe7w1zSgc1FRCM3","XiTzDWc5hUXnReDeF5XT6NEfYMnZmiEhD6","XatcXWHv95EHJgJE7hcsvSiwMhyR74t4Mh","XobfXwwNYgYakhEWbP3swAaXcMjtnV7KnJ","XrCgX57b8cfRCppFxnX2BweBMjxUXCGFj7","XwgwoU6SbpKCE6dnfP7j1re5UW4J93vYE9"]},"keystore":{"seed":"cereal wise two govern top pet frog nut rule sketch bundle logic","type":"bip32","xprv":"xprv9s21ZrQH143K29XjRjUs6MnDB9wXjXbJP2kG1fnRk8zjdDYWqVkQYUqaDtgZp5zPSrH5PZQJs8sU25HrUgT1WdgsPU8GbifKurtMYg37d4v","xpub":"xpub661MyMwAqRbcEdcCXm1sTViwjBn28zK9kFfrp4C3JUXiW1sfP34f6HA45B9yr7EH5XGzWuTfMTdqpt9XPrVQVUdgiYb5NW9m8ij1FSZgGBF"},"pruned_txo":{},"seed_type":"standard","seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[619,310,840,405]}'''
        db = WalletDB(wallet_str, manual_upgrades=False)
        storage = WalletStorage(self.wallet_path)
        wallet = Wallet(db, storage, config=self.config)

        wallet.check_password(None)

        wallet.update_password(None, "1234")
        with self.assertRaises(InvalidPassword):
            wallet.check_password(None)
        with self.assertRaises(InvalidPassword):
            wallet.check_password("wrong password")
        wallet.check_password("1234")
예제 #11
0
    def run_upgrades(self, storage: WalletStorage, db: 'WalletDB') -> None:
        path = storage.path
        if db.requires_split():
            self.hide()
            msg = _(
                "The wallet '{}' contains multiple accounts, which are no longer supported since Firo Electrum 2.7.\n\n"
                "Do you want to split your wallet into multiple files?"
            ).format(path)
            if not self.question(msg):
                return
            file_list = db.split_accounts(path)
            msg = _('Your accounts have been moved to') + ':\n' + '\n'.join(
                file_list) + '\n\n' + _(
                    'Do you want to delete the old file') + ':\n' + path
            if self.question(msg):
                os.remove(path)
                self.show_warning(_('The file was removed'))
            # raise now, to avoid having the old storage opened
            raise UserCancelled()

        action = db.get_action()
        if action and db.requires_upgrade():
            raise WalletFileException(
                'Incomplete wallet files cannot be upgraded.')
        if action:
            self.hide()
            msg = _("The file '{}' contains an incompletely created wallet.\n"
                    "Do you want to complete its creation now?").format(path)
            if not self.question(msg):
                if self.question(
                        _("Do you want to delete '{}'?").format(path)):
                    os.remove(path)
                    self.show_warning(_('The file was removed'))
                return
            self.show()
            self.data = json.loads(storage.read())
            self.run(action)
            for k, v in self.data.items():
                db.put(k, v)
            db.write(storage)
            return

        if db.requires_upgrade():
            self.upgrade_db(storage, db)
예제 #12
0
 def on_filename(filename):
     # FIXME? "filename" might contain ".." (etc) and hence sketchy path traversals are possible
     nonlocal temp_storage
     temp_storage = None
     msg = None
     if filename:
         path = os.path.join(wallet_folder, filename)
         wallet_from_memory = get_wallet_from_daemon(path)
         try:
             if wallet_from_memory:
                 temp_storage = wallet_from_memory.storage  # type: Optional[WalletStorage]
             else:
                 temp_storage = WalletStorage(path)
         except (StorageReadWriteError, WalletFileException) as e:
             msg = _('Cannot read file') + f'\n{repr(e)}'
         except Exception as e:
             self.logger.exception('')
             msg = _('Cannot read file') + f'\n{repr(e)}'
     else:
         msg = ""
     self.next_button.setEnabled(temp_storage is not None)
     user_needs_to_enter_password = False
     if temp_storage:
         if not temp_storage.file_exists():
             msg =_("This file does not exist.") + '\n' \
                   + _("Press 'Next' to create this wallet, or choose another file.")
         elif not wallet_from_memory:
             if temp_storage.is_encrypted_with_user_pw():
                 msg = _("This file is encrypted with a password.") + '\n' \
                       + _('Enter your password or choose another file.')
                 user_needs_to_enter_password = True
             elif temp_storage.is_encrypted_with_hw_device():
                 msg = _("This file is encrypted using a hardware device.") + '\n' \
                       + _("Press 'Next' to choose device to decrypt.")
             else:
                 msg = _("Press 'Next' to open this wallet.")
         else:
             msg = _("This file is already open in memory.") + "\n" \
                 + _("Press 'Next' to create/focus window.")
     if msg is None:
         msg = _('Cannot read file')
     msg_label.setText(msg)
     widget_create_new.setVisible(
         bool(temp_storage and temp_storage.file_exists()))
     if user_needs_to_enter_password:
         pw_label.show()
         pw_e.show()
         pw_e.setFocus()
     else:
         pw_label.hide()
         pw_e.hide()
예제 #13
0
    def test_write_dictionary_to_file(self):

        storage = WalletStorage(self.wallet_path)
        db = WalletDB('', manual_upgrades=True)

        some_dict = {
            u"a": u"b",
            u"c": u"d",
            u"seed_version": FINAL_SEED_VERSION}

        for key, value in some_dict.items():
            db.put(key, value)
        db.write(storage)

        with open(self.wallet_path, "r") as f:
            contents = f.read()
        d = json.loads(contents)
        for key, value in some_dict.items():
            self.assertEqual(d[key], value)
예제 #14
0
    def __init__(self, config: 'SimpleConfig', daemon: 'Daemon', plugins: 'Plugins'):

        self.config = config
        self.network = network = daemon.network
        if config.get('tor_auto_on', True):
            if network:
                proxy_modifiable = config.is_modifiable('proxy')
                if not proxy_modifiable or not network.detect_tor_proxy():
                    print(network.TOR_WARN_MSG_TXT)
                    c = ''
                    while c != 'y':
                        c = input("Continue without Tor (y/n)?")
                        if c == 'n':
                            exit()
        storage = WalletStorage(config.get_wallet_path())
        if not storage.file_exists():
            print("Wallet not found. try 'electrum-dash create'")
            exit()
        if storage.is_encrypted():
            password = getpass.getpass('Password:'******'')
        self.encoding = locale.getpreferredencoding()

        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN)
        curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
        self.stdscr.keypad(1)

        if getattr(storage, 'backup_message', None):
            msg_key = 'Press any key to continue...'
            self.stdscr.addstr(f'{storage.backup_message}\n\n{msg_key}')
            self.stdscr.getch()

        self.stdscr.border(0)
        self.maxy, self.maxx = self.stdscr.getmaxyx()
        self.set_cursor(0)
        self.w = curses.newwin(10, 50, 5, 5)

        console_stderr_handler.setLevel(logging.CRITICAL)
        self.tab = 0
        self.pos = 0
        self.popup_pos = 0

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""
        self.history = None
        def_dip2 = not self.wallet.psman.unsupported
        self.show_dip2 = self.config.get('show_dip2_tx_type', def_dip2)

        util.register_callback(self.update, ['wallet_updated', 'network_updated'])

        self.tab_names = [_("History"), _("Send"), _("Receive"), _("Addresses"), _("Contacts"), _("Banner")]
        self.num_tabs = len(self.tab_names)
예제 #15
0
 def test_decrypt_message(self):
     key = WalletStorage.get_eckey_from_password('pw123')
     self.assertEqual(b'me<(s_s)>age', key.decrypt_message(b'QklFMQMDFtgT3zWSQsa+Uie8H/WvfUjlu9UN9OJtTt3KlgKeSTi6SQfuhcg1uIz9hp3WIUOFGTLr4RNQBdjPNqzXwhkcPi2Xsbiw6UCNJncVPJ6QBg=='))
     self.assertEqual(b'me<(s_s)>age', key.decrypt_message(b'QklFMQKXOXbylOQTSMGfo4MFRwivAxeEEkewWQrpdYTzjPhqjHcGBJwdIhB7DyRfRQihuXx1y0ZLLv7XxLzrILzkl/H4YUtZB4uWjuOAcmxQH4i/Og=='))
     self.assertEqual(b'hey_there' * 100, key.decrypt_message(b'QklFMQLOOsabsXtGQH8edAa6VOUa5wX8/DXmxX9NyHoAx1a5bWgllayGRVPeI2bf0ZdWK0tfal0ap0ZIVKbd2eOJybqQkILqT6E1/Syzq0Zicyb/AA1eZNkcX5y4gzloxinw00ubCA8M7gcUjJpOqbnksATcJ5y2YYXcHMGGfGurWu6uJ/UyrNobRidWppRMW5yR9/6utyNvT6OHIolCMEf7qLcmtneoXEiz51hkRdZS7weNf9mGqSbz9a2NL3sdh1A0feHIjAZgcCKcAvksNUSauf0/FnIjzTyPRpjRDMeDC8Ci3sGiuO3cvpWJwhZfbjcS26KmBv2CHWXfRRNFYOInHZNIXWNAoBB47Il5bGSMd+uXiGr+SQ9tNvcu+BiJNmFbxYqg+oQ8dGAl1DtvY2wJVY8k7vO9BIWSpyIxfGw7EDifhc5vnOmGe016p6a01C3eVGxgl23UYMrP7+fpjOcPmTSF4rk5U5ljEN3MSYqlf1QEv0OqlI9q1TwTK02VBCjMTYxDHsnt04OjNBkNO8v5uJ4NR+UUDBEp433z53I59uawZ+dbk4v4ZExcl8EGmKm3Gzbal/iJ/F7KQuX2b/ySEhLOFVYFWxK73X1nBvCSK2mC2/8fCw8oI5pmvzJwQhcCKTdEIrz3MMvAHqtPScDUOjzhXxInQOCb3+UBj1PPIdqkYLvZss1TEaBwYZjLkVnK2MBj7BaqT6Rp6+5A/fippUKHsnB6eYMEPR2YgDmCHL+4twxHJG6UWdP3ybaKiiAPy2OHNP6PTZ0HrqHOSJzBSDD+Z8YpaRg29QX3UEWlqnSKaan0VYAsV1VeaN0XFX46/TWO0L5tjhYVXJJYGqo6tIQJymxATLFRF6AZaD1Mwd27IAL04WkmoQoXfO6OFfwdp/shudY/1gBkDBvGPICBPtnqkvhGF+ZF3IRkuPwiFWeXmwBxKHsRx/3+aJu32Ml9+za41zVk2viaxcGqwTc5KMexQFLAUwqhv+aIik7U+5qk/gEVSuRoVkihoweFzKolNF+BknH2oB4rZdPixag5Zje3DvgjsSFlOl69W/67t/Gs8htfSAaHlsB8vWRQr9+v/lxTbrAw+O0E+sYGoObQ4qQMyQshNZEHbpPg63eWiHtJJnrVBvOeIbIHzoLDnMDsWVWZSMzAQ1vhX1H5QLgSEbRlKSliVY03kDkh/Nk/KOn+B2q37Ialq4JcRoIYFGJ8AoYEAD0tRuTqFddIclE75HzwaNG7NyKW1plsa72ciOPwsPJsdd5F0qdSQ3OSKtooTn7uf6dXOc4lDkfrVYRlZ0PX'))
class SignApp(object):
    def __init__(self, **kwargs):
        '''Get app settings from options'''
        self.make_commit = kwargs.pop('make_commit')
        self.password = kwargs.pop('password')
        self.signing_key = kwargs.pop('signing_key')
        self.testnet = kwargs.pop('testnet')
        self.wallet_path = kwargs.pop('wallet')

        script_config = read_config()
        if script_config:
            self.make_commit = (self.make_commit
                                or script_config.get('make_commit', False))
            self.signing_key = (self.signing_key
                                or script_config.get('signing_key', False))
            self.testnet = (self.testnet
                            or script_config.get('testnet', False))
            self.wallet_path = (self.wallet_path
                                or script_config.get('wallet', False))
        if self.wallet_path:
            self.wallet_path = os.path.expanduser(self.wallet_path)
        self.config_options = {'cwd': os.getcwd()}
        self.config_options['password'] = self.password
        self.config_options['testnet'] = self.testnet
        self.config_options['wallet_path'] = self.wallet_path
        self.config = SimpleConfig(self.config_options)
        if self.config.get('testnet'):
            constants.set_testnet()
        self.storage = WalletStorage(self.config.get_wallet_path())

    def load_wallet(self, storage):
        print('Lodaing wallet: %s' % self.config.get_wallet_path())
        password = None
        if storage.is_encrypted():
            if storage.is_encrypted_with_hw_device():
                plugins = Plugins(self.config, 'cmdline')
                password = get_passwd_for_hw_device_encrypted_storage(plugins)
                storage.decrypt(password)
            else:
                password = get_password(storage.decrypt)

        db = WalletDB(self.storage.read(), manual_upgrades=True)
        if db.requires_upgrade():
            print('Error: Wallet db need to be upgraded.'
                  ' Do it with the wallet app')
            sys.exit(1)
        self.wallet = Wallet(db, self.storage, config=self.config)

        if self.wallet.has_password() and not password:
            password = get_password(self.wallet.check_password)
        self.config_options['password'] = password

    def commit_latest_version(self):
        commit_msg = COMMIT_MSG_TEMPLATE.format(fname=LATEST_VER_FNAME,
                                                version=ELECTRUM_VERSION)
        print('commiting: %s' % commit_msg)
        os.system('git add ./%s' % LATEST_VER_FNAME)
        os.system('git commit -m "%s"' % commit_msg)

    def run(self):
        self.load_wallet(self.storage)
        if self.signing_key:
            address = self.signing_key
        else:
            address = SIGNING_KEYS[0]
        message = ELECTRUM_VERSION
        password = self.config_options.get('password')
        print('Signing version: %s' % message)
        print('with address: %s' % address)
        sig = self.wallet.sign_message(address, message, password)
        sig = base64.b64encode(sig).decode('ascii')
        content = {
            'version': ELECTRUM_VERSION,
            'signatures': {
                address: sig
            }
        }
        content_json = json.dumps(content, indent=4)
        print(content_json)
        with open('./%s' % LATEST_VER_FNAME, 'w') as fd:
            fd.write('%s\n' % content_json)
        if self.make_commit:
            self.commit_latest_version()