Exemplo n.º 1
0
 def dbb_erase(self):
     self.handler.show_message(_("Are you sure you want to erase the Digital Bitbox?\r\n\r\n" \
                                 "To continue, touch the Digital Bitbox's light for 3 seconds.\r\n\r\n" \
                                 "To cancel, briefly touch the light or wait for the timeout."))
     hid_reply = self.hid_send_encrypt(b'{"reset":"__ERASE__"}')
     self.handler.finished()
     if 'error' in hid_reply:
         raise Exception(hid_reply['error']['message'])
     else:
         self.password = None
         raise Exception('Device erased')
Exemplo n.º 2
0
 def __init__(self, parent, message, task, on_success=None, on_error=None):
     assert parent
     if isinstance(parent, MessageBoxMixin):
         parent = parent.top_level_window()
     WindowModalDialog.__init__(self, parent, _("Please wait"))
     vbox = QVBoxLayout(self)
     vbox.addWidget(QLabel(message))
     self.accepted.connect(self.on_accepted)
     self.show()
     self.thread = TaskThread(self)
     self.thread.add(task, on_success, self.accept, on_error)
Exemplo n.º 3
0
 def get_xpub(self, device_id, derivation, xtype, wizard):
     if xtype not in ('standard', 'p2wpkh-p2sh'):
         raise ScriptTypeNotSupported(
             _('This type of script is not supported with the Digital Bitbox.'
               ))
     devmgr = self.device_manager()
     client = devmgr.client_by_id(device_id)
     client.handler = self.create_handler(wizard)
     client.check_device_dialog()
     xpub = client.get_xpub(derivation, xtype)
     return xpub
Exemplo n.º 4
0
    def remove_local_tx(self, delete_tx):
        to_delete = {delete_tx}
        to_delete |= self.wallet.get_depending_transactions(delete_tx)

        question = _("Are you sure you want to remove this transaction?")
        if len(to_delete) > 1:
            question = _(
                "Are you sure you want to remove this transaction and {} child transactions?"
                .format(len(to_delete) - 1))

        answer = QMessageBox.question(self.parent, _("Please confirm"),
                                      question, QMessageBox.Yes,
                                      QMessageBox.No)
        if answer == QMessageBox.No:
            return
        for tx in to_delete:
            self.wallet.remove_transaction(tx)
        self.wallet.save_transactions(write=True)
        # need to update at least: history_list, utxo_list, address_list
        self.parent.need_update.set()
Exemplo n.º 5
0
 def __init__(self, network, config, network_updated_signal_obj):
     QDialog.__init__(self)
     self.setWindowTitle(_('Network'))
     self.setMinimumSize(500, 20)
     self.nlayout = NetworkChoiceLayout(network, config)
     self.network_updated_signal_obj = network_updated_signal_obj
     vbox = QVBoxLayout(self)
     vbox.addLayout(self.nlayout.layout())
     vbox.addLayout(Buttons(CloseButton(self)))
     self.network_updated_signal_obj.network_updated_signal.connect(
         self.on_update)
     network.register_callback(self.on_network, ['updated', 'interfaces'])
Exemplo n.º 6
0
 def sign_tx(self, wallet, tx):
     if not isinstance(wallet, self.wallet_class):
         return
     if not wallet.can_sign_without_server():
         self.print_error("twofactor:sign_tx")
         auth_code = None
         if wallet.keystores['x3/'].get_tx_derivations(tx):
             msg = _('Please enter your Google Authenticator code:')
             auth_code = int(input(msg))
         else:
             self.print_error("twofactor: xpub3 not needed")
         wallet.auth_code = auth_code
Exemplo n.º 7
0
 def do_auth(self, wizard, short_id, otp, xpub3):
     try:
         server.auth(short_id, otp)
     except:
         wizard.show_message(_('Incorrect password'))
         return
     k3 = keystore.from_xpub(xpub3)
     wizard.storage.put('x3/', k3.dump())
     wizard.storage.put('use_trustedcoin', True)
     wizard.storage.write()
     wizard.wallet = Wallet_2fa(wizard.storage)
     wizard.run('create_addresses')
