diff --git a/app/api/routes/qr.py b/app/api/routes/qr.py new file mode 100644 index 0000000..00619c3 --- /dev/null +++ b/app/api/routes/qr.py @@ -0,0 +1,22 @@ +import io +import re + +import qrcode +from fastapi import APIRouter, HTTPException, status +from fastapi.responses import Response + +router = APIRouter(tags=["qr"]) + +# PLM P2WPKH addresses: bech32 HRP "plm" + separator + witness program. +_ADDRESS_RE = re.compile(r"^plm1[a-z0-9]{10,90}$") + + +@router.get("/qr/{address}") +async def address_qr(address: str) -> Response: + if not _ADDRESS_RE.match(address): + raise HTTPException(status.HTTP_400_BAD_REQUEST, "invalid address") + + image = qrcode.make(address) + buf = io.BytesIO() + image.save(buf, format="PNG") + return Response(content=buf.getvalue(), media_type="image/png") diff --git a/app/main.py b/app/main.py index 511987a..6a461f2 100644 --- a/app/main.py +++ b/app/main.py @@ -15,6 +15,7 @@ import app.rounds.confirmation # noqa: F401 (registers the "payout" confirmati import app.withdrawals.confirmation # noqa: F401 (registers the "withdrawal" confirmation handler) from app.api.routes.admin import router as admin_router from app.api.routes.bets import router as bets_router +from app.api.routes.qr import router as qr_router from app.api.routes.users import router as users_router from app.api.routes.withdrawals import router as withdrawals_router from app.auth.routes import router as auth_router @@ -65,6 +66,7 @@ app.include_router(users_router) app.include_router(bets_router) app.include_router(withdrawals_router) app.include_router(admin_router) +app.include_router(qr_router) @app.exception_handler(Exception) diff --git a/pyproject.toml b/pyproject.toml index 2fc3b83..1725028 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ dependencies = [ "pyjwt>=2.7", "cryptography>=43.0", "embit>=0.7", + "qrcode[pil]>=7.4", ] [project.optional-dependencies]