This commit is contained in:
n 2025-07-09 06:47:17 +01:00
parent 7b3771095b
commit 138afd7c8e
2 changed files with 19 additions and 10 deletions

View File

@ -10,5 +10,7 @@ RUN uv pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app COPY ./app /code/app
# If running behind a proxy like Nginx or Traefik add --proxy-headers # If running behind a proxy like Nginx or Traefik add --proxy-headers
# CMD ["uv", "run", "fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"] # CMD ["uv", "run", "fastapi", "run", "app/main.py", "--proxy-headers"]
CMD ["uv", "run", "fastapi", "run", "app/main.py", "--port", "80"] CMD ["uv", "run", "fastapi", "run", "app/main.py"]
EXPOSE 8000

View File

@ -1,13 +1,15 @@
from collections import OrderedDict from collections import OrderedDict
from dotenv import load_dotenv from dotenv import load_dotenv
from fastapi import FastAPI from fastapi import FastAPI, Query, Request, Response, status
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from uuid import uuid4 from uuid import uuid4
from urllib.parse import urlencode from urllib.parse import urlencode
from typing import Union from typing import Annotated, Union
import requests import requests
import os import os
UUIDPattern = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
UUIDQuery = Query(min_length=36, max_length=36, pattern=f"^{UUIDPattern}$")
load_dotenv() load_dotenv()
client_id = os.environ['MONZO_CLIENT_ID'] client_id = os.environ['MONZO_CLIENT_ID']
client_secret = os.environ['MONZO_CLIENT_SECRET'] client_secret = os.environ['MONZO_CLIENT_SECRET']
@ -16,11 +18,11 @@ callback_uri = os.environ['MONZO_CALLBACK_URI']
app = FastAPI() app = FastAPI()
@app.get("/") @app.get("/")
def read_root(): return {"version": "v0.0.4"} def read_root(): return {"version": "v0.0.8"}
@app.get("/redirect", response_class=RedirectResponse) @app.get("/redirect", response_class=RedirectResponse)
def read_redirect(): def read_redirect(res: Response):
state = uuid4() state = uuid4()
# TODO: store state in a cookie to check it later # TODO: store state in a cookie to check it later
query = urlencode(OrderedDict( query = urlencode(OrderedDict(
@ -29,12 +31,17 @@ def read_redirect():
state=state, state=state,
response_type="code", response_type="code",
)) ))
res.set_cookie(key="monzo-api:state", value=state)
return f"https://auth.monzo.com/?{query}" return f"https://auth.monzo.com/?{query}"
@app.get("/callback") @app.get("/callback")
def read_callback(code: str, state: str): def read_callback(code: str, state: Annotated[str, UUIDQuery], req: Request, res: Response):
# TODO: check that the state is a valid uuid stored_state = req.cookies["monzo-api:state"]
if (state != stored_state):
res.status_code = status.HTTP_400_BAD_REQUEST
return { 'error': True, 'data': f"Callback state '{state}' does not match stored state '{stored_state}'." }
# TODO: check the state with the user's cookie # TODO: check the state with the user's cookie
# TODO: check that the code is a valid jwt # TODO: check that the code is a valid jwt
data = { data = {
@ -44,5 +51,5 @@ def read_callback(code: str, state: str):
'redirect_uri': callback_uri, 'redirect_uri': callback_uri,
'code': code, 'code': code,
} }
response = requests.post("https://api.monzo.com/oauth2/token", data=data) token = requests.post("https://api.monzo.com/oauth2/token", data=data)
return response.json() return { 'error': False, 'data': token.json() }