mirror of
https://github.com/lnbits/lnbits.git
synced 2025-05-04 00:30:16 +02:00
harden sse connections to backends a little.
This commit is contained in:
parent
7f41d73a84
commit
1d00060419
@ -52,9 +52,10 @@ Using this wallet requires the installation of the `lndgrpc` and `purerpc` Pytho
|
|||||||
- `LNBITS_ENDPOINT`: e.g. https://lnbits.com
|
- `LNBITS_ENDPOINT`: e.g. https://lnbits.com
|
||||||
- `LNBITS_KEY`: lnbitsAdminKey
|
- `LNBITS_KEY`: lnbitsAdminKey
|
||||||
|
|
||||||
|
|
||||||
### LNPay
|
### LNPay
|
||||||
|
|
||||||
|
For the invoice listener to work you have a publicly accessible URL in your LNbits and must set up [LNPay webhooks](https://lnpay.co/webhook/) pointing to `<your LNbits host>/wallet/webhook` with the "Wallet Receive" event and no secret.
|
||||||
|
|
||||||
- `LNBITS_BACKEND_WALLET_CLASS`: **LNPayWallet**
|
- `LNBITS_BACKEND_WALLET_CLASS`: **LNPayWallet**
|
||||||
- `LNPAY_API_ENDPOINT`: https://lnpay.co/v1/
|
- `LNPAY_API_ENDPOINT`: https://lnpay.co/v1/
|
||||||
- `LNPAY_API_KEY`: sak_apiKey
|
- `LNPAY_API_KEY`: sak_apiKey
|
||||||
@ -70,6 +71,8 @@ Using this wallet requires the installation of the `lndgrpc` and `purerpc` Pytho
|
|||||||
|
|
||||||
### OpenNode
|
### OpenNode
|
||||||
|
|
||||||
|
For the invoice to work you must have a publicly accessible URL in your LNbits. No manual webhook setting is necessary.
|
||||||
|
|
||||||
- `LNBITS_BACKEND_WALLET_CLASS`: **OpenNodeWallet**
|
- `LNBITS_BACKEND_WALLET_CLASS`: **OpenNodeWallet**
|
||||||
- `OPENNODE_API_ENDPOINT`: https://api.opennode.com/
|
- `OPENNODE_API_ENDPOINT`: https://api.opennode.com/
|
||||||
- `OPENNODE_KEY`: opennodeAdminApiKey
|
- `OPENNODE_KEY`: opennodeAdminApiKey
|
||||||
|
@ -18,6 +18,45 @@ from typing import Optional, Dict, AsyncGenerator
|
|||||||
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
|
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
|
||||||
|
|
||||||
|
|
||||||
|
def get_ssl_context(cert_path: str):
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||||
|
context.options |= ssl.OP_NO_SSLv2
|
||||||
|
context.options |= ssl.OP_NO_SSLv3
|
||||||
|
context.options |= ssl.OP_NO_TLSv1
|
||||||
|
context.options |= ssl.OP_NO_TLSv1_1
|
||||||
|
context.options |= ssl.OP_NO_COMPRESSION
|
||||||
|
context.set_ciphers(
|
||||||
|
":".join(
|
||||||
|
[
|
||||||
|
"ECDHE+AESGCM",
|
||||||
|
"ECDHE+CHACHA20",
|
||||||
|
"DHE+AESGCM",
|
||||||
|
"DHE+CHACHA20",
|
||||||
|
"ECDH+AESGCM",
|
||||||
|
"DH+AESGCM",
|
||||||
|
"ECDH+AES",
|
||||||
|
"DH+AES",
|
||||||
|
"RSA+AESGCM",
|
||||||
|
"RSA+AES",
|
||||||
|
"!aNULL",
|
||||||
|
"!eNULL",
|
||||||
|
"!MD5",
|
||||||
|
"!DSS",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
context.load_verify_locations(capath=cert_path)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def load_macaroon(macaroon_path: str):
|
||||||
|
with open(macaroon_path, "rb") as f:
|
||||||
|
macaroon_bytes = f.read()
|
||||||
|
return macaroon_bytes.hex()
|
||||||
|
|
||||||
|
|
||||||
def parse_checking_id(checking_id: str) -> bytes:
|
def parse_checking_id(checking_id: str) -> bytes:
|
||||||
return base64.b64decode(
|
return base64.b64decode(
|
||||||
checking_id.replace("_", "/"),
|
checking_id.replace("_", "/"),
|
||||||
@ -147,41 +186,4 @@ class LndWallet(Wallet):
|
|||||||
checking_id = stringify_checking_id(inv.r_hash)
|
checking_id = stringify_checking_id(inv.r_hash)
|
||||||
yield checking_id
|
yield checking_id
|
||||||
|
|
||||||
|
print("lost connection to lnd InvoiceSubscription, please restart lnbits.")
|
||||||
def get_ssl_context(cert_path: str):
|
|
||||||
import ssl
|
|
||||||
|
|
||||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
|
||||||
context.options |= ssl.OP_NO_SSLv2
|
|
||||||
context.options |= ssl.OP_NO_SSLv3
|
|
||||||
context.options |= ssl.OP_NO_TLSv1
|
|
||||||
context.options |= ssl.OP_NO_TLSv1_1
|
|
||||||
context.options |= ssl.OP_NO_COMPRESSION
|
|
||||||
context.set_ciphers(
|
|
||||||
":".join(
|
|
||||||
[
|
|
||||||
"ECDHE+AESGCM",
|
|
||||||
"ECDHE+CHACHA20",
|
|
||||||
"DHE+AESGCM",
|
|
||||||
"DHE+CHACHA20",
|
|
||||||
"ECDH+AESGCM",
|
|
||||||
"DH+AESGCM",
|
|
||||||
"ECDH+AES",
|
|
||||||
"DH+AES",
|
|
||||||
"RSA+AESGCM",
|
|
||||||
"RSA+AES",
|
|
||||||
"!aNULL",
|
|
||||||
"!eNULL",
|
|
||||||
"!MD5",
|
|
||||||
"!DSS",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
context.load_verify_locations(capath=cert_path)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def load_macaroon(macaroon_path: str):
|
|
||||||
with open(macaroon_path, "rb") as f:
|
|
||||||
macaroon_bytes = f.read()
|
|
||||||
return macaroon_bytes.hex()
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import trio # type: ignore
|
||||||
import httpx
|
import httpx
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
@ -120,15 +121,26 @@ class LndRestWallet(Wallet):
|
|||||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||||
url = self.endpoint + "/v1/invoices/subscribe"
|
url = self.endpoint + "/v1/invoices/subscribe"
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=None, headers=self.auth, verify=self.cert) as client:
|
while True:
|
||||||
async with client.stream("GET", url) as r:
|
try:
|
||||||
async for line in r.aiter_lines():
|
async with httpx.AsyncClient(
|
||||||
try:
|
timeout=None,
|
||||||
inv = json.loads(line)["result"]
|
headers=self.auth,
|
||||||
if not inv["settled"]:
|
verify=self.cert,
|
||||||
continue
|
) as client:
|
||||||
except:
|
async with client.stream("GET", url) as r:
|
||||||
continue
|
async for line in r.aiter_lines():
|
||||||
|
try:
|
||||||
|
inv = json.loads(line)["result"]
|
||||||
|
if not inv["settled"]:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
payment_hash = base64.b64decode(inv["r_hash"]).hex()
|
payment_hash = base64.b64decode(inv["r_hash"]).hex()
|
||||||
yield payment_hash
|
yield payment_hash
|
||||||
|
except (OSError, httpx.ReadError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
print("lost connection to lnd invoices stream, retrying in 5 seconds")
|
||||||
|
await trio.sleep(5)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import trio # type: ignore
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
import httpx
|
import httpx
|
||||||
@ -96,10 +97,17 @@ class SparkWallet(Wallet):
|
|||||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||||
url = self.url + "/stream?access-key=" + self.token
|
url = self.url + "/stream?access-key=" + self.token
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=None) as client:
|
while True:
|
||||||
async with client.stream("GET", url) as r:
|
try:
|
||||||
async for line in r.aiter_lines():
|
async with httpx.AsyncClient(timeout=None) as client:
|
||||||
if line.startswith("data:"):
|
async with client.stream("GET", url) as r:
|
||||||
data = json.loads(line[5:])
|
async for line in r.aiter_lines():
|
||||||
if "pay_index" in data and data.get("status") == "paid":
|
if line.startswith("data:"):
|
||||||
yield data["label"]
|
data = json.loads(line[5:])
|
||||||
|
if "pay_index" in data and data.get("status") == "paid":
|
||||||
|
yield data["label"]
|
||||||
|
except (OSError, httpx.ReadError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
print("lost connection to spark /stream, retrying in 5 seconds")
|
||||||
|
await trio.sleep(5)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user