Exemplo n.º 8
0
 def auth_dialog(self, window):
     d = WindowModalDialog(window, _("Authorization"))
     vbox = QVBoxLayout(d)
     pw = AmountEdit(None, is_int=True)
     msg = _('Please enter your Google Authenticator code')
     vbox.addWidget(QLabel(msg))
     grid = QGridLayout()
     grid.setSpacing(8)
     grid.addWidget(QLabel(_('Code')), 1, 0)
     grid.addWidget(pw, 1, 1)
     vbox.addLayout(grid)
     msg = _(
         'If you have lost your second factor, you need to restore your wallet from seed in order to request a new code.'
     )
     label = QLabel(msg)
     label.setWordWrap(1)
     vbox.addWidget(label)
     vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
     if not d.exec_():
         return
     return pw.get_amount()
Exemplo n.º 9
0
 def recover_or_erase_dialog(self):
     msg = _("The Digital Bitbox is already seeded. Choose an option:\n")
     choices = [
         (_("Create a wallet using the current seed")),
         (_("Load a wallet from the micro SD card (the current seed is overwritten)"
            )), (_("Erase the Digital Bitbox"))
     ]
     try:
         reply = self.handler.win.query_choice(msg, choices)
     except Exception:
         return  # Back button pushed
     if reply == 2:
         self.dbb_erase()
     elif reply == 1:
         if not self.dbb_load_backup():
             return
     else:
         if self.hid_send_encrypt(b'{"device":"info"}')['device']['lock']:
             raise Exception("Full 2FA enabled. This is not supported yet.")
         # Use existing seed
     self.isInitialized = True
Exemplo n.º 10
0
    def initialize_device(self, device_id, wizard, handler):
        # Initialization method
        msg = _("Choose how you want to initialize your {}.\n\n"
                "The first two methods are secure as no secret information "
                "is entered into your computer.\n\n"
                "For the last two methods you input secrets on your keyboard "
                "and upload them to your {}, and so you should "
                "only do those on a computer you know to be trustworthy "
                "and free of malware.").format(self.device, self.device)
        choices = [
            # Must be short as QT doesn't word-wrap radio button text
            (TIM_NEW,
             _("Let the device generate a completely new seed randomly")),
            (TIM_RECOVER,
             _("Recover from a seed you have previously written down")),
            (TIM_MNEMONIC, _("Upload a BIP39 mnemonic to generate the seed")),
            (TIM_PRIVKEY, _("Upload a master private key"))
        ]

        def f(method):
            import threading
            settings = self.request_trezor_init_settings(
                wizard, method, self.device)
            t = threading.Thread(target=self._initialize_device,
                                 args=(settings, method, device_id, wizard,
                                       handler))
            t.setDaemon(True)
            t.start()
            wizard.loop.exec_()

        wizard.choice_dialog(title=_('Initialize Device'),
                             message=msg,
                             choices=choices,
                             run_next=f)
Exemplo n.º 11
0
    def do_verify(self, d):
        tx = d.tx
        wallet = d.wallet
        window = d.main_window

        if wallet.is_watching_only():
            d.show_critical(
                _('This feature is not available for watch-only wallets.'))
            return

        # 1. get the password and sign the verification request
        password = None
        if wallet.has_keystore_encryption():
            msg = _('GreenAddress requires your signature \n'
                    'to verify that transaction is instant.\n'
                    'Please enter your password to sign a\n'
                    'verification request.')
            password = window.password_dialog(msg, parent=d)
            if not password:
                return
        try:
            d.verify_button.setText(_('Verifying...'))
            QApplication.processEvents()  # update the button label

            addr = self.get_my_addr(d)
            message = "Please verify if %s is GreenAddress instant confirmed" % tx.txid(
            )
            sig = wallet.sign_message(addr, message, password)
            sig = base64.b64encode(sig).decode('ascii')

            # 2. send the request
            response = requests.request(
                "GET",
                ("https://greenaddress.it/verify/?signature=%s&txhash=%s" %
                 (urllib.parse.quote(sig), tx.txid())),
                headers={'User-Agent': 'Electrum'})
            response = response.json()

            # 3. display the result
            if response.get('verified'):
                d.show_message(
                    _('{} is covered by GreenAddress instant confirmation'
                      ).format(tx.txid()),
                    title=_('Verification successful!'))
            else:
                d.show_critical(
                    _('{} is not covered by GreenAddress instant confirmation'
                      ).format(tx.txid()),
                    title=_('Verification failed!'))
        except BaseException as e:
            import traceback
            traceback.print_exc(file=sys.stdout)
            d.show_error(str(e))
        finally:
            d.verify_button.setText(self.button_label)
