From 04ab05f556daf6e60bf36ae312ec7b0c3aaa1ba6 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 2 Jun 2026 11:39:04 +0200 Subject: [PATCH] fix(member-export): forbid request without actor instead of falling through The nil-actor guard used a one-armed if and continued into the export path regardless. The CheckPagePermission plug already halts unauthenticated requests before this controller runs, so the corrected early return preserves observable behavior while removing the dead fall-through. The export action is split into per-payload clauses so the guard reads as a flat early return. --- .../controllers/member_export_controller.ex | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/mv_web/controllers/member_export_controller.ex b/lib/mv_web/controllers/member_export_controller.ex index 9b08f5d..e9c4a2a 100644 --- a/lib/mv_web/controllers/member_export_controller.ex +++ b/lib/mv_web/controllers/member_export_controller.ex @@ -25,31 +25,33 @@ defmodule MvWeb.MemberExportController do @custom_field_prefix Mv.Constants.custom_field_prefix() def export(conn, params) do - actor = current_actor(conn) - if is_nil(actor), do: return_forbidden(conn) - - case params["payload"] do - nil -> - conn - |> put_status(400) - |> put_resp_content_type("application/json") - |> json(%{error: "payload required"}) - - payload when is_binary(payload) -> - case Jason.decode(payload) do - {:ok, decoded} when is_map(decoded) -> - parsed = parse_and_validate(decoded) - run_export(conn, actor, parsed) - - _ -> - conn - |> put_status(400) - |> put_resp_content_type("application/json") - |> json(%{error: "invalid JSON"}) - end + case current_actor(conn) do + nil -> return_forbidden(conn) + actor -> export_with_actor(conn, actor, params["payload"]) end end + defp export_with_actor(conn, actor, payload) when is_binary(payload) do + case Jason.decode(payload) do + {:ok, decoded} when is_map(decoded) -> + run_export(conn, actor, parse_and_validate(decoded)) + + _ -> + json_error(conn, "invalid JSON") + end + end + + defp export_with_actor(conn, _actor, _payload) do + json_error(conn, "payload required") + end + + defp json_error(conn, message) do + conn + |> put_status(400) + |> put_resp_content_type("application/json") + |> json(%{error: message}) + end + defp current_actor(conn) do conn.assigns[:current_user] |> Actor.ensure_loaded()