URI: 
       tlightning qr codes: more robust parsing - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4057140e6a7d858128b8a70aafdf649922073435
   DIR parent d1c262def078098599220d6ae189a90700ece0c9
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Wed, 20 Nov 2019 03:21:59 +0100
       
       lightning qr codes: more robust parsing
       
       kivy qr code handling did not accept "lightning:" prefix or uppercase
       
       Diffstat:
         M electrum/gui/kivy/main_window.py    |      13 +++++++------
         M electrum/gui/kivy/uix/screens.py    |      14 +++++++-------
         M electrum/gui/qt/paytoedit.py        |      20 +++++++++++---------
         M electrum/util.py                    |       9 +++++++++
       
       4 files changed, 34 insertions(+), 22 deletions(-)
       ---
   DIR diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
       t@@ -11,10 +11,10 @@ from typing import TYPE_CHECKING, Optional
        
        from electrum.storage import WalletStorage, StorageReadWriteError
        from electrum.wallet import Wallet, InternalAddressCorruption
       -from electrum.util import profiler, InvalidPassword, send_exception_to_crash_reporter
        from electrum.plugin import run_hook
       -from electrum.util import format_satoshis, format_satoshis_plain, format_fee_satoshis
       -from electrum.util import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_FAILED, PR_INFLIGHT
       +from electrum.util import (profiler, InvalidPassword, send_exception_to_crash_reporter,
       +                           format_satoshis, format_satoshis_plain, format_fee_satoshis,
       +                           PR_PAID, PR_FAILED, maybe_extract_bolt11_invoice)
        from electrum import blockchain
        from electrum.network import Network, TxBroadcastError, BestEffortRequestFailed
        from .i18n import _
       t@@ -385,7 +385,7 @@ class ElectrumWindow(App):
                    self.send_screen.do_clear()
        
            def on_qr(self, data):
       -        from electrum.bitcoin import base_decode, is_address
       +        from electrum.bitcoin import is_address
                data = data.strip()
                if is_address(data):
                    self.set_URI(data)
       t@@ -393,8 +393,9 @@ class ElectrumWindow(App):
                if data.startswith('bitcoin:'):
                    self.set_URI(data)
                    return
       -        if data.startswith('ln'):
       -            self.set_ln_invoice(data)
       +        bolt11_invoice = maybe_extract_bolt11_invoice(data)
       +        if bolt11_invoice is not None:
       +            self.set_ln_invoice(bolt11_invoice)
                    return
                # try to decode transaction
                from electrum.transaction import tx_from_any
   DIR diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
       t@@ -26,8 +26,9 @@ from electrum.util import profiler, parse_URI, format_time, InvalidPassword, Not
        from electrum.util import PR_TYPE_ONCHAIN, PR_TYPE_LN
        from electrum import bitcoin, constants
        from electrum.transaction import Transaction, tx_from_any, PartialTransaction, PartialTxOutput
       -from electrum.util import send_exception_to_crash_reporter, parse_URI, InvalidBitcoinURI
       -from electrum.util import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED, PR_INFLIGHT, TxMinedInfo, get_request_status, pr_expiration_values
       +from electrum.util import (parse_URI, InvalidBitcoinURI, PR_PAID, PR_UNKNOWN, PR_EXPIRED,
       +                           PR_INFLIGHT, TxMinedInfo, get_request_status, pr_expiration_values,
       +                           maybe_extract_bolt11_invoice)
        from electrum.plugin import run_hook
        from electrum.wallet import InternalAddressCorruption
        from electrum import simple_config
       t@@ -204,6 +205,7 @@ class SendScreen(CScreen):
        
            def set_ln_invoice(self, invoice):
                try:
       +            invoice = str(invoice).lower()
                    lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
                except Exception as e:
                    self.app.show_info(invoice + _(" is not a valid Lightning invoice: ") + repr(e)) # repr because str(Exception()) == ''
       t@@ -282,12 +284,10 @@ class SendScreen(CScreen):
                if tx:
                    self.app.tx_dialog(tx)
                    return
       -        lower = data.lower()
       -        if lower.startswith('lightning:ln'):
       -            lower = lower[10:]
                # try to decode as URI/address
       -        if lower.startswith('ln'):
       -            self.set_ln_invoice(lower)
       +        bolt11_invoice = maybe_extract_bolt11_invoice(data)
       +        if bolt11_invoice is not None:
       +            self.set_ln_invoice(bolt11_invoice)
                else:
                    self.set_URI(data)
        
   DIR diff --git a/electrum/gui/qt/paytoedit.py b/electrum/gui/qt/paytoedit.py
       t@@ -25,12 +25,12 @@
        
        import re
        from decimal import Decimal
       -from typing import NamedTuple, Sequence, Optional, List
       +from typing import NamedTuple, Sequence, Optional, List, TYPE_CHECKING
        
        from PyQt5.QtGui import QFontMetrics
        
        from electrum import bitcoin
       -from electrum.util import bfh
       +from electrum.util import bfh, maybe_extract_bolt11_invoice
        from electrum.transaction import push_script, PartialTxOutput
        from electrum.bitcoin import opcodes
        from electrum.logging import Logger
       t@@ -40,6 +40,10 @@ from .qrtextedit import ScanQRTextEdit
        from .completion_text_edit import CompletionTextEdit
        from . import util
        
       +if TYPE_CHECKING:
       +    from .main_window import ElectrumWindow
       +
       +
        RE_ALIAS = r'(.*?)\s*\<([0-9A-Za-z]{1,})\>'
        
        frozen_style = "QWidget {border:none;}"
       t@@ -54,7 +58,7 @@ class PayToLineError(NamedTuple):
        
        class PayToEdit(CompletionTextEdit, ScanQRTextEdit, Logger):
        
       -    def __init__(self, win):
       +    def __init__(self, win: 'ElectrumWindow'):
                CompletionTextEdit.__init__(self)
                ScanQRTextEdit.__init__(self)
                Logger.__init__(self)
       t@@ -140,16 +144,14 @@ class PayToEdit(CompletionTextEdit, ScanQRTextEdit, Logger):
                    if data.startswith("bitcoin:"):
                        self.win.pay_to_URI(data)
                        return
       -            lower = data.lower()
       -            if lower.startswith("lightning:ln"):
       -                lower = lower[10:]
       -            if lower.startswith("ln"):
       +            bolt11_invoice = maybe_extract_bolt11_invoice(data)
       +            if bolt11_invoice is not None:
                        try:
       -                    self.win.parse_lightning_invoice(lower)
       +                    self.win.parse_lightning_invoice(bolt11_invoice)
                        except LnDecodeException as e:
                            self.errors.append(PayToLineError(idx=0, line_content=data, exc=e))
                        else:
       -                    self.lightning_invoice = lower
       +                    self.lightning_invoice = bolt11_invoice
                        return
                    try:
                        self.payto_scriptpubkey = self.parse_output(data)
   DIR diff --git a/electrum/util.py b/electrum/util.py
       t@@ -889,6 +889,15 @@ def create_bip21_uri(addr, amount_sat: Optional[int], message: Optional[str],
            return str(urllib.parse.urlunparse(p))
        
        
       +def maybe_extract_bolt11_invoice(data: str) -> Optional[str]:
       +    lower = data.lower()
       +    if lower.startswith('lightning:ln'):
       +        lower = lower[10:]
       +    if lower.startswith('ln'):
       +        return lower
       +    return None
       +
       +
        # Python bug (http://bugs.python.org/issue1927) causes raw_input
        # to be redirected improperly between stdin/stderr on Unix systems
        #TODO: py3