diff --git a/nouri/__init__.py b/nouri/__init__.py index 7cc6225..508a29b 100644 --- a/nouri/__init__.py +++ b/nouri/__init__.py @@ -17,6 +17,24 @@ WEEKDAY_NAMES = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Sam WEEKDAY_SHORT_NAMES = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"] +def load_secret_key(data_dir: Path) -> str: + env_secret = os.environ.get("NOURI_SECRET_KEY") + if env_secret: + return env_secret + + secret_path = data_dir / ".secret_key" + if secret_path.exists(): + return secret_path.read_text(encoding="utf-8").strip() + + secret_value = secrets.token_hex(24) + try: + with secret_path.open("x", encoding="utf-8") as handle: + handle.write(secret_value) + except FileExistsError: + return secret_path.read_text(encoding="utf-8").strip() + return secret_value + + def create_app() -> Flask: root_dir = Path(__file__).resolve().parent.parent data_dir = Path(os.environ.get("NOURI_DATA_DIR", root_dir / "data")).resolve() @@ -28,12 +46,16 @@ def create_app() -> Flask: app = Flask(__name__, instance_relative_config=False) app.config.update( - SECRET_KEY=os.environ.get("NOURI_SECRET_KEY", secrets.token_hex(24)), + # Persist the signing key inside the app's data directory so all + # gunicorn workers and future restarts agree on the same sessions. + SECRET_KEY=load_secret_key(data_dir), DATABASE_PATH=str(db_path), DATA_DIR=str(data_dir), UPLOAD_FOLDER=str(upload_dir), MAX_CONTENT_LENGTH=int(os.environ.get("NOURI_MAX_UPLOAD_MB", "5")) * 1024 * 1024, PERMANENT_SESSION_LIFETIME=timedelta(days=30), + SESSION_COOKIE_HTTPONLY=True, + SESSION_COOKIE_SAMESITE="Lax", ) db.init_app(app)