util.parse_URI: more granular exceptions
related: #5376 first report in #5376 was generated with these changes; before, the exception was caught and a toast displayed "Not a Bitcoin URI"
This commit is contained in:
@@ -720,18 +720,25 @@ def block_explorer_URL(config: 'SimpleConfig', kind: str, item: str) -> Optional
|
||||
#_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
|
||||
#urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
|
||||
|
||||
def parse_URI(uri: str, on_pr: Callable=None) -> dict:
|
||||
class InvalidBitcoinURI(Exception): pass
|
||||
|
||||
|
||||
def parse_URI(uri: str, on_pr: Callable = None, *, loop=None) -> dict:
|
||||
"""Raises InvalidBitcoinURI on malformed URI."""
|
||||
from . import bitcoin
|
||||
from .bitcoin import COIN
|
||||
|
||||
if not isinstance(uri, str):
|
||||
raise InvalidBitcoinURI(f"expected string, not {repr(uri)}")
|
||||
|
||||
if ':' not in uri:
|
||||
if not bitcoin.is_address(uri):
|
||||
raise Exception("Not a bitcoin address")
|
||||
raise InvalidBitcoinURI("Not a bitcoin address")
|
||||
return {'address': uri}
|
||||
|
||||
u = urllib.parse.urlparse(uri)
|
||||
if u.scheme != 'bitcoin':
|
||||
raise Exception("Not a bitcoin URI")
|
||||
raise InvalidBitcoinURI("Not a bitcoin URI")
|
||||
address = u.path
|
||||
|
||||
# python for android fails to parse query
|
||||
@@ -742,32 +749,44 @@ def parse_URI(uri: str, on_pr: Callable=None) -> dict:
|
||||
pq = urllib.parse.parse_qs(u.query)
|
||||
|
||||
for k, v in pq.items():
|
||||
if len(v)!=1:
|
||||
raise Exception('Duplicate Key', k)
|
||||
if len(v) != 1:
|
||||
raise InvalidBitcoinURI(f'Duplicate Key: {repr(k)}')
|
||||
|
||||
out = {k: v[0] for k, v in pq.items()}
|
||||
if address:
|
||||
if not bitcoin.is_address(address):
|
||||
raise Exception("Invalid bitcoin address:" + address)
|
||||
raise InvalidBitcoinURI(f"Invalid bitcoin address: {address}")
|
||||
out['address'] = address
|
||||
if 'amount' in out:
|
||||
am = out['amount']
|
||||
m = re.match(r'([0-9.]+)X([0-9])', am)
|
||||
if m:
|
||||
k = int(m.group(2)) - 8
|
||||
amount = Decimal(m.group(1)) * pow( Decimal(10) , k)
|
||||
else:
|
||||
amount = Decimal(am) * COIN
|
||||
out['amount'] = int(amount)
|
||||
try:
|
||||
m = re.match(r'([0-9.]+)X([0-9])', am)
|
||||
if m:
|
||||
k = int(m.group(2)) - 8
|
||||
amount = Decimal(m.group(1)) * pow( Decimal(10) , k)
|
||||
else:
|
||||
amount = Decimal(am) * COIN
|
||||
out['amount'] = int(amount)
|
||||
except Exception as e:
|
||||
raise InvalidBitcoinURI(f"failed to parse 'amount' field: {repr(e)}") from e
|
||||
if 'message' in out:
|
||||
out['message'] = out['message']
|
||||
out['memo'] = out['message']
|
||||
if 'time' in out:
|
||||
out['time'] = int(out['time'])
|
||||
try:
|
||||
out['time'] = int(out['time'])
|
||||
except Exception as e:
|
||||
raise InvalidBitcoinURI(f"failed to parse 'time' field: {repr(e)}") from e
|
||||
if 'exp' in out:
|
||||
out['exp'] = int(out['exp'])
|
||||
try:
|
||||
out['exp'] = int(out['exp'])
|
||||
except Exception as e:
|
||||
raise InvalidBitcoinURI(f"failed to parse 'exp' field: {repr(e)}") from e
|
||||
if 'sig' in out:
|
||||
out['sig'] = bh2u(bitcoin.base_decode(out['sig'], None, base=58))
|
||||
try:
|
||||
out['sig'] = bh2u(bitcoin.base_decode(out['sig'], None, base=58))
|
||||
except Exception as e:
|
||||
raise InvalidBitcoinURI(f"failed to parse 'sig' field: {repr(e)}") from e
|
||||
|
||||
r = out.get('r')
|
||||
sig = out.get('sig')
|
||||
@@ -782,7 +801,7 @@ def parse_URI(uri: str, on_pr: Callable=None) -> dict:
|
||||
request = await pr.get_payment_request(r)
|
||||
if on_pr:
|
||||
on_pr(request)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop = loop or asyncio.get_event_loop()
|
||||
asyncio.run_coroutine_threadsafe(get_payment_request(), loop)
|
||||
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user