Exemplo n.º 12
0
    def receive_menu(self, menu, addrs, wallet):
        if len(addrs) != 1:
            return
        for keystore in wallet.get_keystores():
            if type(keystore) == self.keystore_class:

                def show_address():
                    keystore.thread.add(
                        partial(self.show_address, wallet, keystore, addrs[0]))

                menu.addAction(
                    _("Show on {}").format(self.device), show_address)
                break
Exemplo n.º 13
0
 def create_menu(self, position):
     item = self.itemAt(position)
     if not item:
         return
     addr = str(item.text(1))
     req = self.wallet.receive_requests[addr]
     column = self.currentColumn()
     column_title = self.headerItem().text(column)
     column_data = item.text(column)
     menu = QMenu(self)
     menu.addAction(
         _("Copy {}").format(column_title),
         lambda: self.parent.app.clipboard().setText(column_data))
     menu.addAction(
         _("Copy URI"), lambda: self.parent.view_and_paste(
             'URI', '', self.parent.get_request_URI(addr)))
     menu.addAction(_("Save as BIP70 file"),
                    lambda: self.parent.export_payment_request(addr))
     menu.addAction(_("Delete"),
                    lambda: self.parent.delete_payment_request(addr))
     run_hook('receive_list_menu', menu, addr)
     menu.exec_(self.viewport().mapToGlobal(position))
Exemplo n.º 14
0
    def seed_options(self):
        dialog = QDialog()
        vbox = QVBoxLayout(dialog)
        if 'ext' in self.options:
            cb_ext = QCheckBox(_('Extend this seed with custom words'))
            cb_ext.setChecked(self.is_ext)
            vbox.addWidget(cb_ext)
        if 'bip39' in self.options:

            def f(b):
                self.is_seed = (lambda x: bool(x)) if b else self.saved_is_seed
                self.is_bip39 = b
                self.on_edit()
                if b:
                    msg = ' '.join([
                        '<b>' + _('Warning') + ':</b>  ',
                        _('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'
                          ),
                        _('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'
                          ),
                        _('BIP39 seeds do not include a version number, which compromises compatibility with future software.'
                          ),
                        _('We do not guarantee that BIP39 imports will always be supported in Electrum.'
                          ),
                    ])
                else:
                    msg = ''
                self.seed_warning.setText(msg)

            cb_bip39 = QCheckBox(_('BIP39 seed'))
            cb_bip39.toggled.connect(f)
            cb_bip39.setChecked(self.is_bip39)
            vbox.addWidget(cb_bip39)
        vbox.addLayout(Buttons(OkButton(dialog)))
        if not dialog.exec_():
            return None
        self.is_ext = cb_ext.isChecked() if 'ext' in self.options else False
        self.is_bip39 = cb_bip39.isChecked(
        ) if 'bip39' in self.options else False
Exemplo n.º 15
0
 def message_dialog(self, msg, on_cancel):
     # Called more than once during signing, to confirm output and fee
     self.clear_dialog()
     title = _('Please check your {} device').format(self.device)
     self.dialog = dialog = WindowModalDialog(self.top_level_window(),
                                              title)
     l = QLabel(msg)
     vbox = QVBoxLayout(dialog)
     vbox.addWidget(l)
     if on_cancel:
         dialog.rejected.connect(on_cancel)
         vbox.addLayout(Buttons(CancelButton(dialog)))
     dialog.show()
Exemplo n.º 16
0
 def load_wallet(self, wallet, window):
     for keystore in wallet.get_keystores():
         if not isinstance(keystore, self.keystore_class):
             continue
         if not self.libraries_available:
             window.show_error(
                 _("Cannot find python library for") + " '%s'.\n" % self.name \
                 + _("Make sure you install it with python3")
             )
             return
         tooltip = self.device + '\n' + (keystore.label or 'unnamed')
         cb = partial(self.show_settings_dialog, window, keystore)
         button = StatusBarButton(QIcon(self.icon_unpaired), tooltip, cb)
         button.icon_paired = self.icon_paired
         button.icon_unpaired = self.icon_unpaired
         window.statusBar().addPermanentWidget(button)
         handler = self.create_handler(window)
         handler.button = button
         keystore.handler = handler
         keystore.thread = TaskThread(window, window.on_error)
         # Trigger a pairing
         keystore.thread.add(partial(self.get_client, keystore))
