mirror of
https://github.com/lnbits/lnbits.git
synced 2025-05-31 18:20:41 +02:00
Ran black on bleskomat
This commit is contained in:
parent
c86bd74506
commit
20ef9f92a1
@ -6,19 +6,30 @@ from . import db
|
||||
from .models import Bleskomat, BleskomatLnurl
|
||||
from .helpers import generate_bleskomat_lnurl_hash
|
||||
|
||||
|
||||
async def create_bleskomat(
|
||||
*, wallet_id: str, name: str, fiat_currency: str, exchange_rate_provider: str, fee: str
|
||||
) -> Bleskomat:
|
||||
bleskomat_id = uuid4().hex
|
||||
api_key_id = secrets.token_hex(8)
|
||||
api_key_secret = secrets.token_hex(32)
|
||||
api_key_encoding = "hex";
|
||||
api_key_encoding = "hex"
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO bleskomats (id, wallet, api_key_id, api_key_secret, api_key_encoding, name, fiat_currency, exchange_rate_provider, fee)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(bleskomat_id, wallet_id, api_key_id, api_key_secret, api_key_encoding, name, fiat_currency, exchange_rate_provider, fee),
|
||||
(
|
||||
bleskomat_id,
|
||||
wallet_id,
|
||||
api_key_id,
|
||||
api_key_secret,
|
||||
api_key_encoding,
|
||||
name,
|
||||
fiat_currency,
|
||||
exchange_rate_provider,
|
||||
fee,
|
||||
),
|
||||
)
|
||||
bleskomat = await get_bleskomat(bleskomat_id)
|
||||
assert bleskomat, "Newly created bleskomat couldn't be retrieved"
|
||||
@ -65,7 +76,19 @@ async def create_bleskomat_lnurl(
|
||||
INSERT INTO bleskomat_lnurls (id, bleskomat, wallet, hash, tag, params, api_key_id, initial_uses, remaining_uses, created_time, updated_time)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(bleskomat_lnurl_id, bleskomat.id, bleskomat.wallet, hash, tag, params, bleskomat.api_key_id, uses, uses, now, now),
|
||||
(
|
||||
bleskomat_lnurl_id,
|
||||
bleskomat.id,
|
||||
bleskomat.wallet,
|
||||
hash,
|
||||
tag,
|
||||
params,
|
||||
bleskomat.api_key_id,
|
||||
uses,
|
||||
uses,
|
||||
now,
|
||||
now,
|
||||
),
|
||||
)
|
||||
bleskomat_lnurl = await get_bleskomat_lnurl(secret)
|
||||
assert bleskomat_lnurl, "Newly created bleskomat LNURL couldn't be retrieved"
|
||||
|
@ -2,39 +2,41 @@ import httpx
|
||||
import json
|
||||
import os
|
||||
|
||||
fiat_currencies = json.load(open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'fiat_currencies.json'), 'r'))
|
||||
fiat_currencies = json.load(
|
||||
open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "fiat_currencies.json"), "r")
|
||||
)
|
||||
|
||||
exchange_rate_providers = {
|
||||
"bitfinex": {
|
||||
"name": "Bitfinex",
|
||||
"domain": "bitfinex.com",
|
||||
"api_url": "https://api.bitfinex.com/v1/pubticker/{from}{to}",
|
||||
"getter": lambda data, replacements: data["last_price"]
|
||||
"getter": lambda data, replacements: data["last_price"],
|
||||
},
|
||||
"bitstamp": {
|
||||
"name": "Bitstamp",
|
||||
"domain": "bitstamp.net",
|
||||
"api_url": "https://www.bitstamp.net/api/v2/ticker/{from}{to}/",
|
||||
"getter": lambda data, replacements: data["last"]
|
||||
"getter": lambda data, replacements: data["last"],
|
||||
},
|
||||
"coinbase": {
|
||||
"name": "Coinbase",
|
||||
"domain": "coinbase.com",
|
||||
"api_url": "https://api.coinbase.com/v2/exchange-rates?currency={FROM}",
|
||||
"getter": lambda data, replacements: data["data"]["rates"][replacements["TO"]]
|
||||
"getter": lambda data, replacements: data["data"]["rates"][replacements["TO"]],
|
||||
},
|
||||
"coinmate": {
|
||||
"name": "CoinMate",
|
||||
"domain": "coinmate.io",
|
||||
"api_url": "https://coinmate.io/api/ticker?currencyPair={FROM}_{TO}",
|
||||
"getter": lambda data, replacements: data["data"]["last"]
|
||||
"getter": lambda data, replacements: data["data"]["last"],
|
||||
},
|
||||
"kraken": {
|
||||
"name": "Kraken",
|
||||
"domain": "kraken.com",
|
||||
"api_url": "https://api.kraken.com/0/public/Ticker?pair=XBT{TO}",
|
||||
"getter": lambda data, replacements: data["result"]["XXBTZ" + replacements["TO"]]["c"][0]
|
||||
}
|
||||
"getter": lambda data, replacements: data["result"]["XXBTZ" + replacements["TO"]]["c"][0],
|
||||
},
|
||||
}
|
||||
|
||||
exchange_rate_providers_serializable = {}
|
||||
@ -48,12 +50,7 @@ for ref, exchange_rate_provider in exchange_rate_providers.items():
|
||||
|
||||
async def fetch_fiat_exchange_rate(currency: str, provider: str):
|
||||
|
||||
replacements = {
|
||||
"FROM" : "BTC",
|
||||
"from" : "btc",
|
||||
"TO" : currency.upper(),
|
||||
"to" : currency.lower()
|
||||
}
|
||||
replacements = {"FROM": "BTC", "from": "btc", "TO": currency.upper(), "to": currency.lower()}
|
||||
|
||||
url = exchange_rate_providers[provider]["api_url"]
|
||||
for key in replacements.keys():
|
||||
|
@ -21,11 +21,7 @@ def generate_bleskomat_lnurl_signature(payload: str, api_key_secret: str, api_ke
|
||||
key = base64.b64decode(api_key_secret)
|
||||
else:
|
||||
key = bytes(f"{api_key_secret}")
|
||||
return hmac.new(
|
||||
key=key,
|
||||
msg=payload.encode(),
|
||||
digestmod=hashlib.sha256
|
||||
).hexdigest()
|
||||
return hmac.new(key=key, msg=payload.encode(), digestmod=hashlib.sha256).hexdigest()
|
||||
|
||||
|
||||
def generate_bleskomat_lnurl_secret(api_key_id: str, signature: str):
|
||||
@ -58,19 +54,21 @@ class LnurlValidationError(Exception):
|
||||
def prepare_lnurl_params(tag: str, query: Dict[str, str]):
|
||||
params = {}
|
||||
if not is_supported_lnurl_subprotocol(tag):
|
||||
raise LnurlValidationError(f"Unsupported subprotocol: \"{tag}\"")
|
||||
raise LnurlValidationError(f'Unsupported subprotocol: "{tag}"')
|
||||
if tag == "withdrawRequest":
|
||||
params["minWithdrawable"] = float(query["minWithdrawable"])
|
||||
params["maxWithdrawable"] = float(query["maxWithdrawable"])
|
||||
params["defaultDescription"] = query["defaultDescription"]
|
||||
if not params["minWithdrawable"] > 0:
|
||||
raise LnurlValidationError("\"minWithdrawable\" must be greater than zero")
|
||||
raise LnurlValidationError('"minWithdrawable" must be greater than zero')
|
||||
if not params["maxWithdrawable"] >= params["minWithdrawable"]:
|
||||
raise LnurlValidationError("\"maxWithdrawable\" must be greater than or equal to \"minWithdrawable\"")
|
||||
raise LnurlValidationError('"maxWithdrawable" must be greater than or equal to "minWithdrawable"')
|
||||
return params
|
||||
|
||||
|
||||
encode_uri_component_safe_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"
|
||||
|
||||
|
||||
def query_to_signing_payload(query: Dict[str, str]) -> str:
|
||||
# Sort the query by key, then stringify it to create the payload.
|
||||
sorted_keys = sorted(query.keys(), key=str.lower)
|
||||
@ -84,35 +82,17 @@ def query_to_signing_payload(query: Dict[str, str]) -> str:
|
||||
|
||||
|
||||
unshorten_rules = {
|
||||
"query": {
|
||||
"n": "nonce",
|
||||
"s": "signature",
|
||||
"t": "tag"
|
||||
},
|
||||
"tags": {
|
||||
"c": "channelRequest",
|
||||
"l": "login",
|
||||
"p": "payRequest",
|
||||
"w": "withdrawRequest"
|
||||
},
|
||||
"query": {"n": "nonce", "s": "signature", "t": "tag"},
|
||||
"tags": {"c": "channelRequest", "l": "login", "p": "payRequest", "w": "withdrawRequest"},
|
||||
"params": {
|
||||
"channelRequest": {
|
||||
"pl": "localAmt",
|
||||
"pp": "pushAmt"
|
||||
},
|
||||
"channelRequest": {"pl": "localAmt", "pp": "pushAmt"},
|
||||
"login": {},
|
||||
"payRequest": {
|
||||
"pn": "minSendable",
|
||||
"px": "maxSendable",
|
||||
"pm": "metadata"
|
||||
},
|
||||
"withdrawRequest": {
|
||||
"pn": "minWithdrawable",
|
||||
"px": "maxWithdrawable",
|
||||
"pd": "defaultDescription"
|
||||
}
|
||||
}
|
||||
"payRequest": {"pn": "minSendable", "px": "maxSendable", "pm": "metadata"},
|
||||
"withdrawRequest": {"pn": "minWithdrawable", "px": "maxWithdrawable", "pd": "defaultDescription"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]:
|
||||
new_query = {}
|
||||
rules = unshorten_rules
|
||||
@ -121,14 +101,14 @@ def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]:
|
||||
elif "t" in query:
|
||||
tag = query["t"]
|
||||
else:
|
||||
raise LnurlValidationError("Missing required query parameter: \"tag\"")
|
||||
raise LnurlValidationError('Missing required query parameter: "tag"')
|
||||
# Unshorten tag:
|
||||
if tag in rules["tags"]:
|
||||
long_tag = rules["tags"][tag]
|
||||
new_query["tag"] = long_tag
|
||||
tag = long_tag
|
||||
if not tag in rules["params"]:
|
||||
raise LnurlValidationError(f"Unknown tag: \"{tag}\"")
|
||||
raise LnurlValidationError(f'Unknown tag: "{tag}"')
|
||||
for key in query:
|
||||
if key in rules["params"][tag]:
|
||||
short_param_key = key
|
||||
|
@ -47,7 +47,7 @@ async def api_bleskomat_lnurl():
|
||||
# The API key ID, nonce, and tag should be present in the query string.
|
||||
for field in ["id", "nonce", "tag"]:
|
||||
if not field in query:
|
||||
raise LnurlHttpError(f"Failed API key signature check: Missing \"{field}\"", HTTPStatus.BAD_REQUEST)
|
||||
raise LnurlHttpError(f'Failed API key signature check: Missing "{field}"', HTTPStatus.BAD_REQUEST)
|
||||
|
||||
# URL signing scheme is described here:
|
||||
# https://github.com/chill117/lnurl-node#how-to-implement-url-signing-scheme
|
||||
@ -72,8 +72,7 @@ async def api_bleskomat_lnurl():
|
||||
params = prepare_lnurl_params(tag, query)
|
||||
if "f" in query:
|
||||
rate = await fetch_fiat_exchange_rate(
|
||||
currency=query["f"],
|
||||
provider=bleskomat.exchange_rate_provider
|
||||
currency=query["f"], provider=bleskomat.exchange_rate_provider
|
||||
)
|
||||
# Convert fee (%) to decimal:
|
||||
fee = float(bleskomat.fee) / 100
|
||||
@ -88,13 +87,7 @@ async def api_bleskomat_lnurl():
|
||||
raise LnurlHttpError(e.message, HTTPStatus.BAD_REQUEST)
|
||||
# Create a new LNURL using the query parameters provided in the signed URL.
|
||||
params = json.JSONEncoder().encode(params)
|
||||
lnurl = await create_bleskomat_lnurl(
|
||||
bleskomat=bleskomat,
|
||||
secret=secret,
|
||||
tag=tag,
|
||||
params=params,
|
||||
uses=1
|
||||
)
|
||||
lnurl = await create_bleskomat_lnurl(bleskomat=bleskomat, secret=secret, tag=tag, params=params, uses=1)
|
||||
|
||||
# Reply with LNURL response object.
|
||||
return jsonify(lnurl.get_info_response_object(secret)), HTTPStatus.OK
|
||||
|
@ -39,7 +39,7 @@ class BleskomatLnurl(NamedTuple):
|
||||
def get_info_response_object(self, secret: str) -> Dict[str, str]:
|
||||
tag = self.tag
|
||||
params = json.loads(self.params)
|
||||
response = { "tag": tag }
|
||||
response = {"tag": tag}
|
||||
if tag == "withdrawRequest":
|
||||
for key in ["minWithdrawable", "maxWithdrawable", "defaultDescription"]:
|
||||
response[key] = params[key]
|
||||
@ -54,7 +54,7 @@ class BleskomatLnurl(NamedTuple):
|
||||
if tag == "withdrawRequest":
|
||||
for field in ["pr"]:
|
||||
if not field in query:
|
||||
raise LnurlValidationError(f"Missing required parameter: \"{field}\"")
|
||||
raise LnurlValidationError(f'Missing required parameter: "{field}"')
|
||||
# Check the bolt11 invoice(s) provided.
|
||||
pr = query["pr"]
|
||||
if "," in pr:
|
||||
@ -62,13 +62,13 @@ class BleskomatLnurl(NamedTuple):
|
||||
try:
|
||||
invoice = bolt11.decode(pr)
|
||||
except ValueError as e:
|
||||
raise LnurlValidationError("Invalid parameter (\"pr\"): Lightning payment request expected")
|
||||
raise LnurlValidationError('Invalid parameter ("pr"): Lightning payment request expected')
|
||||
if invoice.amount_msat < params["minWithdrawable"]:
|
||||
raise LnurlValidationError("Amount in invoice must be greater than or equal to \"minWithdrawable\"")
|
||||
raise LnurlValidationError('Amount in invoice must be greater than or equal to "minWithdrawable"')
|
||||
if invoice.amount_msat > params["maxWithdrawable"]:
|
||||
raise LnurlValidationError("Amount in invoice must be less than or equal to \"maxWithdrawable\"")
|
||||
raise LnurlValidationError('Amount in invoice must be less than or equal to "maxWithdrawable"')
|
||||
else:
|
||||
raise LnurlValidationError(f"Unknown subprotocol: \"{tag}\"")
|
||||
raise LnurlValidationError(f'Unknown subprotocol: "{tag}"')
|
||||
|
||||
async def execute_action(self, query: Dict[str, str]):
|
||||
self.validate_action(query)
|
||||
@ -105,6 +105,6 @@ class BleskomatLnurl(NamedTuple):
|
||||
WHERE id = ?
|
||||
AND remaining_uses > 0
|
||||
""",
|
||||
(now, self.id)
|
||||
(now, self.id),
|
||||
)
|
||||
return result.rowcount > 0
|
||||
|
@ -7,6 +7,7 @@ from . import bleskomat_ext
|
||||
from .exchange_rates import exchange_rate_providers_serializable, fiat_currencies
|
||||
from .helpers import get_callback_url
|
||||
|
||||
|
||||
@bleskomat_ext.route("/")
|
||||
@validate_uuids(["usr"], required=True)
|
||||
@check_user_exists()
|
||||
@ -14,6 +15,6 @@ async def index():
|
||||
bleskomat_vars = {
|
||||
"callback_url": get_callback_url(),
|
||||
"exchange_rate_providers": exchange_rate_providers_serializable,
|
||||
"fiat_currencies": fiat_currencies
|
||||
"fiat_currencies": fiat_currencies,
|
||||
}
|
||||
return await render_template("bleskomat/index.html", user=g.user, bleskomat_vars=bleskomat_vars)
|
||||
|
@ -58,13 +58,13 @@ async def api_bleskomat_create_or_update(bleskomat_id=None):
|
||||
try:
|
||||
fiat_currency = g.data["fiat_currency"]
|
||||
exchange_rate_provider = g.data["exchange_rate_provider"]
|
||||
rate = await fetch_fiat_exchange_rate(
|
||||
currency=fiat_currency,
|
||||
provider=exchange_rate_provider
|
||||
)
|
||||
rate = await fetch_fiat_exchange_rate(currency=fiat_currency, provider=exchange_rate_provider)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({"message": f"Failed to fetch BTC/{fiat_currency} currency pair from \"{exchange_rate_provider}\""}), HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
return (
|
||||
jsonify({"message": f'Failed to fetch BTC/{fiat_currency} currency pair from "{exchange_rate_provider}"'}),
|
||||
HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
if bleskomat_id:
|
||||
bleskomat = await get_bleskomat(bleskomat_id)
|
||||
|
@ -124,4 +124,5 @@ async def create_hash_check(
|
||||
|
||||
async def get_hash_check(the_hash: str, lnurl_id: str) -> Optional[HashCheck]:
|
||||
row = await db.fetchone("SELECT * FROM hash_check WHERE id = ?", (the_hash,))
|
||||
|
||||
return HashCheck.from_row(row) if row else None
|
Loading…
x
Reference in New Issue
Block a user