def create_menu(self, position): item = self.currentItem() if not item: return menu = QMenu() server = item.data(1, Qt.UserRole) menu.addAction(_("Use as server"), lambda: self.set_server(server)) menu.exec_(self.viewport().mapToGlobal(position))
def __init__(self, parent): super(SignAnnounceWidget, self).__init__(parent) self.dialog = parent self.manager = parent.manager # Displays the status of the masternode. self.status_edit = QLineEdit() self.status_edit.setReadOnly(True) self.alias_edit = QLineEdit() self.collateral_edit = PrevOutWidget() self.delegate_edit = QLineEdit() self.delegate_edit.setFont(QFont(util.MONOSPACE_FONT)) for i in [self.alias_edit, self.collateral_edit, self.delegate_edit]: i.setReadOnly(True) self.mapper = QDataWidgetMapper() self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.dialog.masternodes_widget.proxy_model) model = self.dialog.masternodes_widget.model self.mapper.addMapping(self.alias_edit, model.ALIAS) self.mapper.addMapping(self.collateral_edit, model.VIN, b'string') self.mapper.addMapping(self.delegate_edit, model.DELEGATE) self.sign_button = QPushButton(_('Activate Masternode')) self.sign_button.setEnabled(False) self.sign_button.clicked.connect(self.sign_announce) status_box = QHBoxLayout() status_box.setContentsMargins(0, 0, 0, 0) status_box.addWidget(QLabel(_('Status:'))) status_box.addWidget(self.status_edit, stretch=1) vbox = QVBoxLayout() vbox.addLayout(status_box) form = QFormLayout() form.addRow(_('Alias:'), self.alias_edit) form.addRow(_('Collateral SPARKS Output:'), self.collateral_edit) form.addRow(_('Masternode Private Key:'), self.delegate_edit) vbox.addLayout(form) vbox.addLayout(util.Buttons(self.sign_button)) self.setLayout(vbox)
def calibration_pdf(self, image): printer = QPrinter() printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter) printer.setResolution(600) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(self.base_dir + _('calibration') + '.pdf') printer.setPageMargins(0, 0, 0, 0, 6) painter = QPainter() painter.begin(printer) painter.drawImage(553, 533, image) font = QFont('Source Sans Pro', 10, QFont.Bold) painter.setFont(font) painter.drawText(254, 277, _("Calibration sheet")) font = QFont('Source Sans Pro', 7, QFont.Bold) painter.setFont(font) painter.drawText(600, 2077, _("Instructions:")) font = QFont('Source Sans Pro', 7, QFont.Normal) painter.setFont(font) painter.drawText( 700, 2177, _("1. Place this paper on a flat and well iluminated surface.")) painter.drawText( 700, 2277, _("2. Align your Revealer borderlines to the sparksed lines on the top and left." )) painter.drawText( 700, 2377, _("3. Press slightly the Revealer against the paper and read the numbers that best " "match on the opposite sides. ")) painter.drawText(700, 2477, _("4. Type the numbers in the software")) painter.end()
def check_device_dialog(self): # Set password if fresh device if self.password is None and not self.dbb_has_password(): if not self.setupRunning: return False # A fresh device cannot connect to an existing wallet msg = _("An uninitialized Digital Bitbox is detected.") + " " + \ _("Enter a new password below.") + "\n\n" + \ _("REMEMBER THE PASSWORD!") + "\n\n" + \ _("You cannot access your coins or a backup without the password.") + "\n" + \ _("A backup is saved automatically when generating a new wallet.") if self.password_dialog(msg): reply = self.hid_send_plain(b'{"password":"******"}') else: return False # Get password from user if not yet set msg = _("Enter your Digital Bitbox password:"******"led":"blink"}') if 'error' in reply: self.password = None if reply['error']['code'] == 109: msg = _("Incorrect password entered.") + "\n\n" + \ reply['error']['message'] + "\n\n" + \ _("Enter your Digital Bitbox password:"******"Unexpected error occurred.") + "\n\n" + \ reply['error']['message'] + "\n\n" + \ _("Enter your Digital Bitbox password:"******"device":"info"}') if reply['device']['id'] != "": self.recover_or_erase_dialog() # Already seeded else: self.seed_device_dialog() # Seed if not initialized self.mobile_pairing_dialog() return self.isInitialized
def setup_dialog(self, window): self.update_wallet_name(window.parent().parent().wallet) self.user_input = False self.noise_seed = False self.d = WindowModalDialog(window, "Revealer") self.d.setMinimumWidth(420) vbox = QVBoxLayout(self.d) vbox.addSpacing(21) logo = QLabel() vbox.addWidget(logo) logo.setPixmap(QPixmap(':icons/revealer.png')) logo.setAlignment(Qt.AlignCenter) vbox.addSpacing(42) self.load_noise = ScanQRTextEdit() self.load_noise.setTabChangesFocus(True) self.load_noise.textChanged.connect(self.on_edit) self.load_noise.setMaximumHeight(33) vbox.addWidget( WWLabel("<b>" + _("Enter your physical revealer code:") + "<b>")) vbox.addWidget(self.load_noise) vbox.addSpacing(11) self.next_button = QPushButton(_("Next"), self.d) self.next_button.setDefault(True) self.next_button.setEnabled(False) vbox.addLayout(Buttons(self.next_button)) self.next_button.clicked.connect(self.d.close) self.next_button.clicked.connect( partial(self.cypherseed_dialog, window)) vbox.addSpacing(21) vbox.addWidget(WWLabel(_("or, alternatively: "))) bcreate = QPushButton(_("Create a digital Revealer")) def mk_digital(): try: self.make_digital(self.d) except Exception: traceback.print_exc(file=sys.stdout) else: self.cypherseed_dialog(window) bcreate.clicked.connect(mk_digital) vbox.addWidget(bcreate) vbox.addSpacing(11) vbox.addWidget( QLabel(''.join([ "<b>" + _("WARNING") + "</b>:" + _("Printing a revealer and encrypted seed"), '<br/>', _("on the same printer is not trustless towards the printer."), '<br/>', ]))) vbox.addSpacing(11) vbox.addLayout(Buttons(CloseButton(self.d))) return bool(self.d.exec_())
def on_filename(filename): path = os.path.join(wallet_folder, filename) wallet_from_memory = get_wallet_from_daemon(path) try: if wallet_from_memory: self.storage = wallet_from_memory.storage else: 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 elif not wallet_from_memory: 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 = _("This file is already open in memory.") + "\n" \ + _("Press 'Next' to create/focus window.") 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 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=keystore): keystore.thread.add(partial(self.show_address, wallet, addrs[0], keystore)) device_name = "{} ({})".format(self.device, keystore.label) menu.addAction(_("Show on {}").format(device_name), show_address)
def get_xpub(self, device_id, derivation, xtype, wizard): if xtype not in self.SUPPORTED_XTYPES: raise ScriptTypeNotSupported(_('This type of script is not supported with {}.').format(self.device)) devmgr = self.device_manager() client = devmgr.client_by_id(device_id) client.handler = self.create_handler(wizard) client.checkDevice() xpub = client.get_xpub(derivation, xtype) return xpub
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()
def dbb_has_password(self): reply = self.hid_send_plain(b'{"ping":""}') if 'ping' not in reply: raise Exception( _('Device communication error. Please unplug and replug your Digital Bitbox.' )) if reply['ping'] == 'password': return True return False
def update_dlg(self): self.modes.setCurrentIndex(self.cfg['mode']) self.modebox.setVisible(True) self.addPair.setText( _("Pair") if not self.cfg['pair'] else _("Re-Pair")) self.addPair.setVisible(self.txdata['confirmationType'] > 2) self.helpmsg.setText( helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self. cfg['pair'] else 4]) self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100) self.pairbox.setVisible(False) self.helpmsg.setVisible(True) self.pinbox.setVisible(self.cfg['mode'] == 0) self.cardbox.setVisible(self.cfg['mode'] == 1) self.pintxt.setFocus( True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True) self.setMaximumHeight(400)
def create_password_layout(self, wallet, is_encrypted, OK_button): if not wallet.has_password(): msg = _('Your wallet is not protected.') msg += ' ' + _('Use this dialog to add a password to your wallet.') else: if not is_encrypted: msg = _( 'Your Sparks coins are password protected. However, your wallet file is not encrypted.' ) else: msg = _('Your wallet is password protected and encrypted.') msg += ' ' + _('Use this dialog to change your password.') self.playout = PasswordLayout( wallet, msg, PW_CHANGE, OK_button, force_disable_encrypt_cb=not wallet.can_have_keystore_encryption())
def checkDevice(self): if not self.preflightDone: try: self.perform_hw1_preflight() except BTChipException as e: if (e.sw == 0x6d00 or e.sw == 0x6700): raise Exception(_("Device not in Sparks mode")) from e raise e self.preflightDone = True
def __init__(self, data, parent=None, title="", show_text=False): WindowModalDialog.__init__(self, parent, title) vbox = QVBoxLayout() qrw = QRCodeWidget(data) qscreen = QApplication.primaryScreen() vbox.addWidget(qrw, 1) if show_text: text = QTextEdit() text.setText(data) text.setReadOnly(True) vbox.addWidget(text) hbox = QHBoxLayout() hbox.addStretch(1) config = electrum_sparks.get_config() if config: filename = os.path.join(config.path, "qrcode.png") def print_qr(): p = qscreen.grabWindow(qrw.winId()) p.save(filename, 'png') self.show_message(_("QR code saved to file") + " " + filename) def copy_to_clipboard(): p = qscreen.grabWindow(qrw.winId()) QApplication.clipboard().setPixmap(p) self.show_message(_("QR code copied to clipboard")) b = QPushButton(_("Copy")) hbox.addWidget(b) b.clicked.connect(copy_to_clipboard) b = QPushButton(_("Save")) hbox.addWidget(b) b.clicked.connect(print_qr) b = QPushButton(_("Close")) hbox.addWidget(b) b.clicked.connect(self.accept) b.setDefault(True) vbox.addLayout(hbox) self.setLayout(vbox)
def bcrypt(self, dialog): self.rawnoise = False dialog.show_message(''.join([ _("{} encrypted for Revealer {}_{} saved as PNG and PDF at:" ).format(self.was, self.version, self.code_id), "<br/>", "<b>", self.base_dir + self.filename + self.version + "_" + self.code_id, "</b>" ]), rich_text=True) dialog.close()
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 Sparks-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 Sparks-Electrum.' ), ]) else: msg = '' self.seed_warning.setText(msg)
def create_masternode_conf_tab(self): """Create the tab used to import masternode.conf files.""" desc = ' '.join([ 'You can use this form to import your masternode.conf file.', 'This file is usually located in the same directory that your wallet file is in.', 'If you just need to import your masternode\'s private key, use the regular process for importing a key.' ]) desc = QLabel(_(desc)) desc.setWordWrap(True) import_filename_edit = QLineEdit() import_filename_edit.setPlaceholderText( _('Enter the path to your masternode.conf')) import_select_file = QPushButton(_('Select File...')) hbox = QHBoxLayout() hbox.addWidget(import_filename_edit, stretch=1) hbox.addWidget(import_select_file) import_conf_button = QPushButton(_('Import')) vbox = QVBoxLayout() vbox.addWidget(desc) vbox.addLayout(hbox) vbox.addLayout(util.Buttons(import_conf_button)) vbox.addStretch(1) def select_import_file(): text = QFileDialog.getOpenFileName(None, _('Select a file to import'), '', '*.conf') if text and len(text) == 2: import_filename_edit.setText(text[0]) import_select_file.clicked.connect(select_import_file) def do_import_file(): path = str(import_filename_edit.text()) self.import_masternode_conf(path) import_conf_button.clicked.connect(do_import_file) w = QWidget() w.setLayout(vbox) return w
def sign_message(self, sequence, message, password): message = message.encode('utf8') message_hash = hashlib.sha256(message).hexdigest().upper() # 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 ...\r\nMessage hash: "+message_hash) 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 as 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.") elif e.sw == 0x6985: # cancelled by user return b'' elif e.sw == 0x6982: raise # pin lock. decorator will catch it else: self.give_error(e, True) except UserWarning: self.handler.show_error(_('Cancelled by user')) return b'' except Exception as e: self.give_error(e, True) finally: self.handler.finished() # Parse the ASN.1 signature rLength = signature[3] r = signature[4 : 4 + rLength] sLength = signature[4 + rLength + 1] s = signature[4 + rLength + 2:] if rLength == 33: r = r[1:] if sLength == 33: s = s[1:] # And convert it return bytes([27 + 4 + (signature[0] & 0x01)]) + r + s
def toggle_passphrase(): title = _("Confirm Toggle Passphrase Protection") currently_enabled = self.features.passphrase_protection if currently_enabled: msg = _("After disabling passphrases, you can only pair this " "Sparks-Electrum wallet if it had an empty passphrase. " "If its passphrase was not empty, you will need to " "create a new wallet with the install wizard. You " "can use this wallet again at any time by re-enabling " "passphrases and entering its passphrase.") else: msg = _("Your current Sparks-Electrum wallet can only be used with " "an empty passphrase. You must create a separate " "wallet with the install wizard for other passphrases " "as each one generates a new set of addresses.") msg += "\n\n" + _("Are you sure you want to proceed?") if not self.question(msg, title=title): return invoke_client('toggle_passphrase', unpair_after=currently_enabled)
def filename_field(parent, config, defaultname, select_msg): vbox = QVBoxLayout() vbox.addWidget(QLabel(_("Format"))) gb = QGroupBox("format", parent) b1 = QRadioButton(gb) b1.setText(_("CSV")) b1.setChecked(True) b2 = QRadioButton(gb) b2.setText(_("json")) vbox.addWidget(b1) vbox.addWidget(b2) hbox = QHBoxLayout() directory = config.get('io_dir', os.path.expanduser('~')) path = os.path.join( directory, defaultname ) filename_e = QLineEdit() filename_e.setText(path) def func(): text = filename_e.text() _filter = "*.csv" if text.endswith(".csv") else "*.json" if text.endswith(".json") else None p, __ = QFileDialog.getSaveFileName(None, select_msg, text, _filter) if p: filename_e.setText(p) button = QPushButton(_('File')) button.clicked.connect(func) hbox.addWidget(button) hbox.addWidget(filename_e) vbox.addLayout(hbox) def set_csv(v): text = filename_e.text() text = text.replace(".json",".csv") if v else text.replace(".csv",".json") filename_e.setText(text) b1.clicked.connect(lambda: set_csv(True)) b2.clicked.connect(lambda: set_csv(False)) return vbox, filename_e, b1
def show_transaction(tx, parent, desc=None, prompt_if_unsaved=False): try: d = TxDialog(tx, parent, desc, prompt_if_unsaved) except SerializationError as e: traceback.print_exc(file=sys.stderr) parent.show_critical( _("Sparks-Electrum was unable to deserialize the transaction:") + "\n" + str(e)) else: dialogs.append(d) d.show()
def file_input(self): fileName, __ = QFileDialog.getOpenFileName(self, 'select file') if not fileName: return try: with open(fileName, "r") as f: data = f.read() except BaseException as e: self.show_error(_('Error opening file') + ':\n' + str(e)) else: self.setText(data)
def receive_menu(self, menu, addrs, wallet): if type(wallet) is not Standard_Wallet: return keystore = wallet.get_keystore() if type(keystore) == self.keystore_class and len(addrs) == 1: def show_address(): keystore.thread.add( partial(self.show_address, wallet, addrs[0])) menu.addAction(_("Show on Ledger"), show_address)
def init_network(self, network): message = _("Sparks-Electrum communicates with remote servers to get " "information about your transactions and addresses. The " "servers all fulfill the same purpose only differing in " "hardware. In most cases you simply want to let Sparks-Electrum " "pick one at random. However if you prefer feel free to " "select a server manually.") choices = [_("Auto connect"), _("Select server manually")] title = _("How do you want to connect to a server? ") clayout = ChoicesLayout(message, choices) self.back_button.setText(_('Cancel')) self.exec_layout(clayout.layout(), title) r = clayout.selected_index() if r == 1: nlayout = NetworkChoiceLayout(network, self.config, wizard=True) if self.exec_layout(nlayout.layout()): nlayout.accept() else: network.auto_connect = True self.config.set_key('auto_connect', True, True)
def set_mapper_index(self, row): """Set the row that the data widget mapper should use.""" self.valid_outputs_list.clear() self.status_edit.clear() self.status_edit.setStyleSheet( util.ColorScheme.DEFAULT.as_stylesheet()) self.mapper.setCurrentIndex(row) mn = self.dialog.masternodes_widget.masternode_for_row(row) status_text = _('Masternode has no collateral payment assigned.') can_scan = not mn.announced # Disable the scan_outputs button if the masternode already has an assigned output. if mn.vin.get('value', 0) == COIN * 1000: can_scan = False self.valid_outputs_list.add_output(mn.vin) status_text = _('Masternode already has a collateral payment.') self.status_edit.setText(_(status_text)) self.scan_outputs_button.setEnabled(can_scan)
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 if type(wallet) is not Standard_Wallet: keystore.handler.show_error(_('This function is only available for standard wallets when using {}.').format(self.device)) return sequence = wallet.get_address_index(address) txin_type = wallet.get_txin_type(address) keystore.show_address(sequence, txin_type)
def add_show_address_on_hw_device_button_for_receive_addr( self, wallet, keystore, main_window): plugin = keystore.plugin receive_address_e = main_window.receive_address_e def show_address(): addr = receive_address_e.text() keystore.thread.add( partial(plugin.show_address, wallet, addr, keystore)) receive_address_e.addButton(":icons/eye1.png", show_address, _("Show on {}").format(plugin.device))
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.finished.connect(self.deleteLater) # see #3956 self.thread.add(task, on_success, self.accept, on_error)
def create_menu(self, position): menu = QMenu() item = self.itemAt(position) if not item: return key = item.data(0, Qt.UserRole) column = self.currentColumn() column_title = self.headerItem().text(column) column_data = item.text(column) pr = self.parent.invoices.get(key) status = self.parent.invoices.get_status(key) if column_data: menu.addAction( _("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) menu.addAction(_("Details"), lambda: self.parent.show_invoice(key)) if status == PR_UNPAID: menu.addAction(_("Pay Now"), lambda: self.parent.do_pay_invoice(key)) menu.addAction(_("Delete"), lambda: self.parent.delete_invoice(key)) menu.exec_(self.viewport().mapToGlobal(position))
def calibration(self): img = QImage(self.size[0], self.size[1], QImage.Format_Mono) bitmap = QBitmap.fromImage(img, Qt.MonoOnly) bitmap.fill(Qt.black) self.make_calnoise() img = self.overlay_marks( self.calnoise.scaledToHeight(self.f_size.height()), False, True) self.calibration_pdf(img) QDesktopServices.openUrl( QUrl.fromLocalFile( os.path.abspath(self.base_dir + _('calibration') + '.pdf'))) return img