예제 #1
0
class PasswordDialog(AbstractPasswordDialog):
    enter_pw_message = _('Enter your password')
    enter_new_pw_message = _('Enter new password')
    confirm_new_pw_message = _('Confirm new password')
    wrong_password_message = _('Wrong password')
    allow_disable = False

    def __init__(self, app, **kwargs):
        AbstractPasswordDialog.__init__(self, app, **kwargs)
        self.hide_wallet_label = app._use_single_password

    def clear_password(self):
        self.ids.textinput_generic_password.text = ''

    def on_password(self, pw: str):
        #
        if not self.require_password:
            self.success = True
            self.message = _('Please wait...')
            self.dismiss()
            return
        # if setting new generic password, enforce min length
        if self.level > 0:
            if len(pw) < 6:
                self.app.show_error(
                    _('Password is too short (min {} characters)').format(6))
                return
        # don't enforce minimum length on existing
        self.do_check(pw)
예제 #2
0
 def new_request(self, lightning):
     amount = self.amount
     amount = self.app.get_amount(amount) if amount else 0
     message = self.message
     lnworker = self.app.wallet.lnworker
     try:
         if lightning:
             if lnworker:
                 key = lnworker.add_request(amount, message, self.expiry())
             else:
                 self.app.show_error(_("Lightning payments are not available for this wallet"))
                 return
         else:
             addr = self.address or self.app.wallet.get_unused_address()
             if not addr:
                 if not self.app.wallet.is_deterministic():
                     addr = self.app.wallet.get_receiving_address()
                 else:
                     self.app.show_info(_('No address available. Please remove some of your pending requests.'))
                     return
             self.address = addr
             req = self.app.wallet.make_payment_request(addr, amount, message, self.expiry())
             self.app.wallet.add_payment_request(req)
             key = addr
     except InvoiceError as e:
         self.app.show_error(_('Error creating payment request') + ':\n' + str(e))
         return
     self.clear()
     self.update()
     self.app.show_request(lightning, key)
예제 #3
0
 def init_storage_from_path(self, path):
     self.storage = WalletStorage(path)
     self.basename = self.storage.basename()
     if not self.storage.file_exists():
         self.require_password = False
         self.message = _('Press Next to create')
     elif self.storage.is_encrypted():
         if not self.storage.is_encrypted_with_user_pw():
             raise Exception(
                 "Kivy GUI does not support this type of encrypted wallet files."
             )
         self.pw_check = self.storage.check_password
         if self.app.password and self.check_password(self.app.password):
             self.pw = self.app.password  # must be set so that it is returned in callback
             self.require_password = False
             self.message = _('Press Next to open')
         else:
             self.require_password = True
             self.message = self.enter_pw_message
     else:
         # it is a bit wasteful load the wallet here and load it again in main_window,
         # but that is fine, because we are progressively enforcing storage encryption.
         db = WalletDB(self.storage.read(), manual_upgrades=False)
         wallet = Wallet(db,
                         self.storage,
                         config=self.app.electrumsys_config)
         self.require_password = wallet.has_password()
         self.pw_check = wallet.check_password
         self.message = self.enter_pw_message if self.require_password else _(
             'Wallet not encrypted')
예제 #4
0
 def do_open_channel(self, funding_tx, conn_str, password):
     # read funding_sat from tx; converts '!' to int value
     funding_sat = funding_tx.output_value_for_address(ln_dummy_address())
     lnworker = self.app.wallet.lnworker
     try:
         chan, funding_tx = lnworker.open_channel(
             connect_str=conn_str,
             funding_tx=funding_tx,
             funding_sat=funding_sat,
             push_amt_sat=0,
             password=password)
     except Exception as e:
         self.app.logger.exception("Problem opening channel")
         self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e))
         return
     # TODO: it would be nice to show this before broadcasting
     if chan.has_onchain_backup():
         self.maybe_show_funding_tx(chan, funding_tx)
     else:
         title = _('Save backup')
         help_text = _(messages.MSG_CREATED_NON_RECOVERABLE_CHANNEL)
         data = lnworker.export_channel_backup(chan.channel_id)
         popup = QRDialog(
             title, data,
             show_text=False,
             text_for_clipboard=data,
             help_text=help_text,
             close_button_text=_('OK'),
             on_close=lambda: self.maybe_show_funding_tx(chan, funding_tx))
         popup.open()