Exemplo n.º 17
0
 def pin_dialog(self, msg):
     # Needed e.g. when resetting a device
     self.clear_dialog()
     dialog = WindowModalDialog(self.top_level_window(), _("Enter PIN"))
     matrix = self.pin_matrix_widget_class()
     vbox = QVBoxLayout()
     vbox.addWidget(QLabel(msg))
     vbox.addWidget(matrix)
     vbox.addLayout(Buttons(CancelButton(dialog), OkButton(dialog)))
     dialog.setLayout(vbox)
     dialog.exec_()
     self.response = str(matrix.get_value())
     self.done.set()
Exemplo n.º 18
0
    def settings_dialog(self, window):
        d = WindowModalDialog(window, _("Email settings"))
        d.setMinimumSize(500, 200)

        vbox = QVBoxLayout(d)
        vbox.addWidget(QLabel(_('Server hosting your email acount')))
        grid = QGridLayout()
        vbox.addLayout(grid)
        grid.addWidget(QLabel('Server (IMAP)'), 0, 0)
        server_e = QLineEdit()
        server_e.setText(self.imap_server)
        grid.addWidget(server_e, 0, 1)

        grid.addWidget(QLabel('Username'), 1, 0)
        username_e = QLineEdit()
        username_e.setText(self.username)
        grid.addWidget(username_e, 1, 1)

        grid.addWidget(QLabel('Password'), 2, 0)
        password_e = QLineEdit()
        password_e.setText(self.password)
        grid.addWidget(password_e, 2, 1)

        vbox.addStretch()
        vbox.addLayout(Buttons(CloseButton(d), OkButton(d)))

        if not d.exec_():
            return

        server = str(server_e.text())
        self.config.set_key('email_server', server)

        username = str(username_e.text())
        self.config.set_key('email_username', username)

        password = str(password_e.text())
        self.config.set_key('email_password', password)
Exemplo n.º 19
0
 def restore_choice(self, wizard, seed, passphrase):
     wizard.set_icon(':icons/trustedcoin-wizard.png')
     wizard.stack = []
     title = _('Restore 2FA wallet')
     msg = ' '.join([
         'You are going to restore a wallet protected with two-factor authentication.',
         'Do you want to keep using two-factor authentication with this wallet,',
         'or do you want to disable it, and have two master private keys in your wallet?'
     ])
     choices = [('keep', 'Keep'), ('disable', 'Disable')]
     f = lambda x: self.on_choice(wizard, seed, passphrase, x)
     wizard.choice_dialog(choices=choices,
                          message=msg,
                          title=title,
                          run_next=f)
Exemplo n.º 20
0
 def dbb_load_backup(self, show_msg=True):
     backups = self.hid_send_encrypt(b'{"backup":"list"}')
     if 'error' in backups:
         raise Exception(backups['error']['message'])
     try:
         f = self.handler.win.query_choice(_("Choose a backup file:"),
                                           backups['backup'])
     except Exception:
         return False  # Back button pushed
     key = self.backup_password_dialog()
     if key is None:
         raise Exception('Canceled by user')
     key = self.stretch_key(key)
     if show_msg:
         self.handler.show_message(_("Loading backup...\r\n\r\n" \
                                     "To continue, touch the Digital Bitbox's light for 3 seconds.\r\n\r\n" \
                                     "To cancel, briefly touch the light or wait for the timeout."))
     msg = b'{"seed":{"source": "backup", "key": "%s", "filename": "%s"}}' % (
         key, backups['backup'][f].encode('utf8'))
     hid_reply = self.hid_send_encrypt(msg)
     self.handler.finished()
     if 'error' in hid_reply:
         raise Exception(hid_reply['error']['message'])
     return True
Exemplo n.º 21
0
 def pw_changed(self):
     password = self.new_pw.text()
     if password:
         colors = {
             "Weak": "Red",
             "Medium": "Blue",
             "Strong": "Green",
             "Very Strong": "Green"
         }
         strength = check_password_strength(password)
         label = (_("Password Strength") + ": " + "<font color=" +
                  colors[strength] + ">" + strength + "</font>")
     else:
         label = ""
     self.pw_strength.setText(label)
