electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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:
Melectrum/gui/kivy/main_window.py | 13+++++++------
Melectrum/gui/kivy/uix/screens.py | 14+++++++-------
Melectrum/gui/qt/paytoedit.py | 20+++++++++++---------
Melectrum/util.py | 9+++++++++
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