neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
⭐
Log in to mark this repository.
Keryx: a keryx only carries the owner's own queries
2d73edf · Gabe Morell · 2026-11-04 22:34
Message
{commit_body(@commit)}
Files changed
modified
apps/room_sanctum/lib/room_sanctum/configuration/keryx.ex
+5
−0
@@ -2,6 +2,8 @@ defmodule RoomSanctum.Configuration.Keryx do
| 2 | 2 | use Ecto.Schema |
| 3 | 3 | import Ecto.Changeset |
| 4 | 4 | |
| 5 | + alias RoomSanctum.Configuration.{Ownership, Query} | |
| 6 | + | |
| 5 | 7 | schema "keryxiae" do |
| 6 | 8 | field :name, :string |
| 7 | 9 | field :ttl, :integer |
@@ -18,6 +20,9 @@ defmodule RoomSanctum.Configuration.Keryx do
| 18 | 20 | |> foreign_key_constraint(:user_id) |
| 19 | 21 | |> validate_required([:name, :query_ids, :ttl]) |
| 20 | 22 | |> unique_constraint(:name) |
| 23 | + # The worker publishes every one of these queries' results, so another | |
| 24 | + # user's would be published to this keryx's subscribers. | |
| 25 | + |> Ownership.validate_owned(:query_ids, Query) | |
| 21 | 26 | end |
| 22 | 27 | |
| 23 | 28 | @doc """ |
added
apps/room_sanctum/test/room_sanctum_web/live/keryx_owned_ids_test.exs
+67
−0
@@ -0,0 +1,67 @@
| 1 | +defmodule RoomSanctumWeb.KeryxOwnedIdsTest do | |
| 2 | + @moduledoc """ | |
| 3 | + A keryx publishes its queries' results to whoever subscribes to it, so it | |
| 4 | + may only carry its owner's queries. The form only offers those, but sends | |
| 5 | + them as hidden inputs, and a forged one is refused. | |
| 6 | + """ | |
| 7 | + use RoomSanctumWeb.ConnCase | |
| 8 | + | |
| 9 | + import Phoenix.LiveViewTest | |
| 10 | + import RoomSanctum.DataCase, only: [errors_on: 1] | |
| 11 | + import RoomSanctum.OwnershipFixtures | |
| 12 | + | |
| 13 | + alias RoomSanctum.{Configuration, Repo} | |
| 14 | + alias RoomSanctum.Configuration.Keryx | |
| 15 | + | |
| 16 | + setup %{conn: conn} do | |
| 17 | + me = owner() | |
| 18 | + %{conn: log_in_user(conn, me), me: me} | |
| 19 | + end | |
| 20 | + | |
| 21 | + defp submit(conn, query_ids) do | |
| 22 | + {:ok, live, _html} = live(conn, Routes.keryx_index_path(conn, :new)) | |
| 23 | + | |
| 24 | + live | |
| 25 | + |> form("#keryx-form") | |
| 26 | + |> render_submit(%{ | |
| 27 | + "keryx" => %{ | |
| 28 | + "name" => "herald", | |
| 29 | + "ttl" => "60", | |
| 30 | + "query_ids" => Enum.map(query_ids, &to_string/1) | |
| 31 | + } | |
| 32 | + }) | |
| 33 | + end | |
| 34 | + | |
| 35 | + test "the form saves the owner's own queries", ctx do | |
| 36 | + mine = query_for(ctx.me) | |
| 37 | + submit(ctx.conn, [mine.id]) | |
| 38 | + | |
| 39 | + assert [%Keryx{query_ids: [id]}] = Repo.all(Keryx) | |
| 40 | + assert id == mine.id | |
| 41 | + end | |
| 42 | + | |
| 43 | + test "the form refuses another user's query", ctx do | |
| 44 | + theirs = query_for(owner()) | |
| 45 | + submit(ctx.conn, [query_for(ctx.me).id, theirs.id]) | |
| 46 | + | |
| 47 | + assert Repo.all(Keryx) == [] | |
| 48 | + end | |
| 49 | + | |
| 50 | + test "an existing keryx cannot be given another user's query", ctx do | |
| 51 | + mine = query_for(ctx.me) | |
| 52 | + | |
| 53 | + {:ok, keryx} = | |
| 54 | + Configuration.create_keryx(%{ | |
| 55 | + name: "herald", | |
| 56 | + ttl: 60, | |
| 57 | + query_ids: [mine.id], | |
| 58 | + user_id: ctx.me.id | |
| 59 | + }) | |
| 60 | + | |
| 61 | + assert {:error, changeset} = | |
| 62 | + Configuration.update_keryx(keryx, %{query_ids: [mine.id, query_for(owner()).id]}) | |
| 63 | + | |
| 64 | + assert %{query_ids: [_]} = errors_on(changeset) | |
| 65 | + assert {:ok, _} = Configuration.update_keryx(keryx, %{name: "renamed"}) | |
| 66 | + end | |
| 67 | +end |
Parents: 31b25cb