예제 #5
0
 def do_pay_invoice(self, invoice):
     if invoice.is_lightning():
         if self.app.wallet.lnworker:
             amount_sat = invoice.get_amount_sat()
             msg = _("Pay lightning invoice?") + '\n\n' + _("This will send {}?").format(self.app.format_amount_and_units_with_fiat(amount_sat)) +'\n'
             self.app.protected(msg, self._do_pay_lightning, (invoice,))
         else:
             self.app.show_error(_("Lightning payments are not available for this wallet"))
     else:
         self._do_pay_onchain(invoice)
예제 #6
0
 def get_card(self, addr, balance, is_used, label):
     ci = {}
     ci['screen'] = self
     ci['address'] = addr
     ci['memo'] = label
     ci['amount'] = self.app.format_amount_and_units(balance)
     ci['status'] = _('Used') if is_used else _(
         'Funded') if balance > 0 else _('Unused')
     ci['is_frozen'] = self.app.wallet.is_frozen_address(addr)
     return ci
예제 #7
0
 def close(self):
     dialog = ChoiceDialog(title=_('Close channel'),
                           choices={
                               0: _('Cooperative close'),
                               1: _('Request force-close')
                           },
                           key=0,
                           callback=self._close,
                           description=_(messages.MSG_REQUEST_FORCE_CLOSE),
                           keep_choice_order=True)
     dialog.open()
예제 #8
0
 def routing_dialog(self, item, dt):
     description = _(messages.MSG_HELP_TRAMPOLINE)
     def cb(text):
         self.app.use_gossip = (text == 'Gossip')
     dialog = ChoiceDialog(
         _('Lightning Routing'),
         ['Trampoline', 'Gossip'],
         'Gossip' if self.app.use_gossip else 'Trampoline',
         cb, description=description,
         keep_choice_order=True)
     dialog.open()
예제 #9
0
 def update_status(self):
     invoice = self.app.wallet.get_invoice(self.key)
     self.status = self.app.wallet.get_invoice_status(invoice)
     self.status_str = invoice.get_status_str(self.status)
     self.status_color = pr_color[self.status]
     self.can_pay = self.status in [PR_UNPAID, PR_FAILED]
     if self.can_pay and self.is_lightning and self.app.wallet.lnworker:
         if self.amount_sat and self.amount_sat > self.app.wallet.lnworker.num_sats_can_send(
         ):
             self.warning = _('Warning') + ': ' + _(
                 'This amount exceeds the maximum you can currently send with your channels'
             )
예제 #10
0
 def __init__(self,
              msg,
              callback,
              *,
              yes_str: str = None,
              no_str: str = None,
              title: str = None):
     Factory.Popup.__init__(self)
     self.yes_str = yes_str or _('Yes')
     self.no_str = no_str or _('No')
     self.title = title or _('Question')
     self.message = msg
     self.callback = callback
예제 #11
0
    def maybe_show_funding_tx(self, chan, funding_tx):
        n = chan.constraints.funding_txn_minimum_depth
        message = '\n'.join([
            _('Channel established.'),
            _('Remote peer ID') + ':' + chan.node_id.hex(),
            _('This channel will be usable after {} confirmations').format(n)
        ])
        if not funding_tx.is_complete():
            message += '\n\n' + _('Please sign and broadcast the funding transaction')
        self.app.show_info(message)

        if not funding_tx.is_complete():
            self.app.tx_dialog(funding_tx)
예제 #12
0
 def _request_force_close(self, b):
     if not b:
         return
     loop = self.app.wallet.network.asyncio_loop
     coro = asyncio.run_coroutine_threadsafe(
         self.app.wallet.lnworker.request_force_close(self.chan.channel_id),
         loop)
     try:
         coro.result(5)
         self.app.show_info(_('Request sent'))
     except Exception as e:
         self.logger.exception("Could not close channel")
         self.app.show_info(_('Could not close channel: ') +
                            repr(e))  # repr because str(Exception()) == ''
예제 #13
0
 def export_backup(self):
     text = self.app.wallet.lnworker.export_channel_backup(
         self.chan.channel_id)
     # TODO: some messages are duplicated between Kivy and Qt.
     help_text = ' '.join([
         _("Channel backups can be imported in another instance of the same wallet, by scanning this QR code."
           ),
         _("Please note that channel backups cannot be used to restore your channels."
           ),
         _("If you lose your wallet file, the only thing you can do with a backup is to request your channel to be closed, so that your funds will be sent on-chain."
           ),
     ])
     self.app.qr_dialog(_("Channel Backup " + self.chan.short_id_for_GUI()),
                        text,
                        help_text=help_text)
