mirror of
https://github.com/lnbits/lnbits.git
synced 2025-07-12 22:12:41 +02:00
feat: add generic lnurl error response handler (#2638)
* feat: add generic lnurl error response handler this is used multiple times in extensions to safeguard `views_lnurl.py` endpoint to not return a wrong lnurl error response. you use it by just setting following on your lnurl router/view ``` withdraw_ext_lnurl = APIRouter(prefix="/api/v1/lnurl") withdraw_ext_lnurl.route_class = LNURLErrorResponseHandler ```
This commit is contained in:
@ -25,6 +25,7 @@ from lnbits.decorators import (
|
|||||||
check_user_extension_access,
|
check_user_extension_access,
|
||||||
require_admin_key,
|
require_admin_key,
|
||||||
)
|
)
|
||||||
|
from lnbits.exceptions import InvoiceError, PaymentError
|
||||||
from lnbits.helpers import url_for
|
from lnbits.helpers import url_for
|
||||||
from lnbits.lnurl import LnurlErrorResponse
|
from lnbits.lnurl import LnurlErrorResponse
|
||||||
from lnbits.lnurl import decode as decode_lnurl
|
from lnbits.lnurl import decode as decode_lnurl
|
||||||
@ -70,18 +71,6 @@ from .helpers import to_valid_user_id
|
|||||||
from .models import BalanceDelta, Payment, PaymentState, User, UserConfig, Wallet
|
from .models import BalanceDelta, Payment, PaymentState, User, UserConfig, Wallet
|
||||||
|
|
||||||
|
|
||||||
class PaymentError(Exception):
|
|
||||||
def __init__(self, message: str, status: str = "pending"):
|
|
||||||
self.message = message
|
|
||||||
self.status = status
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceError(Exception):
|
|
||||||
def __init__(self, message: str, status: str = "pending"):
|
|
||||||
self.message = message
|
|
||||||
self.status = status
|
|
||||||
|
|
||||||
|
|
||||||
async def calculate_fiat_amounts(
|
async def calculate_fiat_amounts(
|
||||||
amount: float,
|
amount: float,
|
||||||
wallet_id: str,
|
wallet_id: str,
|
||||||
|
@ -8,11 +8,21 @@ from fastapi.exceptions import RequestValidationError
|
|||||||
from fastapi.responses import JSONResponse, RedirectResponse, Response
|
from fastapi.responses import JSONResponse, RedirectResponse, Response
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from lnbits.core.services import InvoiceError, PaymentError
|
|
||||||
|
|
||||||
from .helpers import template_renderer
|
from .helpers import template_renderer
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentError(Exception):
|
||||||
|
def __init__(self, message: str, status: str = "pending"):
|
||||||
|
self.message = message
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceError(Exception):
|
||||||
|
def __init__(self, message: str, status: str = "pending"):
|
||||||
|
self.message = message
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
|
||||||
def register_exception_handlers(app: FastAPI):
|
def register_exception_handlers(app: FastAPI):
|
||||||
register_exception_handler(app)
|
register_exception_handler(app)
|
||||||
register_request_validation_exception_handler(app)
|
register_request_validation_exception_handler(app)
|
||||||
|
@ -1 +1,65 @@
|
|||||||
from lnurl import LnurlErrorResponse, decode, encode, handle # noqa: F401
|
from typing import Callable
|
||||||
|
|
||||||
|
from fastapi import HTTPException, Request, Response
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi.routing import APIRoute
|
||||||
|
from lnurl import LnurlErrorResponse, decode, encode, handle
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from lnbits.exceptions import InvoiceError, PaymentError
|
||||||
|
|
||||||
|
|
||||||
|
class LnurlErrorResponseHandler(APIRoute):
|
||||||
|
"""
|
||||||
|
Custom APIRoute class to handle LNURL errors.
|
||||||
|
LNURL errors always return with status 200 and
|
||||||
|
a JSON response with `status="ERROR"` and a `reason` key.
|
||||||
|
Helps to catch HTTPException and return a valid lnurl error response
|
||||||
|
|
||||||
|
Example:
|
||||||
|
withdraw_lnurl_router = APIRouter(prefix="/api/v1/lnurl")
|
||||||
|
withdraw_lnurl_router.route_class = LnurlErrorResponseHandler
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_route_handler(self) -> Callable:
|
||||||
|
original_route_handler = super().get_route_handler()
|
||||||
|
|
||||||
|
async def lnurl_route_handler(request: Request) -> Response:
|
||||||
|
try:
|
||||||
|
response = await original_route_handler(request)
|
||||||
|
return response
|
||||||
|
except (InvoiceError, PaymentError) as exc:
|
||||||
|
logger.debug(f"Wallet Error: {exc}")
|
||||||
|
response = JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={"status": "ERROR", "reason": f"{exc.message}"},
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
except HTTPException as exc:
|
||||||
|
logger.debug(f"HTTPException: {exc}")
|
||||||
|
response = JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={"status": "ERROR", "reason": f"{exc.detail}"},
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error("Unknown Error:", exc)
|
||||||
|
response = JSONResponse(
|
||||||
|
status_code=200,
|
||||||
|
content={
|
||||||
|
"status": "ERROR",
|
||||||
|
"reason": f"UNKNOWN ERROR: {exc!s}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
|
||||||
|
return lnurl_route_handler
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"decode",
|
||||||
|
"encode",
|
||||||
|
"handle",
|
||||||
|
"LnurlErrorResponse",
|
||||||
|
"LnurlErrorResponseHandler",
|
||||||
|
]
|
||||||
|
Reference in New Issue
Block a user