From a1cdc45f1affbae747fb3e15ce07a6a1d4b85eff Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:39:11 -0800 Subject: [PATCH] one-time code --- src/paperless_migration/settings.py | 15 +++++++++ .../templates/account/login.html | 6 +++- src/paperless_migration/views.py | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/paperless_migration/settings.py b/src/paperless_migration/settings.py index 2478a09d9..dec940dc1 100644 --- a/src/paperless_migration/settings.py +++ b/src/paperless_migration/settings.py @@ -2,7 +2,9 @@ from __future__ import annotations +import logging import os +import secrets from pathlib import Path from typing import Any @@ -196,3 +198,16 @@ MIGRATION_TRANSFORMED_PATH = __get_path( "PAPERLESS_MIGRATION_TRANSFORMED_PATH", EXPORT_DIR / "manifest.v3.json", ) + +# One-time access code required for migration logins; stable across autoreload +_code = os.getenv("PAPERLESS_MIGRATION_ACCESS_CODE") +if not _code: + _code = secrets.token_urlsafe(12) + os.environ["PAPERLESS_MIGRATION_ACCESS_CODE"] = _code +MIGRATION_ACCESS_CODE = _code +if os.environ.get("PAPERLESS_MIGRATION_CODE_LOGGED") != "1": + logging.getLogger(__name__).warning( + "Migration one-time access code: %s", + MIGRATION_ACCESS_CODE, + ) + os.environ["PAPERLESS_MIGRATION_CODE_LOGGED"] = "1" diff --git a/src/paperless_migration/templates/account/login.html b/src/paperless_migration/templates/account/login.html index 283588bb2..3a25cd684 100644 --- a/src/paperless_migration/templates/account/login.html +++ b/src/paperless_migration/templates/account/login.html @@ -48,10 +48,14 @@ -
+
+
+ + +
diff --git a/src/paperless_migration/views.py b/src/paperless_migration/views.py index 000822e5f..3a1cf96e0 100644 --- a/src/paperless_migration/views.py +++ b/src/paperless_migration/views.py @@ -1,6 +1,8 @@ from pathlib import Path from django.contrib import messages +from django.contrib.auth import authenticate +from django.contrib.auth import login from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from django.shortcuts import redirect @@ -13,6 +15,8 @@ from paperless_migration import settings @login_required @require_http_methods(["GET", "POST"]) def migration_home(request): + if not request.session.get("migration_code_ok"): + return HttpResponseForbidden("Access code required") if not request.user.is_superuser: return HttpResponseForbidden("Superuser access required") @@ -44,3 +48,30 @@ def migration_home(request): "transformed_exists": transformed_path.exists(), } return render(request, "paperless_migration/migration_home.html", context) + + +@require_http_methods(["GET", "POST"]) +def migration_login(request): + if request.method == "POST": + username = request.POST.get("login", "") + password = request.POST.get("password", "") + code = request.POST.get("code", "") + + if not code or code != settings.MIGRATION_ACCESS_CODE: + messages.error(request, "One-time code is required.") + return redirect("account_login") + + user = authenticate(request, username=username, password=password) + if user is None: + messages.error(request, "Invalid username or password.") + return redirect("account_login") + + if not user.is_superuser: + messages.error(request, "Superuser access required.") + return redirect("account_login") + + login(request, user) + request.session["migration_code_ok"] = True + return redirect(settings.LOGIN_REDIRECT_URL) + + return render(request, "account/login.html")