예제 #14
0
 def on_password(self, pw: str):
     #
     if not self.require_password:
         self.success = True
         self.message = _('Please wait...')
         self.dismiss()
         return
     # if setting new generic password, enforce min length
     if self.level > 0:
         if len(pw) < 6:
             self.app.show_error(
                 _('Password is too short (min {} characters)').format(6))
             return
     # don't enforce minimum length on existing
     self.do_check(pw)
예제 #15
0
    def remove_local_tx(self):
        txid = self.tx.txid()
        num_child_txs = len(self.wallet.get_depending_transactions(txid))
        question = _("Are you sure you want to remove this transaction?")
        if num_child_txs > 0:
            question = (_("Are you sure you want to remove this transaction and {} child transactions?")
                        .format(num_child_txs))

        def on_prompt(b):
            if b:
                self.wallet.remove_transaction(txid)
                self.wallet.save_db()
                self.app._trigger_update_wallet()  # FIXME private...
                self.dismiss()
        d = Question(question, on_prompt)
        d.open()
예제 #16
0
 def update_status(self):
     req = self.app.wallet.get_request(self.key)
     self.status = self.app.wallet.get_request_status(self.key)
     self.status_str = req.get_status_str(self.status)
     self.status_color = pr_color[self.status]
     if self.status == PR_UNPAID and self.is_lightning and self.app.wallet.lnworker:
         if self.amount_sat and self.amount_sat > self.app.wallet.lnworker.num_sats_can_receive(
         ):
             self.warning = _('Warning') + ': ' + _(
                 'This amount exceeds the maximum you can currently receive with your channels'
             )
     if self.status == PR_UNPAID and not self.is_lightning:
         address = req.get_address()
         if self.app.wallet.is_used(address):
             self.warning = _('Warning') + ': ' + _(
                 'This address is being reused')
예제 #17
0
 def _do_force_close(self, b):
     if not b:
         return
     loop = self.app.wallet.network.asyncio_loop
     coro = asyncio.run_coroutine_threadsafe(
         self.app.wallet.lnworker.force_close_channel(self.chan.channel_id),
         loop)
     try:
         coro.result(1)
         self.app.show_info(
             _('Channel closed, you may need to wait at least {} blocks, because of CSV delays'
               .format(self.chan.config[REMOTE].to_self_delay)))
     except Exception as e:
         self.logger.exception("Could not force close channel")
         self.app.show_info(_('Could not force close channel: ') +
                            repr(e))  # repr because str(Exception()) == ''
예제 #18
0
 def get_card(self, item: Invoice) -> Dict[str, Any]:
     status = self.app.wallet.get_invoice_status(item)
     status_str = item.get_status_str(status)
     is_lightning = item.type == PR_TYPE_LN
     key = self.app.wallet.get_key_for_outgoing_invoice(item)
     if is_lightning:
         assert isinstance(item, LNInvoice)
         address = item.rhash
         if self.app.wallet.lnworker:
             log = self.app.wallet.lnworker.logs.get(key)
             if status == PR_INFLIGHT and log:
                 status_str += '... (%d)'%len(log)
         is_bip70 = False
     else:
         assert isinstance(item, OnchainInvoice)
         address = item.get_address()
         is_bip70 = bool(item.bip70)
     return {
         'is_lightning': is_lightning,
         'is_bip70': is_bip70,
         'screen': self,
         'status': status,
         'status_str': status_str,
         'key': key,
         'memo': item.message or _('No Description'),
         'address': address,
         'amount': self.app.format_amount_and_units(item.get_amount_sat() or 0),
     }
예제 #19
0
 def _do_pay_onchain(self, invoice: OnchainInvoice) -> None:
     outputs = invoice.outputs
     amount = sum(map(lambda x: x.value, outputs)) if not any(parse_max_spend(x.value) for x in outputs) else '!'
     coins = self.app.wallet.get_spendable_coins(None)
     make_tx = lambda rbf: self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, rbf=rbf)
     on_pay = lambda tx: self.app.protected(_('Send payment?'), self.send_tx, (tx, invoice))
     d = ConfirmTxDialog(self.app, amount=amount, make_tx=make_tx, on_pay=on_pay)
     d.open()
예제 #20
0
 def show_log(self):
     if self.log:
         log_str = _('Payment log:') + '\n\n'
         for payment_attempt_log in self.log:
             route_str, chan_str, message = payment_attempt_log.formatted_tuple(
             )
             log_str += chan_str + '  ---  ' + message + '\n'
         self.app.show_info(log_str)
