set User-Agent when accessing external resources (#2100)

* set User-Agent when accessing external resources

* refactor User-Agent into settings.user_agent
This commit is contained in:
Pavol Rusnak 2023-11-30 13:54:07 +01:00 committed by GitHub
parent 992e3bfb9a
commit 62b0e3fe89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 70 additions and 43 deletions

View file

@ -385,7 +385,8 @@ async def redeem_lnurl_withdraw(
res = {} res = {}
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
lnurl = decode_lnurl(lnurl_request) lnurl = decode_lnurl(lnurl_request)
r = await client.get(str(lnurl)) r = await client.get(str(lnurl))
res = r.json() res = r.json()
@ -419,7 +420,8 @@ async def redeem_lnurl_withdraw(
except Exception: except Exception:
pass pass
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
try: try:
await client.get(res["callback"], params=params) await client.get(res["callback"], params=params)
except Exception: except Exception:
@ -482,7 +484,8 @@ async def perform_lnurlauth(
sig = key.sign_digest_deterministic(k1, sigencode=encode_strict_der) sig = key.sign_digest_deterministic(k1, sigencode=encode_strict_der)
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
assert key.verifying_key, "LNURLauth verifying_key does not exist" assert key.verifying_key, "LNURLauth verifying_key does not exist"
r = await client.get( r = await client.get(
callback, callback,

View file

@ -120,7 +120,8 @@ async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue):
# dispatch balance_notify # dispatch balance_notify
url = await get_balance_notify(payment.wallet_id) url = await get_balance_notify(payment.wallet_id)
if url: if url:
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
try: try:
r = await client.post(url, timeout=4) r = await client.post(url, timeout=4)
await mark_webhook_sent(payment, r.status_code) await mark_webhook_sent(payment, r.status_code)
@ -152,7 +153,8 @@ async def dispatch_webhook(payment: Payment):
if not payment.webhook: if not payment.webhook:
return await mark_webhook_sent(payment, -1) return await mark_webhook_sent(payment, -1)
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
data = payment.dict() data = payment.dict()
try: try:
r = await client.post(payment.webhook, json=data, timeout=40) r = await client.post(payment.webhook, json=data, timeout=40)

View file

@ -297,7 +297,8 @@ async def api_payments_create_invoice(data: CreateInvoice, wallet: Wallet):
if data.lnurl_balance_check is not None: if data.lnurl_balance_check is not None:
await save_balance_check(wallet.id, data.lnurl_balance_check) await save_balance_check(wallet.id, data.lnurl_balance_check)
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
try: try:
r = await client.get( r = await client.get(
data.lnurl_callback, data.lnurl_callback,
@ -412,7 +413,8 @@ async def api_payments_pay_lnurl(
): ):
domain = urlparse(data.callback).netloc domain = urlparse(data.callback).netloc
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
try: try:
r = await client.get( r = await client.get(
data.callback, data.callback,
@ -594,7 +596,8 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
assert lnurlauth_key.verifying_key assert lnurlauth_key.verifying_key
params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex()) params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex())
else: else:
async with httpx.AsyncClient(follow_redirects=True) as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers, follow_redirects=True) as client:
r = await client.get(url, timeout=5) r = await client.get(url, timeout=5)
r.raise_for_status() r.raise_for_status()
if r.is_error: if r.is_error:

View file

@ -179,7 +179,8 @@ class NodeRank(BaseModel):
) )
async def api_get_1ml_stats(node: Node = Depends(require_node)) -> Optional[NodeRank]: async def api_get_1ml_stats(node: Node = Depends(require_node)) -> Optional[NodeRank]:
node_id = await node.get_id() node_id = await node.get_id()
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
r = await client.get(url=f"https://1ml.com/node/{node_id}/json", timeout=15) r = await client.get(url=f"https://1ml.com/node/{node_id}/json", timeout=15)
try: try:
r.raise_for_status() r.raise_for_status()

View file

@ -144,16 +144,11 @@ async def fetch_github_release_config(
async def github_api_get(url: str, error_msg: Optional[str]) -> Any: async def github_api_get(url: str, error_msg: Optional[str]) -> Any:
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
headers = ( if settings.lnbits_ext_github_token:
{"Authorization": "Bearer " + settings.lnbits_ext_github_token} headers["Authorization"] = f"Bearer {settings.lnbits_ext_github_token}"
if settings.lnbits_ext_github_token async with httpx.AsyncClient(headers=headers) as client:
else None resp = await client.get(url)
)
resp = await client.get(
url,
headers=headers,
)
if resp.status_code != 200: if resp.status_code != 200:
logger.warning(f"{error_msg} ({url}): {resp.text}") logger.warning(f"{error_msg} ({url}): {resp.text}")
resp.raise_for_status() resp.raise_for_status()

View file

@ -297,6 +297,7 @@ class EnvSettings(LNbitsSettings):
lnbits_extensions_path: str = Field(default="lnbits") lnbits_extensions_path: str = Field(default="lnbits")
super_user: str = Field(default="") super_user: str = Field(default="")
version: str = Field(default="0.0.0") version: str = Field(default="0.0.0")
user_agent: str = Field(default="")
enable_log_to_file: bool = Field(default=True) enable_log_to_file: bool = Field(default=True)
log_rotation: str = Field(default="100 MB") log_rotation: str = Field(default="100 MB")
log_retention: str = Field(default="3 months") log_retention: str = Field(default="3 months")
@ -432,6 +433,9 @@ settings.lnbits_path = str(path.dirname(path.realpath(__file__)))
settings.version = importlib.metadata.version("lnbits") settings.version = importlib.metadata.version("lnbits")
if not settings.user_agent:
settings.user_agent = f"LNbits/{settings.version}"
# printing environment variable for debugging # printing environment variable for debugging
if not settings.lnbits_admin_ui: if not settings.lnbits_admin_ui:
logger.debug("Environment Settings:") logger.debug("Environment Settings:")

View file

@ -4,6 +4,7 @@ from typing import Callable, NamedTuple
import httpx import httpx
from loguru import logger from loguru import logger
from lnbits.settings import settings
from lnbits.utils.cache import cache from lnbits.utils.cache import cache
currencies = { currencies = {
@ -246,7 +247,8 @@ async def btc_price(currency: str) -> float:
async def fetch_price(provider: Provider): async def fetch_price(provider: Provider):
url = provider.api_url.format(**replacements) url = provider.api_url.format(**replacements)
try: try:
async with httpx.AsyncClient() as client: headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client:
r = await client.get(url, timeout=0.5) r = await client.get(url, timeout=0.5)
r.raise_for_status() r.raise_for_status()
data = r.json() data = r.json()

View file

@ -28,7 +28,7 @@ class AlbyWallet(Wallet):
self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
self.auth = { self.auth = {
"Authorization": "Bearer " + settings.alby_access_token, "Authorization": "Bearer " + settings.alby_access_token,
"User-Agent": f"LNbits/{settings.version}", "User-Agent": settings.user_agent,
} }
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth) self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth)

View file

@ -38,14 +38,15 @@ class CoreLightningRestWallet(Wallet):
self.url = ( self.url = (
f"https://{self.url}" if not self.url.startswith("http") else self.url f"https://{self.url}" if not self.url.startswith("http") else self.url
) )
self.auth = { headers = {
"macaroon": self.macaroon, "macaroon": self.macaroon,
"encodingtype": "hex", "encodingtype": "hex",
"accept": "application/json", "accept": "application/json",
"User-Agent": settings.user_agent,
} }
self.cert = settings.corelightning_rest_cert or False self.cert = settings.corelightning_rest_cert or False
self.client = httpx.AsyncClient(verify=self.cert, headers=self.auth) self.client = httpx.AsyncClient(verify=self.cert, headers=headers)
self.last_pay_index = 0 self.last_pay_index = 0
self.statuses = { self.statuses = {
"paid": True, "paid": True,

View file

@ -40,8 +40,11 @@ class EclairWallet(Wallet):
encodedAuth = base64.b64encode(f":{passw}".encode()) encodedAuth = base64.b64encode(f":{passw}".encode())
auth = str(encodedAuth, "utf-8") auth = str(encodedAuth, "utf-8")
self.auth = {"Authorization": f"Basic {auth}"} self.headers = {
self.client = httpx.AsyncClient(base_url=self.url, headers=self.auth) "Authorization": f"Basic {auth}",
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient(base_url=self.url, headers=self.headers)
async def cleanup(self): async def cleanup(self):
try: try:
@ -214,7 +217,7 @@ class EclairWallet(Wallet):
try: try:
async with connect( async with connect(
self.ws_url, self.ws_url,
extra_headers=[("Authorization", self.auth["Authorization"])], extra_headers=[("Authorization", self.headers["Authorization"])],
) as ws: ) as ws:
while True: while True:
message = await ws.recv() message = await ws.recv()

View file

@ -28,8 +28,8 @@ class LNbitsWallet(Wallet):
) )
if not self.endpoint or not key: if not self.endpoint or not key:
raise Exception("cannot initialize lnbits wallet") raise Exception("cannot initialize lnbits wallet")
self.key = {"X-Api-Key": key} self.headers = {"X-Api-Key": key, "User-Agent": settings.user_agent}
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.key) self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers)
async def cleanup(self): async def cleanup(self):
try: try:
@ -136,7 +136,9 @@ class LNbitsWallet(Wallet):
while True: while True:
try: try:
async with httpx.AsyncClient(timeout=None, headers=self.key) as client: async with httpx.AsyncClient(
timeout=None, headers=self.headers
) as client:
del client.headers[ del client.headers[
"accept-encoding" "accept-encoding"
] # we have to disable compression for SSEs ] # we have to disable compression for SSEs

View file

@ -67,9 +67,12 @@ class LndRestWallet(Wallet):
# even on startup # even on startup
self.cert = cert or True self.cert = cert or True
self.auth = {"Grpc-Metadata-macaroon": self.macaroon} headers = {
"Grpc-Metadata-macaroon": self.macaroon,
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient( self.client = httpx.AsyncClient(
base_url=self.endpoint, headers=self.auth, verify=self.cert base_url=self.endpoint, headers=headers, verify=self.cert
) )
async def cleanup(self): async def cleanup(self):

View file

@ -28,8 +28,11 @@ class LNPayWallet(Wallet):
self.wallet_key = wallet_key self.wallet_key = wallet_key
self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
self.auth = {"X-Api-Key": settings.lnpay_api_key} headers = {
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth) "X-Api-Key": settings.lnpay_api_key,
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=headers)
async def cleanup(self): async def cleanup(self):
try: try:

View file

@ -29,8 +29,11 @@ class LnTipsWallet(Wallet):
if not endpoint or not key: if not endpoint or not key:
raise Exception("cannot initialize lntxbod") raise Exception("cannot initialize lntxbod")
self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
self.auth = {"Authorization": f"Basic {key}"} headers = {
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth) "Authorization": f"Basic {key}",
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=headers)
async def cleanup(self): async def cleanup(self):
try: try:

View file

@ -21,17 +21,20 @@ class OpenNodeWallet(Wallet):
def __init__(self): def __init__(self):
endpoint = settings.opennode_api_endpoint endpoint = settings.opennode_api_endpoint
key = ( self.key = (
settings.opennode_key settings.opennode_key
or settings.opennode_admin_key or settings.opennode_admin_key
or settings.opennode_invoice_key or settings.opennode_invoice_key
) )
if not endpoint or not key: if not endpoint or not self.key:
raise Exception("cannot initialize opennode") raise Exception("cannot initialize opennode")
self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
self.auth = {"Authorization": key} headers = {
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth) "Authorization": self.key,
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=headers)
async def cleanup(self): async def cleanup(self):
try: try:
@ -142,7 +145,7 @@ class OpenNodeWallet(Wallet):
# raise HTTPException(status_code=HTTPStatus.NO_CONTENT) # raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
# charge_id = data["id"] # charge_id = data["id"]
# x = hmac.new(self.auth["Authorization"].encode("ascii"), digestmod="sha256") # x = hmac.new(self.key.encode("ascii"), digestmod="sha256")
# x.update(charge_id.encode("ascii")) # x.update(charge_id.encode("ascii"))
# if x.hexdigest() != data["hashed_order"]: # if x.hexdigest() != data["hashed_order"]:
# logger.error("invalid webhook, not from opennode") # logger.error("invalid webhook, not from opennode")

View file

@ -32,9 +32,8 @@ class SparkWallet(Wallet):
self.url = settings.spark_url.replace("/rpc", "") self.url = settings.spark_url.replace("/rpc", "")
self.token = settings.spark_token self.token = settings.spark_token
assert self.token, "spark wallet token does not exist" assert self.token, "spark wallet token does not exist"
self.client = httpx.AsyncClient( headers = {"X-Access": self.token, "User-Agent": settings.user_agent}
base_url=self.url, headers={"X-Access": self.token} self.client = httpx.AsyncClient(base_url=self.url, headers=headers)
)
async def cleanup(self): async def cleanup(self):
try: try: