mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-11-06 12:06:54 -05:00
fix: Enabled Using Mealie In iframe If Served Over HTTPS (#6128)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import Literal
|
||||||
|
|
||||||
from authlib.integrations.starlette_client import OAuth
|
from authlib.integrations.starlette_client import OAuth
|
||||||
from fastapi import APIRouter, Depends, Request, Response, status
|
from fastapi import APIRouter, Depends, Request, Response, status
|
||||||
from fastapi.exceptions import HTTPException
|
from fastapi.exceptions import HTTPException
|
||||||
@@ -52,7 +54,9 @@ class MealieAuthToken(BaseModel):
|
|||||||
token_type: str = "bearer"
|
token_type: str = "bearer"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_cookie(cls, response: Response, token: str, expires_in: int | float | None = None):
|
def set_cookie(
|
||||||
|
cls, response: Response, token: str, *, expires_in: int | float | None = None, samesite: str | None = None
|
||||||
|
):
|
||||||
expires_in = int(expires_in) if expires_in else None
|
expires_in = int(expires_in) if expires_in else None
|
||||||
|
|
||||||
# httponly=False to allow JS access for frontend
|
# httponly=False to allow JS access for frontend
|
||||||
@@ -62,6 +66,7 @@ class MealieAuthToken(BaseModel):
|
|||||||
httponly=False,
|
httponly=False,
|
||||||
max_age=expires_in,
|
max_age=expires_in,
|
||||||
secure=settings.PRODUCTION,
|
secure=settings.PRODUCTION,
|
||||||
|
samesite=samesite,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -69,6 +74,22 @@ class MealieAuthToken(BaseModel):
|
|||||||
return cls(access_token=token, token_type=token_type).model_dump()
|
return cls(access_token=token, token_type=token_type).model_dump()
|
||||||
|
|
||||||
|
|
||||||
|
def get_samesite(request: Request) -> Literal["lax", "none"]:
|
||||||
|
"""
|
||||||
|
Determine the appropriate samesite attribute for cookies.
|
||||||
|
|
||||||
|
`samesite="none"` is required for iframe support (i.e. embedding Mealie in another site)
|
||||||
|
but only works over HTTPS. If `samesite="none"` is set over HTTP, most browsers will reject the cookie.
|
||||||
|
|
||||||
|
`samesite="lax"` is the default, which works regardless of HTTP or HTTPS,
|
||||||
|
but does not support hosting in iframes.
|
||||||
|
"""
|
||||||
|
if request.url.scheme == "https" and settings.PRODUCTION:
|
||||||
|
return "none"
|
||||||
|
else:
|
||||||
|
return "lax"
|
||||||
|
|
||||||
|
|
||||||
@public_router.post("/token")
|
@public_router.post("/token")
|
||||||
def get_token(
|
def get_token(
|
||||||
request: Request,
|
request: Request,
|
||||||
@@ -100,7 +121,12 @@ def get_token(
|
|||||||
access_token, duration = auth
|
access_token, duration = auth
|
||||||
expires_in = duration.total_seconds() if duration else None
|
expires_in = duration.total_seconds() if duration else None
|
||||||
|
|
||||||
MealieAuthToken.set_cookie(response, access_token, expires_in)
|
MealieAuthToken.set_cookie(
|
||||||
|
response,
|
||||||
|
access_token,
|
||||||
|
expires_in=expires_in,
|
||||||
|
samesite=get_samesite(request),
|
||||||
|
)
|
||||||
return MealieAuthToken.respond(access_token)
|
return MealieAuthToken.respond(access_token)
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +179,12 @@ async def oauth_callback(request: Request, response: Response, session: Session
|
|||||||
access_token, duration = auth
|
access_token, duration = auth
|
||||||
expires_in = duration.total_seconds() if duration else None
|
expires_in = duration.total_seconds() if duration else None
|
||||||
|
|
||||||
MealieAuthToken.set_cookie(response, access_token, expires_in)
|
MealieAuthToken.set_cookie(
|
||||||
|
response,
|
||||||
|
access_token,
|
||||||
|
expires_in=expires_in,
|
||||||
|
samesite=get_samesite(request),
|
||||||
|
)
|
||||||
return MealieAuthToken.respond(access_token)
|
return MealieAuthToken.respond(access_token)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user