from datetime import datetime, timedelta
from flask import current_app, session
from flask_login import (
COOKIE_DURATION,
COOKIE_HTTPONLY,
COOKIE_NAME,
COOKIE_SECURE,
LoginManager,
user_loaded_from_cookie,
)
from .utils import decode_cookie, encode_cookie
COOKIE_SAMESITE = None
DEFAULT_REMEMBER_COOKIE_PASETO_VERSION = 4
[docs]
class PasetoLoginManager(LoginManager):
[docs]
def init_app(self, app, add_context_processor=True):
super().init_app(app, add_context_processor)
self.paseto_version = app.config.get("REMEMBER_COOKIE_PASETO_VERSION", DEFAULT_REMEMBER_COOKIE_PASETO_VERSION)
if not isinstance(self.paseto_version, int):
raise TypeError("REMEMBER_COOKIE_PASETO_VERSION must be int")
if self.paseto_version not in [1, 2, 3, 4]:
raise ValueError("REMEMBER_COOKIE_PASETO_VERSION must be 1, 2, 3 or 4")
self._remember_cookie_key = app.config.get("REMEMBER_COOKIE_PASETO_KEY", None)
if not isinstance(self._remember_cookie_key, (type(None), str)):
raise TypeError("REMEMBER_COOKIE_PASETO_KEY must be str")
def _set_cookie(self, response):
# cookie settings
config = current_app.config
cookie_name = config.get("REMEMBER_COOKIE_NAME", COOKIE_NAME)
domain = config.get("REMEMBER_COOKIE_DOMAIN")
path = config.get("REMEMBER_COOKIE_PATH", "/")
secure = config.get("REMEMBER_COOKIE_SECURE", COOKIE_SECURE)
httponly = config.get("REMEMBER_COOKIE_HTTPONLY", COOKIE_HTTPONLY)
samesite = config.get("REMEMBER_COOKIE_SAMESITE", COOKIE_SAMESITE)
if "_remember_seconds" in session:
duration = timedelta(seconds=session["_remember_seconds"])
else:
duration = config.get("REMEMBER_COOKIE_DURATION", COOKIE_DURATION)
# prepare data
data = encode_cookie(str(session["_user_id"]), self._remember_cookie_key)
if isinstance(duration, int):
duration = timedelta(seconds=duration)
try:
expires = datetime.utcnow() + duration
except TypeError as err:
raise TypeError("REMEMBER_COOKIE_DURATION must be datetime.timedelta") from err
# actually set it
response.set_cookie(
cookie_name,
value=data,
expires=expires,
domain=domain,
path=path,
secure=secure,
httponly=httponly,
samesite=samesite,
)
return
def _load_user_from_remember_cookie(self, cookie):
user_id = decode_cookie(cookie, self._remember_cookie_key)
if user_id is None:
return None
session["_user_id"] = user_id
session["_fresh"] = False
user = None
if self._user_callback:
user = self._user_callback(user_id)
if user is not None:
app = current_app._get_current_object()
user_loaded_from_cookie.send(app, user=user)
return user