Exemplo n.º 22
0
 def multisig_dialog(self, run_next):
     cw = CosignWidget(2, 2)
     m_edit = QSlider(Qt.Horizontal, self)
     n_edit = QSlider(Qt.Horizontal, self)
     n_edit.setMinimum(2)
     n_edit.setMaximum(15)
     m_edit.setMinimum(1)
     m_edit.setMaximum(2)
     n_edit.setValue(2)
     m_edit.setValue(2)
     n_label = QLabel()
     m_label = QLabel()
     grid = QGridLayout()
     grid.addWidget(n_label, 0, 0)
     grid.addWidget(n_edit, 0, 1)
     grid.addWidget(m_label, 1, 0)
     grid.addWidget(m_edit, 1, 1)
     def on_m(m):
         m_label.setText(_('Require {0} signatures').format(m))
         cw.set_m(m)
     def on_n(n):
         n_label.setText(_('From {0} cosigners').format(n))
         cw.set_n(n)
         m_edit.setMaximum(n)
     n_edit.valueChanged.connect(on_n)
     m_edit.valueChanged.connect(on_m)
     on_n(2)
     on_m(2)
     vbox = QVBoxLayout()
     vbox.addWidget(cw)
     vbox.addWidget(WWLabel(_("Choose the number of signatures needed to unlock funds in your wallet:")))
     vbox.addLayout(grid)
     self.exec_layout(vbox, _("Multi-Signature Wallet"))
     m = int(m_edit.value())
     n = int(n_edit.value())
     return (m, n)
Exemplo n.º 23
0
 def on_edit(self):
     from electrum_bca.bitcoin import seed_type
     s = self.get_seed()
     b = self.is_seed(s)
     if not self.is_bip39:
         t = seed_type(s)
         label = _('Seed Type') + ': ' + t if t else ''
     else:
         from electrum_bca.keystore import bip39_is_checksum_valid
         is_checksum, is_wordlist = bip39_is_checksum_valid(s)
         status = ('checksum: ' + ('ok' if is_checksum else 'failed')
                   ) if is_wordlist else 'unknown wordlist'
         label = 'BIP39' + ' (%s)' % status
     self.seed_type_label.setText(label)
     self.parent.next_button.setEnabled(b)
Exemplo n.º 24
0
def seed_warning_msg(seed):
    return ''.join([
        "<p>",
        _("Please save these {0} words on paper (order is important). "),
        _("This seed will allow you to recover your wallet in case "
          "of computer failure."), "</p>", "<b>" + _("WARNING") + ":</b>",
        "<ul>", "<li>" + _("Never disclose your seed.") + "</li>",
        "<li>" + _("Never type it on a website.") + "</li>",
        "<li>" + _("Do not store it electronically.") + "</li>", "</ul>"
    ]).format(len(seed.split()))
Exemplo n.º 25
0
 def __init__(self, parent=None):
     MyTreeWidget.__init__(self, parent, self.create_menu, [], 1)
     self.refresh_headers()
     self.setSelectionMode(QAbstractItemView.ExtendedSelection)
     self.show_change = 0
     self.show_used = 0
     self.change_button = QComboBox(self)
     self.change_button.currentIndexChanged.connect(self.toggle_change)
     for t in [_('Receiving'), _('Change'), _('All')]:
         self.change_button.addItem(t)
     self.used_button = QComboBox(self)
     self.used_button.currentIndexChanged.connect(self.toggle_used)
     for t in [_('All'), _('Unused'), _('Funded'), _('Used')]:
         self.used_button.addItem(t)
Exemplo n.º 26
0
 def show_address(self, wallet, address):
     client = self.get_client(wallet.keystore)
     if not client.atleast_version(1, 3):
         wallet.keystore.handler.show_error(
             _("Your device firmware is too old"))
         return
     change, index = wallet.get_address_index(address)
     derivation = wallet.keystore.derivation
     address_path = "%s/%d/%d" % (derivation, change, index)
     address_n = client.expand_path(address_path)
     segwit = wallet.keystore.is_segwit()
     script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS
     client.get_address(self.get_coin_name(),
                        address_n,
                        True,
                        script_type=script_type)
Exemplo n.º 27
0
 def change_homescreen():
     from PIL import Image  # FIXME
     dialog = QFileDialog(self, _("Choose Homescreen"))
     filename, __ = dialog.getOpenFileName()
     if filename:
         im = Image.open(str(filename))
         if im.size != (hs_cols, hs_rows):
             raise Exception('Image must be 64 x 128 pixels')
         im = im.convert('1')
         pix = im.load()
         img = ''
         for j in range(hs_rows):
             for i in range(hs_cols):
                 img += '1' if pix[i, j] else '0'
         img = ''.join(
             chr(int(img[i:i + 8], 2)) for i in range(0, len(img), 8))
         invoke_client('change_homescreen', img)
