lightning qr codes: more robust parsing
kivy qr code handling did not accept "lightning:" prefix or uppercase
This commit is contained in:
@@ -11,10 +11,10 @@ from typing import TYPE_CHECKING, Optional
|
|||||||
|
|
||||||
from electrum.storage import WalletStorage, StorageReadWriteError
|
from electrum.storage import WalletStorage, StorageReadWriteError
|
||||||
from electrum.wallet import Wallet, InternalAddressCorruption
|
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.plugin import run_hook
|
||||||
from electrum.util import format_satoshis, format_satoshis_plain, format_fee_satoshis
|
from electrum.util import (profiler, InvalidPassword, send_exception_to_crash_reporter,
|
||||||
from electrum.util import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_FAILED, PR_INFLIGHT
|
format_satoshis, format_satoshis_plain, format_fee_satoshis,
|
||||||
|
PR_PAID, PR_FAILED, maybe_extract_bolt11_invoice)
|
||||||
from electrum import blockchain
|
from electrum import blockchain
|
||||||
from electrum.network import Network, TxBroadcastError, BestEffortRequestFailed
|
from electrum.network import Network, TxBroadcastError, BestEffortRequestFailed
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
@@ -385,7 +385,7 @@ class ElectrumWindow(App):
|
|||||||
self.send_screen.do_clear()
|
self.send_screen.do_clear()
|
||||||
|
|
||||||
def on_qr(self, data):
|
def on_qr(self, data):
|
||||||
from electrum.bitcoin import base_decode, is_address
|
from electrum.bitcoin import is_address
|
||||||
data = data.strip()
|
data = data.strip()
|
||||||
if is_address(data):
|
if is_address(data):
|
||||||
self.set_URI(data)
|
self.set_URI(data)
|
||||||
@@ -393,8 +393,9 @@ class ElectrumWindow(App):
|
|||||||
if data.startswith('bitcoin:'):
|
if data.startswith('bitcoin:'):
|
||||||
self.set_URI(data)
|
self.set_URI(data)
|
||||||
return
|
return
|
||||||
if data.startswith('ln'):
|
bolt11_invoice = maybe_extract_bolt11_invoice(data)
|
||||||
self.set_ln_invoice(data)
|
if bolt11_invoice is not None:
|
||||||
|
self.set_ln_invoice(bolt11_invoice)
|
||||||
return
|
return
|
||||||
# try to decode transaction
|
# try to decode transaction
|
||||||
from electrum.transaction import tx_from_any
|
from electrum.transaction import tx_from_any
|
||||||
|
|||||||
@@ -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.util import PR_TYPE_ONCHAIN, PR_TYPE_LN
|
||||||
from electrum import bitcoin, constants
|
from electrum import bitcoin, constants
|
||||||
from electrum.transaction import Transaction, tx_from_any, PartialTransaction, PartialTxOutput
|
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 (parse_URI, InvalidBitcoinURI, PR_PAID, PR_UNKNOWN, PR_EXPIRED,
|
||||||
from electrum.util import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED, PR_INFLIGHT, TxMinedInfo, get_request_status, pr_expiration_values
|
PR_INFLIGHT, TxMinedInfo, get_request_status, pr_expiration_values,
|
||||||
|
maybe_extract_bolt11_invoice)
|
||||||
from electrum.plugin import run_hook
|
from electrum.plugin import run_hook
|
||||||
from electrum.wallet import InternalAddressCorruption
|
from electrum.wallet import InternalAddressCorruption
|
||||||
from electrum import simple_config
|
from electrum import simple_config
|
||||||
@@ -204,6 +205,7 @@ class SendScreen(CScreen):
|
|||||||
|
|
||||||
def set_ln_invoice(self, invoice):
|
def set_ln_invoice(self, invoice):
|
||||||
try:
|
try:
|
||||||
|
invoice = str(invoice).lower()
|
||||||
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
|
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.show_info(invoice + _(" is not a valid Lightning invoice: ") + repr(e)) # repr because str(Exception()) == ''
|
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:
|
if tx:
|
||||||
self.app.tx_dialog(tx)
|
self.app.tx_dialog(tx)
|
||||||
return
|
return
|
||||||
lower = data.lower()
|
|
||||||
if lower.startswith('lightning:ln'):
|
|
||||||
lower = lower[10:]
|
|
||||||
# try to decode as URI/address
|
# try to decode as URI/address
|
||||||
if lower.startswith('ln'):
|
bolt11_invoice = maybe_extract_bolt11_invoice(data)
|
||||||
self.set_ln_invoice(lower)
|
if bolt11_invoice is not None:
|
||||||
|
self.set_ln_invoice(bolt11_invoice)
|
||||||
else:
|
else:
|
||||||
self.set_URI(data)
|
self.set_URI(data)
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,12 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from decimal import Decimal
|
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 PyQt5.QtGui import QFontMetrics
|
||||||
|
|
||||||
from electrum import bitcoin
|
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.transaction import push_script, PartialTxOutput
|
||||||
from electrum.bitcoin import opcodes
|
from electrum.bitcoin import opcodes
|
||||||
from electrum.logging import Logger
|
from electrum.logging import Logger
|
||||||
@@ -40,6 +40,10 @@ from .qrtextedit import ScanQRTextEdit
|
|||||||
from .completion_text_edit import CompletionTextEdit
|
from .completion_text_edit import CompletionTextEdit
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .main_window import ElectrumWindow
|
||||||
|
|
||||||
|
|
||||||
RE_ALIAS = r'(.*?)\s*\<([0-9A-Za-z]{1,})\>'
|
RE_ALIAS = r'(.*?)\s*\<([0-9A-Za-z]{1,})\>'
|
||||||
|
|
||||||
frozen_style = "QWidget {border:none;}"
|
frozen_style = "QWidget {border:none;}"
|
||||||
@@ -54,7 +58,7 @@ class PayToLineError(NamedTuple):
|
|||||||
|
|
||||||
class PayToEdit(CompletionTextEdit, ScanQRTextEdit, Logger):
|
class PayToEdit(CompletionTextEdit, ScanQRTextEdit, Logger):
|
||||||
|
|
||||||
def __init__(self, win):
|
def __init__(self, win: 'ElectrumWindow'):
|
||||||
CompletionTextEdit.__init__(self)
|
CompletionTextEdit.__init__(self)
|
||||||
ScanQRTextEdit.__init__(self)
|
ScanQRTextEdit.__init__(self)
|
||||||
Logger.__init__(self)
|
Logger.__init__(self)
|
||||||
@@ -140,16 +144,14 @@ class PayToEdit(CompletionTextEdit, ScanQRTextEdit, Logger):
|
|||||||
if data.startswith("bitcoin:"):
|
if data.startswith("bitcoin:"):
|
||||||
self.win.pay_to_URI(data)
|
self.win.pay_to_URI(data)
|
||||||
return
|
return
|
||||||
lower = data.lower()
|
bolt11_invoice = maybe_extract_bolt11_invoice(data)
|
||||||
if lower.startswith("lightning:ln"):
|
if bolt11_invoice is not None:
|
||||||
lower = lower[10:]
|
|
||||||
if lower.startswith("ln"):
|
|
||||||
try:
|
try:
|
||||||
self.win.parse_lightning_invoice(lower)
|
self.win.parse_lightning_invoice(bolt11_invoice)
|
||||||
except LnDecodeException as e:
|
except LnDecodeException as e:
|
||||||
self.errors.append(PayToLineError(idx=0, line_content=data, exc=e))
|
self.errors.append(PayToLineError(idx=0, line_content=data, exc=e))
|
||||||
else:
|
else:
|
||||||
self.lightning_invoice = lower
|
self.lightning_invoice = bolt11_invoice
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
self.payto_scriptpubkey = self.parse_output(data)
|
self.payto_scriptpubkey = self.parse_output(data)
|
||||||
|
|||||||
@@ -889,6 +889,15 @@ def create_bip21_uri(addr, amount_sat: Optional[int], message: Optional[str],
|
|||||||
return str(urllib.parse.urlunparse(p))
|
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
|
# Python bug (http://bugs.python.org/issue1927) causes raw_input
|
||||||
# to be redirected improperly between stdin/stderr on Unix systems
|
# to be redirected improperly between stdin/stderr on Unix systems
|
||||||
#TODO: py3
|
#TODO: py3
|
||||||
|
|||||||
Reference in New Issue
Block a user