Files
nutshell/cashu/mint/app.py
callebtc a0ef44dba0 Blind authentication (#675)
* auth server

* cleaning up

* auth ledger class

* class variables -> instance variables

* annotations

* add models and api route

* custom amount and api prefix

* add auth db

* blind auth token working

* jwt working

* clean up

* JWT works

* using openid connect server

* use oauth server with password flow

* new realm

* add keycloak docker

* hopefully not garbage

* auth works

* auth kinda working

* fix cli

* auth works for send and receive

* pass auth_db to Wallet

* auth in info

* refactor

* fix supported

* cache mint info

* fix settings and endpoints

* add description to .env.example

* track changes for openid connect client

* store mint in db

* store credentials

* clean up v1_api.py

* load mint info into auth wallet

* fix first login

* authenticate if refresh token fails

* clear auth also middleware

* use regex

* add cli command

* pw works

* persist keyset amounts

* add errors.py

* do not start auth server if disabled in config

* upadte poetry

* disvoery url

* fix test

* support device code flow

* adopt latest spec changes

* fix code flow

* mint max bat dynamic

* mypy ignore

* fix test

* do not serialize amount in authproof

* all auth flows working

* fix tests

* submodule

* refactor

* test

* dont sleep

* test

* add wallet auth tests

* test differently

* test only keycloak for now

* fix creds

* daemon

* fix test

* install everything

* install jinja

* delete wallet for every test

* auth: use global rate limiter

* test auth rate limit

* keycloak hostname

* move keycloak test data

* reactivate all tests

* add readme

* load proofs

* remove unused code

* remove unused code

* implement change suggestions by ok300

* add error codes

* test errors
2025-01-29 22:48:51 -06:00

118 lines
3.5 KiB
Python

import asyncio
import sys
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from traceback import print_exception
from fastapi import FastAPI, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from loguru import logger
from starlette.requests import Request
from ..core.errors import CashuError
from ..core.logging import configure_logger
from ..core.settings import settings
from .auth.router import auth_router
from .router import redis, router
from .router_deprecated import router_deprecated
from .startup import shutdown_mint, start_auth, start_mint
if settings.debug_profiling:
pass
if settings.mint_rate_limit:
pass
from .middleware import add_middlewares, request_validation_exception_handler
@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
await start_mint()
if settings.mint_require_auth:
await start_auth()
try:
yield
except asyncio.CancelledError:
# Handle the cancellation gracefully
logger.info("Shutdown process interrupted by CancelledError")
finally:
try:
await redis.disconnect()
await shutdown_mint()
except asyncio.CancelledError:
logger.info("CancelledError during shutdown, shutting down forcefully")
def create_app(config_object="core.settings") -> FastAPI:
configure_logger()
app = FastAPI(
title="Nutshell Mint",
description="Ecash mint based on the Cashu protocol.",
version=settings.version,
license_info={
"name": "MIT License",
"url": "https://raw.githubusercontent.com/cashubtc/cashu/main/LICENSE",
},
lifespan=lifespan,
)
return app
app = create_app()
# Add middlewares
add_middlewares(app)
@app.middleware("http")
async def catch_exceptions(request: Request, call_next):
CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Credentials": "true",
}
try:
return await call_next(request)
except Exception as e:
try:
err_message = str(e)
except Exception:
err_message = e.args[0] if e.args else "Unknown error"
if isinstance(e, CashuError) or isinstance(e.args[0], CashuError):
logger.error(f"CashuError: {err_message}")
code = e.code if isinstance(e, CashuError) else e.args[0].code
# return with cors headers
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": err_message, "code": code},
headers=CORS_HEADERS,
)
logger.error(f"Exception: {err_message}")
if settings.debug:
print_exception(*sys.exc_info())
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": err_message, "code": 0},
headers=CORS_HEADERS,
)
# Add exception handlers
app.add_exception_handler(RequestValidationError, request_validation_exception_handler) # type: ignore
# Add routers
if settings.debug_mint_only_deprecated:
app.include_router(router=router_deprecated, tags=["Deprecated"], deprecated=True)
else:
app.include_router(router=router, tags=["Mint"])
app.include_router(router=router_deprecated, tags=["Deprecated"], deprecated=True)
if settings.mint_require_auth:
app.include_router(auth_router, tags=["Auth"])