Exemplo n.º 28
0
 def item_changed(self, item):
     if item is None:
         return
     if not item.isSelected():
         return
     addr = str(item.text(1))
     req = self.wallet.receive_requests[addr]
     expires = age(req['time'] +
                   req['exp']) if req.get('exp') else _('Never')
     amount = req['amount']
     message = self.wallet.labels.get(addr, '')
     self.parent.receive_address_e.setText(addr)
     self.parent.receive_message_e.setText(message)
     self.parent.receive_amount_e.setAmount(amount)
     self.parent.expires_combo.hide()
     self.parent.expires_label.show()
     self.parent.expires_label.setText(expires)
     self.parent.new_request_button.setEnabled(True)
Exemplo n.º 29
0
 def on_update(self):
     inv_list = self.parent.invoices.unpaid_invoices()
     self.clear()
     for pr in inv_list:
         key = pr.get_id()
         status = self.parent.invoices.get_status(key)
         requestor = pr.get_requestor()
         exp = pr.get_expiration_date()
         date_str = format_time(exp) if exp else _('Never')
         item = QTreeWidgetItem([date_str, requestor, pr.memo, self.parent.format_amount(pr.get_amount(), whitespaces=True), pr_tooltips.get(status,'')])
         item.setIcon(4, QIcon(pr_icons.get(status)))
         item.setData(0, Qt.UserRole, key)
         item.setFont(1, QFont(MONOSPACE_FONT))
         item.setFont(3, QFont(MONOSPACE_FONT))
         self.addTopLevelItem(item)
     self.setCurrentItem(self.topLevelItem(0))
     self.setVisible(len(inv_list))
     self.parent.invoices_label.setVisible(len(inv_list))
Exemplo n.º 30
0
 def __init__(self, config, app, plugins, storage):
     BaseWizard.__init__(self, config, storage)
     QDialog.__init__(self, None)
     self.setWindowTitle('Electrum  -  ' + _('Install Wizard'))
     self.app = app
     self.config = config
     # Set for base base class
     self.plugins = plugins
     self.language_for_seed = config.get('language')
     self.setMinimumSize(600, 400)
     self.accept_signal.connect(self.accept)
     self.title = QLabel()
     self.main_widget = QWidget()
     self.back_button = QPushButton(_("Back"), self)
     self.back_button.setText(_('Back') if self.can_go_back() else _('Cancel'))
     self.next_button = QPushButton(_("Next"), self)
     self.next_button.setDefault(True)
     self.logo = QLabel()
     self.please_wait = QLabel(_("Please wait..."))
     self.please_wait.setAlignment(Qt.AlignCenter)
     self.icon_filename = None
     self.loop = QEventLoop()
     self.rejected.connect(lambda: self.loop.exit(0))
     self.back_button.clicked.connect(lambda: self.loop.exit(1))
     self.next_button.clicked.connect(lambda: self.loop.exit(2))
     outer_vbox = QVBoxLayout(self)
     inner_vbox = QVBoxLayout()
     inner_vbox.addWidget(self.title)
     inner_vbox.addWidget(self.main_widget)
     inner_vbox.addStretch(1)
     inner_vbox.addWidget(self.please_wait)
     inner_vbox.addStretch(1)
     scroll_widget = QWidget()
     scroll_widget.setLayout(inner_vbox)
     scroll = QScrollArea()
     scroll.setWidget(scroll_widget)
     scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
     scroll.setWidgetResizable(True)
     icon_vbox = QVBoxLayout()
     icon_vbox.addWidget(self.logo)
     icon_vbox.addStretch(1)
     hbox = QHBoxLayout()
     hbox.addLayout(icon_vbox)
     hbox.addSpacing(5)
     hbox.addWidget(scroll)
     hbox.setStretchFactor(scroll, 1)
     outer_vbox.addLayout(hbox)
     outer_vbox.addLayout(Buttons(self.back_button, self.next_button))
     self.set_icon(':icons/electrum-bca.png')
     self.show()
     self.raise_()
     self.refresh_gui()  # Need for QT on MacOSX.  Lame.