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.
Sources: a packages source only reads the owner's own mailbox
04935c3 · Gabe Morell · 2026-11-04 22:43
Message
{commit_body(@commit)}
Files changed
modified
apps/room_sanctum/lib/room_sanctum/configuration.ex
+3
−3
@@ -109,10 +109,10 @@ defmodule RoomSanctum.Configuration do
| 109 | 109 | """ |
| 110 | 110 | def create_source(attrs \\ %{}) do |
| 111 | 111 | r = %Source{} |> Source.changeset(attrs) |> Repo.insert() |
| 112 | − {:ok, d} = r | |
| 113 | 112 | |
| 114 | − case d.type do | |
| 115 | − :packages -> | |
| 113 | + # A refused source is handed back as one, not raised as a MatchError. | |
| 114 | + case r do | |
| 115 | + {:ok, %Source{type: :packages} = d} -> | |
| 116 | 116 | ## create main mailbox |
| 117 | 117 | create_taxid(%{source_id: d.id, user: Ecto.UUID.generate(), designator: "mail_main"}) |
| 118 | 118 | ## create mailbox for usps handling |
modified
apps/room_sanctum/lib/room_sanctum/configuration/source.ex
+5
−0
@@ -3,6 +3,8 @@ defmodule RoomSanctum.Configuration.Source do
| 3 | 3 | import Ecto.Changeset |
| 4 | 4 | import PolymorphicEmbed |
| 5 | 5 | |
| 6 | + alias RoomSanctum.Configuration.Ownership | |
| 7 | + | |
| 6 | 8 | schema "cfg_sources" do |
| 7 | 9 | has_many :mailboxes, RoomSanctum.Configuration.Taxid |
| 8 | 10 | has_many :webhooks, RoomSanctum.Configuration.Agyr |
@@ -83,6 +85,9 @@ defmodule RoomSanctum.Configuration.Source do
| 83 | 85 | |> foreign_key_constraint(:user_id) |
| 84 | 86 | |> cast_polymorphic_embed(:config, required: true) |
| 85 | 87 | |> validate_required([:name, :type, :enabled, :user_id]) |
| 88 | + # A packages source is fed the mail its mailbox source pulls, so it may | |
| 89 | + # only name one of its owner's own. | |
| 90 | + |> Ownership.validate_owned_in(:config, :mailbox_source_id, __MODULE__) | |
| 86 | 91 | end |
| 87 | 92 | |
| 88 | 93 | def meta_changeset(meta, attrs \\ %{}) do |
added
apps/room_sanctum/test/room_sanctum/source_mailbox_owner_test.exs
+59
−0
@@ -0,0 +1,59 @@
| 1 | +defmodule RoomSanctum.SourceMailboxOwnerTest do | |
| 2 | + @moduledoc """ | |
| 3 | + A packages source is fed the mail its mailbox source pulls, so it may only | |
| 4 | + name one of its owner's own -- naming someone else's would fan their mail | |
| 5 | + out to it. | |
| 6 | + """ | |
| 7 | + use RoomSanctum.DataCase | |
| 8 | + | |
| 9 | + import RoomSanctum.OwnershipFixtures | |
| 10 | + | |
| 11 | + alias RoomSanctum.Configuration | |
| 12 | + | |
| 13 | + defp mailbox_for(user) do | |
| 14 | + source_for(user, %{ | |
| 15 | + type: :mailbox, | |
| 16 | + config: %{ | |
| 17 | + "__type__" => "mailbox", | |
| 18 | + "host" => "imap.e.test", | |
| 19 | + "username" => "me", | |
| 20 | + "password" => "pw" | |
| 21 | + } | |
| 22 | + }) | |
| 23 | + end | |
| 24 | + | |
| 25 | + defp packages(user, mailbox) do | |
| 26 | + Configuration.create_source(%{ | |
| 27 | + name: "Parcels", | |
| 28 | + notes: "", | |
| 29 | + type: :packages, | |
| 30 | + enabled: true, | |
| 31 | + user_id: user.id, | |
| 32 | + config: %{"__type__" => "packages", "mailbox_source_id" => mailbox.id} | |
| 33 | + }) | |
| 34 | + end | |
| 35 | + | |
| 36 | + test "the owner's own mailbox is accepted" do | |
| 37 | + me = owner() | |
| 38 | + mailbox = mailbox_for(me) | |
| 39 | + assert {:ok, source} = packages(me, mailbox) | |
| 40 | + assert source.config.mailbox_source_id == mailbox.id | |
| 41 | + end | |
| 42 | + | |
| 43 | + test "another user's mailbox is refused, as a changeset error" do | |
| 44 | + assert {:error, changeset} = packages(owner(), mailbox_for(owner())) | |
| 45 | + assert %{config: [_]} = errors_on(changeset) | |
| 46 | + end | |
| 47 | + | |
| 48 | + test "an existing source cannot be moved onto another user's mailbox" do | |
| 49 | + me = owner() | |
| 50 | + {:ok, source} = packages(me, mailbox_for(me)) | |
| 51 | + theirs = mailbox_for(owner()) | |
| 52 | + | |
| 53 | + assert {:error, _} = | |
| 54 | + Configuration.update_source_config(source, %{mailbox_source_id: theirs.id}) | |
| 55 | + | |
| 56 | + assert {:ok, _} = Configuration.update_source(source, %{name: "Renamed"}) | |
| 57 | + assert {:ok, _} = Configuration.update_source_config(source, %{handle_usps: false}) | |
| 58 | + end | |
| 59 | +end |
Parents: b4aa1b1