예제 #21
0
 def send_report(self):
     try:
         loop = self.main_window.network.asyncio_loop
         proxy = self.main_window.network.proxy
         # FIXME network request in GUI thread...
         response = json.loads(BaseCrashReporter.send_report(self, loop, proxy,
                                                             "/crash.json", timeout=10))
     except (ValueError, ClientError) as e:
         self.logger.warning(f"Error sending crash report. exc={e!r}")
         self.show_popup(_('Unable to send report'), _("Please check your network connection."))
     else:
         self.show_popup(_('Report sent'), response["text"])
         location = response["location"]
         if location:
             self.logger.info(f"Crash report sent. location={location!r}")
             self.open_url(location)
     self.dismiss()
예제 #22
0
class PincodeDialog(AbstractPasswordDialog):
    enter_pw_message = _('Enter your PIN')
    enter_new_pw_message = _('Enter new PIN')
    confirm_new_pw_message = _('Confirm new PIN')
    wrong_password_message = _('Wrong PIN')
    allow_disable = True

    def __init__(self, app, **kwargs):
        AbstractPasswordDialog.__init__(self, app, **kwargs)

    def clear_password(self):
        self.ids.kb.password = ''

    def on_password(self, pw: str):
        # PIN codes are exactly 6 chars
        if len(pw) >= 6:
            self.do_check(pw)
예제 #23
0
 def unit_dialog(self, item, dt):
     if self._unit_dialog is None:
         def cb(text):
             self.app._set_bu(text)
             item.bu = self.app.base_unit
         self._unit_dialog = ChoiceDialog(_('Denomination'), base_units_list,
                                          self.app.base_unit, cb, keep_choice_order=True)
     self._unit_dialog.open()
예제 #24
0
 def fx_status(self):
     fx = self.app.fx
     if fx.is_enabled():
         source = fx.exchange.name()
         ccy = fx.get_currency()
         return '%s [%s]' %(ccy, source)
     else:
         return _('None')
예제 #25
0
 def _close(self, choice):
     loop = self.app.wallet.network.asyncio_loop
     if choice == 1:
         coro = self.app.wallet.lnworker.request_force_close(
             self.chan.channel_id)
         msg = _('Request sent')
     else:
         coro = self.app.wallet.lnworker.close_channel(self.chan.channel_id)
         msg = _('Channel closed')
     f = asyncio.run_coroutine_threadsafe(coro, loop)
     try:
         f.result(5)
         self.app.show_info(msg)
     except Exception as e:
         self.logger.exception("Could not close channel")
         self.app.show_info(_('Could not close channel: ') +
                            repr(e))  # repr because str(Exception()) == ''
예제 #26
0
 def coinselect_dialog(self, item, dt):
     if self._coinselect_dialog is None:
         choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
         chooser_name = coinchooser.get_name(self.config)
         def cb(text):
             self.config.set_key('coin_chooser', text)
             item.status = text
         self._coinselect_dialog = ChoiceDialog(_('Coin selection'), choosers, chooser_name, cb)
     self._coinselect_dialog.open()
예제 #27
0
 def language_dialog(self, item, dt):
     if self._language_dialog is None:
         l = self.config.get('language') or ''
         def cb(key):
             self.config.set_key("language", key, True)
             item.lang = self.get_language_name()
             self.app.language = key
         self._language_dialog = ChoiceDialog(_('Language'), languages, l, cb)
     self._language_dialog.open()
예제 #28
0
 def on_address(self, addr):
     req = self.app.wallet.get_request(addr)
     self.status = ''
     if req:
         self.message = req.get('memo', '')
         amount = req.get('amount')
         self.amount = self.app.format_amount_and_units(amount) if amount else ''
         status = req.get('status', PR_UNKNOWN)
         self.status = _('Payment received') if status == PR_PAID else ''
예제 #29
0
 def on_currency(self, ccy):
     b = (ccy != _('None'))
     self.fx.set_enabled(b)
     if b:
         if ccy != self.fx.get_currency():
             self.fx.set_currency(ccy)
         self.app.fiat_unit = ccy
     else:
         self.app.is_fiat = False
     Clock.schedule_once(lambda dt: self.add_exchanges())
예제 #30
0
 def label_dialog(self):
     from .label_dialog import LabelDialog
     key = self.tx.txid()
     text = self.app.wallet.get_label_for_txid(key)
     def callback(text):
         self.app.wallet.set_label(key, text)
         self.update()
         self.app.history_screen.update()
     d = LabelDialog(_('Enter Transaction Label'), text, callback)
     d.open()