From 91eaef7f93683fc807263a2c81d3384b0e9e7984 Mon Sep 17 00:00:00 2001 From: Finn Stutzenstein Date: Wed, 21 Oct 2026 19:24:37 +0000 Subject: [PATCH] Pass only the return parameter to form actions Five templates built their form action with url_for(..., **request.args), so every query parameter ended up in the action. This included Flask's special parameters (?_external=1 gave an absolute http:// action in production) and the route parameters (?user_id=... or ?alias_id=... caused a TypeError and HTTP 500). The only parameter needed is return=detail, which sends the user back to the detail page after the POST. ReturnToMixin reads it, passes on only the known value and puts it into the template context as return_to. BackToUsersMixin and BackToAliasesMixin build on it. Co-Authored-By: Claude Opus 5.5 --- max/routes/base_alias_views.py | 6 ++++-- max/routes/base_user_views.py | 6 ++++-- max/routes/return_to_mixin.py | 17 +++++++++++++++++ max/templates/alias/delete.html | 2 +- max/templates/alias/edit-note.html | 2 +- max/templates/user/change-password.html | 2 +- max/templates/user/delete.html | 2 +- max/templates/user/edit-note.html | 2 +- 8 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 max/routes/return_to_mixin.py diff --git a/max/routes/base_alias_views.py b/max/routes/base_alias_views.py index e86b36a..62cb1ec 100644 --- a/max/routes/base_alias_views.py +++ b/max/routes/base_alias_views.py @@ -4,6 +4,8 @@ from max.db import get_alias_with_user_by_id from max.exceptions import NotFound from max.views import BaseTemplateGetView +from .return_to_mixin import RETURN_DETAIL, ReturnToMixin + class FetchAliasMixin: def before_handler(self): @@ -21,9 +23,9 @@ class FetchAliasTemplateGetView(FetchAliasMixin, BaseTemplateGetView): return context -class BackToAliasesMixin: +class BackToAliasesMixin(ReturnToMixin): def get_back_text_and_url(self): - if self.request.args.get("return") == "detail": + if self.get_return_to() == RETURN_DETAIL: return self.user.email, url_for("alias-detail", alias_id=self.alias.id) else: return self.user.email, url_for("user-detail", user_id=self.user.id) diff --git a/max/routes/base_user_views.py b/max/routes/base_user_views.py index da32939..04b8879 100644 --- a/max/routes/base_user_views.py +++ b/max/routes/base_user_views.py @@ -5,6 +5,8 @@ from max.exceptions import NotFound from max.translations import t from max.views import BaseTemplateGetView +from .return_to_mixin import RETURN_DETAIL, ReturnToMixin + class FetchUserMixin: def before_handler(self): @@ -20,9 +22,9 @@ class FetchUserTemplateGetView(FetchUserMixin, BaseTemplateGetView): return context -class BackToUsersMixin: +class BackToUsersMixin(ReturnToMixin): def get_back_text_and_url(self): - if self.request.args.get("return") == "detail": + if self.get_return_to() == RETURN_DETAIL: return self.user.email, url_for("user-detail", user_id=self.user.id) else: return t("User list"), url_for("user-list") diff --git a/max/routes/return_to_mixin.py b/max/routes/return_to_mixin.py new file mode 100644 index 0000000..2d9c8fa --- /dev/null +++ b/max/routes/return_to_mixin.py @@ -0,0 +1,17 @@ +RETURN_DETAIL = "detail" + + +class ReturnToMixin: + """ + Reads the `return` query parameter, which tells where to go back to + """ + + def get_return_to(self): + if self.request.args.get("return") == RETURN_DETAIL: + return RETURN_DETAIL + return None + + def get_context(self): + context = super().get_context() + context["return_to"] = self.get_return_to() + return context diff --git a/max/templates/alias/delete.html b/max/templates/alias/delete.html index 4e47de5..ba6fb74 100644 --- a/max/templates/alias/delete.html +++ b/max/templates/alias/delete.html @@ -4,7 +4,7 @@ {% include "alerts.html" %} -
+ {{ t("Cancel") }} {% include "csrf.html" %} diff --git a/max/templates/alias/edit-note.html b/max/templates/alias/edit-note.html index 36b5dab..36f03af 100644 --- a/max/templates/alias/edit-note.html +++ b/max/templates/alias/edit-note.html @@ -4,7 +4,7 @@ {% include "alerts.html" %} - + diff --git a/max/templates/user/change-password.html b/max/templates/user/change-password.html index a6a7615..40e70ee 100644 --- a/max/templates/user/change-password.html +++ b/max/templates/user/change-password.html @@ -4,7 +4,7 @@ {% include "alerts.html" %} - +
diff --git a/max/templates/user/delete.html b/max/templates/user/delete.html index f10df2d..ffa5c3c 100644 --- a/max/templates/user/delete.html +++ b/max/templates/user/delete.html @@ -4,7 +4,7 @@ {% include "alerts.html" %} - + {{ t("Cancel") }} {% include "csrf.html" %} diff --git a/max/templates/user/edit-note.html b/max/templates/user/edit-note.html index 065ca9f..69b0760 100644 --- a/max/templates/user/edit-note.html +++ b/max/templates/user/edit-note.html @@ -4,7 +4,7 @@ {% include "alerts.html" %} - +