commit 4057140e6a7d858128b8a70aafdf649922073435
parent d1c262def078098599220d6ae189a90700ece0c9
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:
4 files changed, 34 insertions(+), 22 deletions(-)
diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
@@ -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 _
@@ -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)
@@ -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
diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
@@ -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
@@ -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()) == ''
@@ -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)
diff --git a/electrum/gui/qt/paytoedit.py b/electrum/gui/qt/paytoedit.py
@@ -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
@@ -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;}"
@@ -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)
@@ -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)
diff --git a/electrum/util.py b/electrum/util.py
@@ -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