def build_tray_menu(self): m = QMenu() m.addAction(_("Show/Hide"), self.show_or_hide) m.addAction(_("Dark/Light"), self.toggle_tray_icon) m.addSeparator() m.addAction(_("Exit Vialectrum"), self.close) self.tray.setContextMenu(m)
def __init__(self, parent): super(MatrixDialog, self).__init__(parent) self.setWindowTitle(_("Trezor Matrix Recovery")) self.num = 9 self.loop = QEventLoop() vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(MATRIX_RECOVERY)) grid = QGridLayout() grid.setSpacing(0) self.char_buttons = [] for y in range(3): for x in range(3): button = QPushButton('?') button.clicked.connect(partial(self.process_key, ord('1') + y * 3 + x)) grid.addWidget(button, 3 - y, x) self.char_buttons.append(button) vbox.addLayout(grid) self.backspace_button = QPushButton("<=") self.backspace_button.clicked.connect(partial(self.process_key, Qt.Key_Backspace)) self.cancel_button = QPushButton(_("Cancel")) self.cancel_button.clicked.connect(partial(self.process_key, Qt.Key_Escape)) buttons = Buttons(self.backspace_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
def __init__(self, transaction_id, parent): super(TransactionWindow, self).__init__() self.tx_id = str(transaction_id) self.parent = parent self.setModal(True) self.resize(200,100) self.setWindowTitle(_("Transaction successfully sent")) self.layout = QGridLayout(self) history_label = "%s\n%s" % (_("Your transaction has been sent."), _("Please enter a label for this transaction for future reference.")) self.layout.addWidget(QLabel(history_label)) self.label_edit = QLineEdit() self.label_edit.setPlaceholderText(_("Transaction label")) self.label_edit.setObjectName("label_input") self.label_edit.setAttribute(Qt.WA_MacShowFocusRect, 0) self.label_edit.setFocusPolicy(Qt.ClickFocus) self.layout.addWidget(self.label_edit) self.save_button = QPushButton(_("Save")) self.layout.addWidget(self.save_button) self.save_button.clicked.connect(self.set_label) self.exec_()
def contextMenuEvent(self, e): m = self.createStandardContextMenu() if self.isReadOnly(): m.addAction(_("Show as QR code"), self.qr_show) else: m.addAction(_("Read QR code"), self.qr_input) m.exec_(e.globalPos())
def context_menu(self): view_menu = QMenu() themes_menu = view_menu.addMenu(_("&Themes")) selected_theme = self.actuator.selected_theme() theme_group = QActionGroup(self) for theme_name in self.actuator.theme_names(): theme_action = themes_menu.addAction(theme_name) theme_action.setCheckable(True) if selected_theme == theme_name: theme_action.setChecked(True) class SelectThemeFunctor: def __init__(self, theme_name, toggle_theme): self.theme_name = theme_name self.toggle_theme = toggle_theme def __call__(self, checked): if checked: self.toggle_theme(self.theme_name) delegate = SelectThemeFunctor(theme_name, self.toggle_theme) theme_action.toggled.connect(delegate) theme_group.addAction(theme_action) view_menu.addSeparator() show_receiving = view_menu.addAction(_("Show Receiving addresses")) show_receiving.setCheckable(True) show_receiving.toggled.connect(self.toggle_receiving_layout) show_receiving.setChecked(self.config.get("gui_show_receiving",False)) show_history = view_menu.addAction(_("Show History")) show_history.setCheckable(True) show_history.toggled.connect(self.show_history) show_history.setChecked(self.config.get("gui_show_history",False)) return view_menu
def mouseReleaseEvent(self, event): dialog = QDialog(self) dialog.setWindowTitle(_('Vialectrum update')) dialog.setModal(1) main_layout = QGridLayout() main_layout.addWidget(QLabel(_("A new version of Vialectrum is available:")+" " + self.latest_version), 0,0,1,3) ignore_version = QPushButton(_("Ignore this version")) ignore_version.clicked.connect(self.ignore_this_version) ignore_all_versions = QPushButton(_("Ignore all versions")) ignore_all_versions.clicked.connect(self.ignore_all_version) open_website = QPushButton(_("Goto download page")) open_website.clicked.connect(self.open_website) main_layout.addWidget(ignore_version, 1, 0) main_layout.addWidget(ignore_all_versions, 1, 1) main_layout.addWidget(open_website, 1, 2) dialog.setLayout(main_layout) self.dialog = dialog if not dialog.exec_(): return
def create_menu(self, position): idx = self.indexAt(position) item = self.model().itemFromIndex(idx) # TODO use siblingAtColumn when min Qt version is >=5.11 item_addr = self.model().itemFromIndex(idx.sibling(idx.row(), self.Columns.ADDRESS)) if not item_addr: return addr = item_addr.text() req = self.wallet.receive_requests.get(addr) if req is None: self.update() return column = idx.column() column_title = self.model().horizontalHeaderItem(column).text() column_data = item.text() menu = QMenu(self) if column != self.Columns.SIGNATURE: if column == self.Columns.AMOUNT: column_data = column_data.strip() 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))
def _initialize_device(self, settings: TrezorInitSettings, method, device_id, wizard, handler): if method == TIM_RECOVER and settings.recovery_type == RECOVERY_TYPE_SCRAMBLED_WORDS: handler.show_error(_( "You will be asked to enter 24 words regardless of your " "seed's actual length. If you enter a word incorrectly or " "misspell it, you cannot change it or go back - you will need " "to start again from the beginning.\n\nSo please enter " "the words carefully!"), blocking=True) devmgr = self.device_manager() client = devmgr.client_by_id(device_id) if not client: raise Exception(_("The device was disconnected.")) if method == TIM_NEW: strength_from_word_count = {12: 128, 18: 192, 24: 256} client.reset_device( strength=strength_from_word_count[settings.word_count], passphrase_protection=settings.passphrase_enabled, pin_protection=settings.pin_enabled, label=settings.label, no_backup=settings.no_backup) elif method == TIM_RECOVER: client.recover_device( recovery_type=settings.recovery_type, word_count=settings.word_count, passphrase_protection=settings.passphrase_enabled, pin_protection=settings.pin_enabled, label=settings.label) if settings.recovery_type == RECOVERY_TYPE_MATRIX: handler.close_matrix_dialog() else: raise RuntimeError("Unsupported recovery method")
def make_cypherseed(self, img, rawnoise, calibration=False, is_seed = True): img = img.convertToFormat(QImage.Format_Mono) p = QPainter() p.begin(img) p.setCompositionMode(26) #xor p.drawImage(0, 0, rawnoise) p.end() cypherseed = self.pixelcode_2x2(img) cypherseed = QBitmap.fromImage(cypherseed) cypherseed = cypherseed.scaled(self.f_size, Qt.KeepAspectRatio) cypherseed = self.overlay_marks(cypherseed, True, calibration) if not is_seed: self.filename_prefix = 'custom_secret_' self.was = _('Custom secret') else: self.filename_prefix = self.wallet_name + '_seed_' self.was = self.wallet_name + ' ' + _('seed') if self.extension: self.ext_warning(self.c_dialog) if not calibration: self.toPdf(QImage(cypherseed)) QDesktopServices.openUrl(QUrl.fromLocalFile(self.get_path_to_revealer_file('.pdf'))) cypherseed.save(self.get_path_to_revealer_file('.png')) self.bcrypt(self.c_dialog) return cypherseed
def show_address(self, sequence, txin_type): client = self.get_client() address_path = self.get_derivation()[2:] + "/%d/%d"%sequence self.handler.show_message(_("Showing address ...")) segwit = is_segwit_script_type(txin_type) segwitNative = txin_type == 'p2wpkh' try: client.getWalletPublicKey(address_path, showOnScreen=True, segwit=segwit, segwitNative=segwitNative) except BTChipException as e: if e.sw == 0x6985: # cancelled by user pass elif e.sw == 0x6982: raise # pin lock. decorator will catch it elif e.sw == 0x6b00: # hw.1 raises this self.handler.show_error('{}\n{}\n{}'.format( _('Error showing address') + ':', e, _('Your device might not have support for this functionality.'))) else: self.logger.exception('') self.handler.show_error(e) except BaseException as e: self.logger.exception('') self.handler.show_error(e) finally: self.handler.finished()
def do_full_push(self): try: bundle = {"labels": {}} for key, value in self.wallet.labels.iteritems(): encoded = self.encode(key) bundle["labels"][encoded] = self.encode(value) params = json.dumps(bundle) connection = httplib.HTTPConnection(self.target_host) connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'}) response = connection.getresponse() if response.reason == httplib.responses[httplib.NOT_FOUND]: return try: response = json.loads(response.read()) except ValueError as e: return False if "error" in response: QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"])) return False return True except socket.gaierror as e: print_error('Error connecting to service: %s ' % e) return False
def full_pull(self, force = False): if self.do_full_pull(force) and force: QMessageBox.information(None, _("Labels synchronized"), _("Your labels have been synchronized.")) self.window.update_history_tab() self.window.update_completions() self.window.update_receive_tab() self.window.update_contacts_tab()
def add_io(self, vbox): if self.tx.locktime > 0: vbox.addWidget(QLabel("LockTime: %d\n" % self.tx.locktime)) vbox.addWidget(QLabel(_("Inputs"))) def format_input(x): if x.get('is_coinbase'): return 'coinbase' else: _hash = x.get('prevout_hash') return _hash[0:16] + '...' + _hash[-8:] + ":%d"%x.get('prevout_n') + u'\t' + "%s"%x.get('address') lines = map(format_input, self.tx.inputs ) i_text = QTextEdit() i_text.setText('\n'.join(lines)) i_text.setReadOnly(True) i_text.setMaximumHeight(100) vbox.addWidget(i_text) vbox.addWidget(QLabel(_("Outputs"))) lines = map(lambda x: x[0] + u'\t\t' + self.parent.format_amount(x[1]), self.tx.get_outputs()) o_text = QTextEdit() o_text.setText('\n'.join(lines)) o_text.setReadOnly(True) o_text.setMaximumHeight(100) vbox.addWidget(o_text)
def add_cosigner_dialog(self, run_next, index, is_valid): title = _("Add Cosigner") + " %d"%index message = ' '.join([ _('Please enter the master public key (xpub) of your cosigner.'), _('Enter their master private key (xprv) if you want to be able to sign for them.') ]) return self.text_input(title, message, is_valid)
def get_library_not_available_message(self) -> str: if hasattr(self, 'libraries_available_message'): message = self.libraries_available_message else: message = _("Missing libraries for {}.").format(self.name) message += '\n' + _("Make sure you install it with python3") return message
def save(self): name = 'signed_%s.txn' % (self.tx.hash()[0:8]) if self.tx.is_complete() else 'unsigned.txn' fileName = self.parent.getSaveFileName(_("Select where to save your signed transaction"), name, "*.txn") if fileName: with open(fileName, "w+") as f: f.write(json.dumps(self.tx.as_dict(),indent=4) + '\n') self.show_message(_("Transaction saved successfully"))
def do_full_pull(self, force = False): try: connection = httplib.HTTPConnection(self.target_host) connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())),"", {'Content-Type': 'application/json'}) response = connection.getresponse() if response.reason == httplib.responses[httplib.NOT_FOUND]: return try: response = json.loads(response.read()) except ValueError as e: return False if "error" in response: QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"])) return False for label in response: decoded_key = self.decode(label["external_id"]) decoded_label = self.decode(label["text"]) if force or not self.wallet.labels.get(decoded_key): self.wallet.labels[decoded_key] = decoded_label return True except socket.gaierror as e: print_error('Error connecting to service: %s ' % e) return False
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")), ] def f(method): import threading settings = self.request_trezor_init_settings(wizard, method, device_id) t = threading.Thread(target=self._initialize_device_safe, args=(settings, method, device_id, wizard, handler)) t.setDaemon(True) t.start() exit_code = wizard.loop.exec_() if exit_code != 0: # this method (initialize_device) was called with the expectation # of leaving the device in an initialized state when finishing. # signal that this is not the case: raise UserCancelled() wizard.choice_dialog(title=_('Initialize Device'), message=msg, choices=choices, run_next=f)
def toggle_passphrase(self): if self.features.passphrase_protection: self.msg = _("Confirm on your {} device to disable passphrases") else: self.msg = _("Confirm on your {} device to enable passphrases") enabled = not self.features.passphrase_protection self.apply_settings(use_passphrase=enabled)
def __init__(self, parent): super(CharacterDialog, self).__init__(parent) self.setWindowTitle(_("KeepKey Seed Recovery")) self.character_pos = 0 self.word_pos = 0 self.loop = QEventLoop() self.word_help = QLabel() self.char_buttons = [] vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(CHARACTER_RECOVERY)) hbox = QHBoxLayout() hbox.addWidget(self.word_help) for i in range(4): char_button = CharacterButton('*') char_button.setMaximumWidth(36) self.char_buttons.append(char_button) hbox.addWidget(char_button) self.accept_button = CharacterButton(_("Accept Word")) self.accept_button.clicked.connect(partial(self.process_key, 32)) self.rejected.connect(partial(self.loop.exit, 1)) hbox.addWidget(self.accept_button) hbox.addStretch(1) vbox.addLayout(hbox) self.finished_button = QPushButton(_("Seed Entered")) self.cancel_button = QPushButton(_("Cancel")) self.finished_button.clicked.connect(partial(self.process_key, Qt.Key_Return)) self.cancel_button.clicked.connect(self.rejected) buttons = Buttons(self.finished_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
def toggle_passphrase(self): if self.features.passphrase_protection: msg = _("Confirm on your {} device to disable passphrases") else: msg = _("Confirm on your {} device to enable passphrases") enabled = not self.features.passphrase_protection with self.run_flow(msg): trezorlib.device.apply_settings(self.client, use_passphrase=enabled)
def create_password_layout(self, wallet, is_encrypted, OK_button): if not is_encrypted: msg = _('Your wallet file is NOT encrypted.') else: msg = _('Your wallet file is encrypted.') msg += '\n' + _('Note: If you enable this setting, you will need your hardware device to open your wallet.') msg += '\n' + _('Use this dialog to toggle encryption.') self.playout = PasswordLayoutForHW(msg)
def setup_device(self, device_info, wizard, purpose): devmgr = self.device_manager() device_id = device_info.device.id_ client = devmgr.client_by_id(device_id) if client is None: raise UserFacingException(_('Failed to create a client for this device.') + '\n' + _('Make sure it is in the correct state.')) client.handler = self.create_handler(wizard)
def set_pin(self, remove): if remove: self.msg = _("Confirm on your {} device to disable PIN protection") elif self.features.pin_protection: self.msg = _("Confirm on your {} device to change your PIN") else: self.msg = _("Confirm on your {} device to set a PIN") self.change_pin(remove)
def restore_seed_dialog(self, run_next, test): options = [] if self.opt_ext: options.append('ext') if self.opt_bip39: options.append('bip39') title = _('Enter Seed') message = _('Please enter your seed phrase in order to restore your wallet.') return self.seed_input(title, message, test, options)
def bcrypt(self, dialog): self.rawnoise = False version = self.versioned_seed.version code_id = self.versioned_seed.checksum dialog.show_message(''.join([_("{} encrypted for Revealer {}_{} saved as PNG and PDF at: ").format(self.was, version, code_id), "<b>", self.get_path_to_revealer_file(), "</b>", "<br/>", "<br/>", "<b>", _("Always check your backups.")]), rich_text=True) dialog.close()
def setup_device(self, device_info, wizard, purpose): devmgr = self.device_manager() device_id = device_info.device.id_ client = devmgr.client_by_id(device_id) if client is None: raise UserFacingException(_('Failed to create a client for this device.') + '\n' + _('Make sure it is in the correct state.')) client.handler = self.create_handler(wizard) client.get_xpub("m/44'/2'", 'standard') # TODO replace by direct derivation once Nano S > 1.1
def set_pin(self, remove): if remove: msg = _("Confirm on your {} device to disable PIN protection") elif self.features.pin_protection: msg = _("Confirm on your {} device to change your PIN") else: msg = _("Confirm on your {} device to set a PIN") with self.run_flow(msg): trezorlib.device.change_pin(self.client, remove)
def create_toolbar_buttons(self): self.period_combo = QComboBox() self.start_button = QPushButton('-') self.start_button.pressed.connect(self.select_start_date) self.start_button.setEnabled(False) self.end_button = QPushButton('-') self.end_button.pressed.connect(self.select_end_date) self.end_button.setEnabled(False) self.period_combo.addItems([_('All'), _('Custom')]) self.period_combo.activated.connect(self.on_combo)
def ok_cancel_buttons(dialog): row_layout = QHBoxLayout() row_layout.addStretch(1) ok_button = QPushButton(_("OK")) row_layout.addWidget(ok_button) ok_button.clicked.connect(dialog.accept) cancel_button = QPushButton(_("Cancel")) row_layout.addWidget(cancel_button) cancel_button.clicked.connect(dialog.reject) return row_layout
def on_receive(self, keyhash, message): self.print_error("signal arrived for", keyhash) for key, _hash, window in self.keys: if _hash == keyhash: break else: self.print_error("keyhash not found") return wallet = window.wallet if isinstance(wallet.keystore, keystore.Hardware_KeyStore): window.show_warning( _('An encrypted transaction was retrieved from cosigning pool.' ) + '\n' + _('However, hardware wallets do not support message decryption, ' 'which makes them not compatible with the current design of cosigner pool.' )) return elif wallet.has_keystore_encryption(): password = window.password_dialog( _('An encrypted transaction was retrieved from cosigning pool.' ) + '\n' + _('Please enter your password to decrypt it.')) if not password: return else: password = None if not window.question( _("An encrypted transaction was retrieved from cosigning pool." ) + '\n' + _("Do you want to open it now?")): return xprv = wallet.keystore.get_master_private_key(password) if not xprv: return try: k = bitcoin.deserialize_xprv(xprv)[-1] EC = ecc.ECPrivkey(k) message = bh2u(EC.decrypt_message(message)) except Exception as e: traceback.print_exc(file=sys.stdout) window.show_error(_('Error decrypting message') + ':\n' + str(e)) return self.listener.clear(keyhash) tx = transaction.Transaction(message) show_transaction(tx, window, prompt_if_unsaved=True)
def calibration_dialog(self, window): d = WindowModalDialog(window, _("Revealer - Printer calibration settings")) d.setMinimumSize(100, 200) vbox = QVBoxLayout(d) vbox.addWidget( QLabel(''.join([ "<br/>", _("If you have an old printer, or want optimal precision"), "<br/>", _("print the calibration pdf and follow the instructions "), "<br/>", "<br/>", ]))) self.calibration_h = self.config.get('calibration_h') self.calibration_v = self.config.get('calibration_v') cprint = QPushButton(_("Open calibration pdf")) cprint.clicked.connect(self.calibration) vbox.addWidget(cprint) vbox.addWidget(QLabel(_('Calibration values:'))) grid = QGridLayout() vbox.addLayout(grid) grid.addWidget(QLabel(_('Right side')), 0, 0) horizontal = QLineEdit() horizontal.setText(str(self.calibration_h)) grid.addWidget(horizontal, 0, 1) grid.addWidget(QLabel(_('Bottom')), 1, 0) vertical = QLineEdit() vertical.setText(str(self.calibration_v)) grid.addWidget(vertical, 1, 1) vbox.addStretch() vbox.addSpacing(13) vbox.addLayout(Buttons(CloseButton(d), OkButton(d))) if not d.exec_(): return self.calibration_h = int(Decimal(horizontal.text())) self.config.set_key('calibration_h', self.calibration_h) self.calibration_v = int(Decimal(vertical.text())) self.config.set_key('calibration_v', self.calibration_v)
def __init__(self, config, app, plugins, storage): BaseWizard.__init__(self, config, plugins, storage) QDialog.__init__(self, None) self.setWindowTitle('Vialectrum - ' + _('Install Wizard')) self.app = app self.config = config # Set for base base class 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/vialectrum.png') self.show() self.raise_() self.refresh_gui() # Need for QT on MacOSX. Lame.
def passphrase_dialog(self, msg, confirm): # If confirm is true, require the user to enter the passphrase twice parent = self.top_level_window() if confirm: d = PasswordDialog(parent, None, msg, PW_PASSPHRASE) confirmed, p, passphrase = d.run() else: d = WindowModalDialog(parent, _("Enter Passphrase")) pw = QLineEdit() pw.setEchoMode(2) pw.setMinimumWidth(200) vbox = QVBoxLayout() vbox.addWidget(WWLabel(msg)) vbox.addWidget(pw) vbox.addLayout(Buttons(CancelButton(d), OkButton(d))) d.setLayout(vbox) passphrase = pw.text() if d.exec_() else None self.passphrase = passphrase self.done.set()
def receive_menu(self, menu, addrs, wallet): if type(wallet) is not Standard_Wallet: return keystore = wallet.get_keystore() if type(keystore) is not self.keystore_class: return if not self.is_mobile_paired(): return if not keystore.is_p2pkh(): return if len(addrs) == 1: def show_address(): keystore.thread.add(partial(self.show_address, wallet, addrs[0], keystore)) menu.addAction(_("Show on {}").format(self.device), show_address)
def item_changed(self, idx): # TODO use siblingAtColumn when min Qt version is >=5.11 addr = self.model().itemFromIndex( idx.sibling(idx.row(), self.Columns.ADDRESS)).text() req = self.wallet.receive_requests.get(addr) if req is None: self.update() return expires = age(req['time'] + req['exp']) if req.get('exp') else _('Never') amount = req['amount'] message = req['memo'] 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)
def __init__(self, parent, address): WindowModalDialog.__init__(self, parent, _("Address")) self.address = address self.parent = parent self.config = parent.config self.wallet = parent.wallet self.app = parent.app self.saved = True self.setMinimumWidth(700) vbox = QVBoxLayout() self.setLayout(vbox) vbox.addWidget(QLabel(_("Address:"))) self.addr_e = ButtonsLineEdit(self.address) self.addr_e.addCopyButton(self.app) icon = ":icons/qrcode_white.png" if ColorScheme.dark_scheme else ":icons/qrcode.png" self.addr_e.addButton(icon, self.show_qr, _("Show QR Code")) self.addr_e.setReadOnly(True) vbox.addWidget(self.addr_e) try: pubkeys = self.wallet.get_public_keys(address) except BaseException as e: pubkeys = None if pubkeys: vbox.addWidget(QLabel(_("Public keys") + ':')) for pubkey in pubkeys: pubkey_e = ButtonsLineEdit(pubkey) pubkey_e.addCopyButton(self.app) vbox.addWidget(pubkey_e) try: redeem_script = self.wallet.pubkeys_to_redeem_script(pubkeys) except BaseException as e: redeem_script = None if redeem_script: vbox.addWidget(QLabel(_("Redeem Script") + ':')) redeem_e = ShowQRTextEdit(text=redeem_script) redeem_e.addCopyButton(self.app) vbox.addWidget(redeem_e) vbox.addWidget(QLabel(_("History"))) self.hw = HistoryList(self.parent) self.hw.get_domain = self.get_domain vbox.addWidget(self.hw) vbox.addLayout(Buttons(CloseButton(self))) self.format_amount = self.parent.format_amount self.hw.update()
def __init__(self, main_window, exctype, value, tb): BaseCrashReporter.__init__(self, exctype, value, tb) self.main_window = main_window QWidget.__init__(self) self.setWindowTitle('Vialectrum - ' + _('An Error Occurred')) self.setMinimumSize(600, 300) main_box = QVBoxLayout() heading = QLabel('<h2>' + BaseCrashReporter.CRASH_TITLE + '</h2>') main_box.addWidget(heading) main_box.addWidget(QLabel(BaseCrashReporter.CRASH_MESSAGE)) main_box.addWidget(QLabel(BaseCrashReporter.REQUEST_HELP_MESSAGE)) collapse_info = QPushButton(_("Show report contents")) collapse_info.clicked.connect( lambda: self.msg_box(QMessageBox.NoIcon, self, _( "Report contents"), self.get_report_string())) main_box.addWidget(collapse_info) main_box.addWidget(QLabel(BaseCrashReporter.DESCRIBE_ERROR_MESSAGE)) self.description_textfield = QTextEdit() self.description_textfield.setFixedHeight(50) main_box.addWidget(self.description_textfield) main_box.addWidget(QLabel(BaseCrashReporter.ASK_CONFIRM_SEND)) buttons = QHBoxLayout() report_button = QPushButton(_('Send Bug Report')) report_button.clicked.connect(self.send_report) report_button.setIcon(QIcon(":icons/tab_send.png")) buttons.addWidget(report_button) never_button = QPushButton(_('Never')) never_button.clicked.connect(self.show_never) buttons.addWidget(never_button) close_button = QPushButton(_('Not Now')) close_button.clicked.connect(self.close) buttons.addWidget(close_button) main_box.addLayout(buttons) self.setLayout(main_box) self.show()
def refresh_headers(self): headers = [ '', '', _('Date'), _('Description'), _('Amount'), _('Balance') ] fx = self.parent.fx if fx and fx.show_history(): headers.extend( ['%s ' % fx.ccy + _('Amount'), '%s ' % fx.ccy + _('Balance')]) self.update_headers(headers)
def __init__(self, parent=None): super().__init__(parent, self.create_menu, stretch_column=self.Columns.LABEL) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.show_change = 0 self.show_used = 0 self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) for t in [_('All'), _('Receiving'), _('Change')]: 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) self.setModel(QStandardItemModel(self)) self.update()
def show_address(self, wallet, keystore, address): client = self.get_client(keystore) if not client.atleast_version(1, 3): keystore.handler.show_error(_("Your device firmware is too old")) return change, index = wallet.get_address_index(address) derivation = keystore.derivation address_path = "%s/%d/%d" % (derivation, change, index) address_n = client.expand_path(address_path) xpubs = wallet.get_master_public_keys() if len(xpubs) == 1: script_gen = keystore.get_script_gen() if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: script_type = self.types.InputScriptType.SPENDWITNESS elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: script_type = self.types.InputScriptType.SPENDP2SHWITNESS else: script_type = self.types.InputScriptType.SPENDADDRESS client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) else: def f(xpub): node = self.ckd_public.deserialize(xpub) return self.types.HDNodePathType(node=node, address_n=[change, index]) pubkeys = wallet.get_public_keys(address) # sort xpubs using the order of pubkeys sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs))) pubkeys = list(map(f, sorted_xpubs)) multisig = self.types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=[b''] * wallet.n, m=wallet.m, ) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig)
def refresh_headers(self): headers = [ '', '', _('Date'), _('Description'), _('Amount'), _('Balance') ] fx = self.parent.fx if fx and fx.show_history(): headers.extend(['%s ' % fx.ccy + _('Value')]) self.editable_columns |= {6} if fx.get_history_capital_gains_config(): headers.extend(['%s ' % fx.ccy + _('Acquisition price')]) headers.extend(['%s ' % fx.ccy + _('Capital Gains')]) else: self.editable_columns -= {6} self.update_headers(headers)
def settings_dialog(self, window): wallet = window.parent().wallet d = WindowModalDialog(window, _("Label Settings")) hbox = QHBoxLayout() hbox.addWidget(QLabel("Label sync options:")) upload = ThreadedButton("Force upload", partial(self.push_thread, wallet), partial(self.done_processing, d)) download = ThreadedButton("Force download", partial(self.pull_thread, wallet, True), partial(self.done_processing, d)) vbox = QVBoxLayout() vbox.addWidget(upload) vbox.addWidget(download) hbox.addLayout(vbox) vbox = QVBoxLayout(d) vbox.addLayout(hbox) vbox.addSpacing(20) vbox.addLayout(Buttons(OkButton(d))) return bool(d.exec_())
def sign_message(self, sequence, message, password): self.signing = True # prompt for the PIN before displaying the dialog if necessary client = self.get_client() address_path = self.get_derivation()[2:] + "/%d/%d"%sequence self.handler.show_message("Signing message ...") try: info = self.get_client().signMessagePrepare(address_path, message) pin = "" if info['confirmationNeeded']: pin = self.handler.get_auth( info ) # does the authenticate dialog and returns pin if not pin: raise UserWarning(_('Cancelled by user')) pin = str(pin).encode() signature = self.get_client().signMessageSign(pin) except BTChipException, e: if e.sw == 0x6a80: self.give_error("Unfortunately, this message cannot be signed by the Ledger wallet. Only alphanumerical messages shorter than 140 characters are supported. Please remove any extra characters (tab, carriage return) and retry.") else: self.give_error(e, True)
def run_upgrades(self, storage): path = storage.path if storage.requires_split(): self.hide() msg = _( "The wallet '{}' contains multiple accounts, which are no longer supported since 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 = '\n'.join(storage.split_accounts()) msg = _('Your accounts have been moved to' ) + ':\n' + 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 = storage.get_action() if action and storage.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 = storage.db.data # FIXME self.run(action) for k, v in self.data.items(): storage.put(k, v) storage.write() return if storage.requires_upgrade(): self.upgrade_storage(storage)
def show_restore(self, wallet, network): # FIXME: these messages are shown after the install wizard is # finished and the window closed. On macOS they appear parented # with a re-appeared ghost install wizard window... if network: def task(): wallet.wait_until_synchronized() if wallet.is_found(): msg = _("Recovery successful") else: msg = _("No transactions found for this seed") self.synchronized_signal.emit(msg) self.synchronized_signal.connect(self.show_message) t = threading.Thread(target = task) t.daemon = True t.start() else: msg = _("This wallet was restored offline. It may " "contain more addresses than displayed.") self.show_message(msg)
def select_date(self, button): d = WindowModalDialog(self, _("Select date")) d.setMinimumSize(600, 150) d.date = None vbox = QVBoxLayout() def on_date(date): d.date = date cal = QCalendarWidget() cal.setGridVisible(True) cal.clicked[QDate].connect(on_date) vbox.addWidget(cal) vbox.addLayout(Buttons(OkButton(d), CancelButton(d))) d.setLayout(vbox) if d.exec_(): if d.date is None: return None date = d.date.toPyDate() button.setText(self.format_date(date)) return datetime.datetime(date.year, date.month, date.day)
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.get(addr) if req is None: self.update() return 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)
def sign_transaction(self, tx, password): if tx.is_complete(): return # previous transactions used as inputs prev_tx = {} # path of the xpubs that are involved xpub_path = {} for txin in tx.inputs(): pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin) tx_hash = txin['prevout_hash'] if txin.get('prev_tx') is None and not Transaction.is_segwit_input(txin): raise Exception(_('Offline signing with {} is not supported for legacy inputs.').format(self.device)) prev_tx[tx_hash] = txin['prev_tx'] for x_pubkey in x_pubkeys: if not is_xpubkey(x_pubkey): continue xpub, s = parse_xpubkey(x_pubkey) if xpub == self.get_master_public_key(): xpub_path[xpub] = self.get_derivation() self.plugin.sign_transaction(self, tx, prev_tx, xpub_path)
def update(self): net_params = self.network.get_parameters() host, port, protocol = net_params.host, net_params.port, net_params.protocol proxy_config, auto_connect = net_params.proxy, net_params.auto_connect self.server_host.setText(host) self.server_port.setText(str(port)) self.autoconnect_cb.setChecked(auto_connect) interface = self.network.interface host = interface.host if interface else _('None') self.server_label.setText(host) self.set_protocol(protocol) self.servers = self.network.get_servers() self.servers_list.update(self.servers, self.protocol, self.tor_cb.isChecked()) self.enable_set_server() height_str = "%d " % (self.network.get_local_height()) + _('blocks') self.height_label.setText(height_str) n = len(self.network.get_interfaces()) status = _("Connected to {0} nodes.").format(n) if n else _( "Not connected") self.status_label.setText(status) chains = self.network.get_blockchains() if len(chains) > 1: chain = self.network.blockchain() forkpoint = chain.get_max_forkpoint() name = chain.get_name() msg = _('Chain split detected at block {0}').format( forkpoint) + '\n' msg += (_('You are following branch') if auto_connect else _('Your server is on branch')) + ' ' + name msg += ' (%d %s)' % (chain.get_branch_size(), _('blocks')) else: msg = '' self.split_label.setText(msg) self.nodes_list_widget.update(self.network)
def on_edit(self): 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 vialectrum.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) # to account for bip39 seeds for word in self.get_seed().split(" ")[:-1]: if word not in self.wordlist: self.seed_e.disable_suggestions() return self.seed_e.enable_suggestions()
def __init__(self, wallet, msg, kind, OK_button): self.wallet = wallet self.kind = kind self.OK_button = OK_button vbox = QVBoxLayout() label = QLabel(msg + "\n") label.setWordWrap(True) grid = QGridLayout() grid.setSpacing(8) grid.setColumnMinimumWidth(0, 150) grid.setColumnMinimumWidth(1, 100) grid.setColumnStretch(1,1) logo_grid = QGridLayout() logo_grid.setSpacing(8) logo_grid.setColumnMinimumWidth(0, 70) logo_grid.setColumnStretch(1,1) logo = QLabel() logo.setAlignment(Qt.AlignCenter) logo_grid.addWidget(logo, 0, 0) logo_grid.addWidget(label, 0, 1, 1, 2) vbox.addLayout(logo_grid) if wallet and wallet.has_storage_encryption(): lockfile = ":icons/lock.png" else: lockfile = ":icons/unlock.png" logo.setPixmap(QPixmap(lockfile).scaledToWidth(36, mode=Qt.SmoothTransformation)) vbox.addLayout(grid) self.encrypt_cb = QCheckBox(_('Encrypt wallet file')) grid.addWidget(self.encrypt_cb, 1, 0, 1, 2) self.vbox = vbox
def show_address(self, wallet, address, keystore=None): if keystore is None: keystore = wallet.get_keystore() if not self.show_address_helper(wallet, address, keystore): return client = self.get_client(keystore) if not client.atleast_version(1, 3): keystore.handler.show_error(_("Your device firmware is too old")) return change, index = wallet.get_address_index(address) derivation = keystore.derivation address_path = "%s/%d/%d" % (derivation, change, index) address_n = client.expand_path(address_path) xpubs = wallet.get_master_public_keys() if len(xpubs) == 1: script_type = self.get_trezor_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, script_type=script_type) else: def f(xpub): return self._make_node_path(xpub, [change, index]) pubkeys = wallet.get_public_keys(address) # sort xpubs using the order of pubkeys sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs))) pubkeys = list(map(f, sorted_xpubs)) multisig = self.types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=[b''] * wallet.n, m=wallet.m, ) script_type = self.get_trezor_input_script_type(wallet.txin_type) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type)
def on_filename(filename): path = os.path.join(wallet_folder, filename) try: self.storage = WalletStorage(path, manual_upgrades=True) self.next_button.setEnabled(True) except BaseException: traceback.print_exc(file=sys.stderr) self.storage = None self.next_button.setEnabled(False) if self.storage: if not self.storage.file_exists(): msg =_("This file does not exist.") + '\n' \ + _("Press 'Next' to create this wallet, or choose another file.") pw = False else: if self.storage.is_encrypted_with_user_pw(): msg = _("This file is encrypted with a password.") + '\n' \ + _('Enter your password or choose another file.') pw = True elif self.storage.is_encrypted_with_hw_device(): msg = _("This file is encrypted using a hardware device.") + '\n' \ + _("Press 'Next' to choose device to decrypt.") pw = False else: msg = _("Press 'Next' to open this wallet.") pw = False else: msg = _('Cannot read file') pw = False self.msg_label.setText(msg) if pw: self.pw_label.show() self.pw_e.show() self.pw_e.setFocus() else: self.pw_label.hide() self.pw_e.hide()
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))
def address_field(addresses): hbox = QHBoxLayout() address_e = QLineEdit() if addresses and len(addresses) > 0: address_e.setText(addresses[0]) else: addresses = [] def func(): try: i = addresses.index(str(address_e.text())) + 1 i = i % len(addresses) address_e.setText(addresses[i]) except ValueError: # the user might have changed address_e to an # address not in the wallet (or to something that isn't an address) if addresses and len(addresses) > 0: address_e.setText(addresses[0]) button = QPushButton(_('Address')) button.clicked.connect(func) hbox.addWidget(button) hbox.addWidget(address_e) return hbox, address_e
def show_address(self, sequence, txin_type): client = self.get_client() address_path = self.get_derivation()[2:] + "/%d/%d" % sequence self.handler.show_message(_("Showing address ...")) segwit = Transaction.is_segwit_inputtype(txin_type) segwitNative = txin_type == 'p2wpkh' try: client.getWalletPublicKey(address_path, showOnScreen=True, segwit=segwit, segwitNative=segwitNative) except BTChipException as e: if e.sw == 0x6985: # cancelled by user pass else: traceback.print_exc(file=sys.stderr) self.handler.show_error(e) except BaseException as e: traceback.print_exc(file=sys.stderr) self.handler.show_error(e) finally: self.handler.finished()
def _initialize_device(self, settings, method, device_id, wizard, handler): item, label, pin_protection, passphrase_protection = settings if method == TIM_RECOVER: # FIXME the PIN prompt will appear over this message # which makes this unreadable handler.show_error( _("You will be asked to enter 24 words regardless of your " "seed's actual length. If you enter a word incorrectly or " "misspell it, you cannot change it or go back - you will need " "to start again from the beginning.\n\nSo please enter " "the words carefully!")) language = 'english' devmgr = self.device_manager() client = devmgr.client_by_id(device_id) if method == TIM_NEW: strength = 64 * (item + 2) # 128, 192 or 256 u2f_counter = 0 skip_backup = False client.reset_device(True, strength, passphrase_protection, pin_protection, label, language, u2f_counter, skip_backup) elif method == TIM_RECOVER: word_count = 6 * (item + 2) # 12, 18 or 24 client.step = 0 client.recovery_device(word_count, passphrase_protection, pin_protection, label, language) elif method == TIM_MNEMONIC: pin = pin_protection # It's the pin, not a boolean client.load_device_by_mnemonic(str(item), pin, passphrase_protection, label, language) else: pin = pin_protection # It's the pin, not a boolean client.load_device_by_xprv(item, pin, passphrase_protection, label, language) wizard.loop.exit(0)
def create_menu(self, position): menu = QMenu() selected = self.selectedItems() if not selected: menu.addAction(_("New contact"), lambda: self.parent.new_contact_dialog()) menu.addAction(_("Import file"), lambda: self.import_contacts()) menu.addAction(_("Export file"), lambda: self.export_contacts()) else: names = [item.text(0) for item in selected] keys = [item.text(1) for item in selected] column = self.currentColumn() column_title = self.headerItem().text(column) column_data = '\n'.join([item.text(column) for item in selected]) menu.addAction( _("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) if column in self.editable_columns: item = self.currentItem() menu.addAction( _("Edit {}").format(column_title), lambda: self.editItem(item, column)) menu.addAction(_("Pay to"), lambda: self.parent.payto_contacts(keys)) menu.addAction(_("Delete"), lambda: self.parent.delete_contacts(keys)) URLs = [ block_explorer_URL(self.config, 'addr', key) for key in filter(is_address, keys) ] if URLs: menu.addAction(_("View on block explorer"), lambda: map(webbrowser.open, URLs)) run_hook('create_contact_menu', menu, selected) menu.exec_(self.viewport().mapToGlobal(position))
def on_receive(self, keyhash, message): self.print_error("signal arrived for", keyhash) for key, _hash, window in self.keys: if _hash == keyhash: break else: self.print_error("keyhash not found") return wallet = window.wallet if wallet.has_keystore_encryption(): password = window.password_dialog( 'An encrypted transaction was retrieved from cosigning pool.\nPlease enter your password to decrypt it.' ) if not password: return else: password = None if not window.question( _("An encrypted transaction was retrieved from cosigning pool.\nDo you want to open it now?" )): return xprv = wallet.keystore.get_master_private_key(password) if not xprv: return try: k = bh2u(bitcoin.deserialize_xprv(xprv)[-1]) EC = bitcoin.EC_KEY(bfh(k)) message = bh2u(EC.decrypt_message(message)) except Exception as e: traceback.print_exc(file=sys.stdout) window.show_message(str(e)) return self.listener.clear(keyhash) tx = transaction.Transaction(message) show_transaction(tx, window, prompt_if_unsaved=True)