Keryx: the keryx pages only reach the user's own

3994bbf · Gabe Morell · 2026-11-04 22:12

14 files +50 -4
Message
{commit_body(@commit)}

Files changed

modified apps/room_sanctum/lib/room_sanctum/configuration.ex
+3 −0
@@ -1213,6 +1213,9 @@ defmodule RoomSanctum.Configuration do
1213 1213 """
1214 1214 def get_keryx!(id), do: Repo.get!(Keryx, id)
1215 1215
1216 + # Someone else's keryx raises the not-found a missing one does.
1217 + def get_keryx!({:user, uid}, id), do: Repo.get_by!(Keryx, id: id, user_id: uid)
1218 +
1216 1219 @doc """
1217 1220 Creates a keryx.
1218 1221
modified apps/room_sanctum/lib/room_sanctum_web/live/keryx_live/index.ex
+5 −2
@@ -20,7 +20,7 @@ defmodule RoomSanctumWeb.KeryxLive.Index do
20 20 defp apply_action(socket, :edit, %{"id" => id}) do
21 21 socket
22 22 |> assign(:page_title, "Edit Keryx")
23 − |> assign(:keryx, Configuration.get_keryx!(id))
23 + |> assign(:keryx, Configuration.get_keryx!(owner(socket), id))
24 24 end
25 25
26 26 defp apply_action(socket, :new, _params) do
@@ -42,7 +42,7 @@ defmodule RoomSanctumWeb.KeryxLive.Index do
42 42
43 43 @impl true
44 44 def handle_event("delete", %{"id" => id}, socket) do
45 − keryx = Configuration.get_keryx!(id)
45 + keryx = Configuration.get_keryx!(owner(socket), id)
46 46 {:ok, _} = Configuration.delete_keryx(keryx)
47 47
48 48 {:noreply, stream_delete(socket, :keryxiae, keryx)}
@@ -51,4 +51,7 @@ defmodule RoomSanctumWeb.KeryxLive.Index do
51 51 def handle_event("info", _params, socket) do
52 52 {:noreply, socket |> assign(:show_info, !socket.assigns.show_info)}
53 53 end
54 +
55 + # Ids from the URL or the client are looked up among the user's own.
56 + defp owner(socket), do: {:user, socket.assigns.current_user.id}
54 57 end
modified apps/room_sanctum/lib/room_sanctum_web/live/keryx_live/show.ex
+8 −2
@@ -10,12 +10,13 @@ defmodule RoomSanctumWeb.KeryxLive.Show do
10 10 # Set up periodic refresh of cached items
11 11 Process.send_after(self(), :refresh_cache, 1000)
12 12 end
13 +
13 14 {:ok, socket}
14 15 end
15 16
16 17 @impl true
17 18 def handle_params(%{"id" => id}, _, socket) do
18 − keryx = Configuration.get_keryx!(id)
19 + keryx = Configuration.get_keryx!(owner(socket), id)
19 20 queries = Configuration.get_queries!(keryx.query_ids)
20 21 cached_items = fetch_cached_items(keryx.id)
21 22
@@ -73,7 +74,9 @@ defmodule RoomSanctumWeb.KeryxLive.Show do
73 74 _ ->
74 75 # If Jason encoding fails, use inspect as fallback
75 76 inspected = inspect(data, pretty: true, limit: 2048)
76 − String.slice(inspected, 0..2048) <> if String.length(inspected) > 2048, do: "...", else: ""
77 +
78 + String.slice(inspected, 0..2048) <>
79 + if String.length(inspected) > 2048, do: "...", else: ""
77 80 end
78 81 end
79 82
@@ -118,4 +121,7 @@ defmodule RoomSanctumWeb.KeryxLive.Show do
118 121 # RabbitMQ shows an MQTT client the routing key with its dots as slashes.
119 122 defp mqtt_base(keryx),
120 123 do: keryx.id |> Keryx.topic() |> Keryx.mqtt_topic()
124 +
125 + # The keryx comes from the URL, so it is looked up among the user's own.
126 + defp owner(socket), do: {:user, socket.assigns.current_user.id}
121 127 end
modified apps/room_sanctum/test/room_sanctum_web/live/ownership_test.exs
+34 −0
@@ -469,4 +469,38 @@ defmodule RoomSanctumWeb.OwnershipTest do
469 469 assert Repo.reload(theirs)
470 470 end
471 471 end
472 +
473 + describe "the keryx pages" do
474 + setup ctx do
475 + {:ok, theirs} =
476 + Configuration.create_keryx(%{
477 + name: "their herald",
478 + ttl: 60,
479 + query_ids: [query_for(ctx.them).id],
480 + user_id: ctx.them.id
481 + })
482 +
483 + %{theirs: theirs}
484 + end
485 +
486 + test "will not show another user's keryx", ctx do
487 + assert_raise Ecto.NoResultsError, fn ->
488 + live(ctx.conn, Routes.keryx_show_path(ctx.conn, :show, ctx.theirs))
489 + end
490 + end
491 +
492 + test "will not open another user's keryx for editing", ctx do
493 + assert_raise Ecto.NoResultsError, fn ->
494 + live(ctx.conn, Routes.keryx_index_path(ctx.conn, :edit, ctx.theirs))
495 + end
496 + end
497 +
498 + test "will not delete another user's keryx", ctx do
499 + {:ok, live, _html} = live(ctx.conn, Routes.keryx_index_path(ctx.conn, :index))
500 +
501 + forge(live, "delete", %{"id" => to_string(ctx.theirs.id)})
502 +
503 + assert Repo.reload(ctx.theirs)
504 + end
505 + end
472 506 end

Parents: d3734b5