Harden M3 giftwrap recipient gating in storage adapters

This commit is contained in:
2026-03-13 22:07:39 +01:00
parent 3bf1b22103
commit 1547d00215
4 changed files with 65 additions and 15 deletions

View File

@@ -37,15 +37,19 @@ defmodule Parrhesia.Storage.Adapters.Memory.Events do
end
@impl true
def query(_context, filters, _opts) do
def query(_context, filters, opts) do
with :ok <- Filter.validate_filters(filters) do
state = Store.get(& &1)
requester_pubkeys = Keyword.get(opts, :requester_pubkeys, [])
events =
state.events
|> Map.values()
|> Enum.reject(fn event -> MapSet.member?(state.deleted, event["id"]) end)
|> Enum.filter(&Filter.matches_any?(&1, filters))
|> Enum.filter(fn event ->
not MapSet.member?(state.deleted, event["id"]) and
Filter.matches_any?(event, filters) and
giftwrap_visible_to_requester?(event, requester_pubkeys)
end)
{:ok, events}
end
@@ -100,4 +104,20 @@ defmodule Parrhesia.Storage.Adapters.Memory.Events do
@impl true
def purge_expired(_opts), do: {:ok, 0}
defp giftwrap_visible_to_requester?(%{"kind" => 1059} = event, requester_pubkeys) do
requester_pubkeys != [] and
event_targets_any_recipient?(event, requester_pubkeys)
end
defp giftwrap_visible_to_requester?(_event, _requester_pubkeys), do: true
defp event_targets_any_recipient?(event, requester_pubkeys) do
event
|> Map.get("tags", [])
|> Enum.any?(fn
["p", recipient | _rest] -> recipient in requester_pubkeys
_tag -> false
end)
end
end

View File

@@ -661,19 +661,24 @@ defmodule Parrhesia.Storage.Adapters.Postgres.Events do
defp maybe_restrict_giftwrap_access(query, filter, opts) do
requester_pubkeys = Keyword.get(opts, :requester_pubkeys, [])
if targets_giftwrap?(filter) and requester_pubkeys != [] do
where(
query,
[event],
fragment(
"EXISTS (SELECT 1 FROM event_tags AS tag WHERE tag.event_created_at = ? AND tag.event_id = ? AND tag.name = 'p' AND tag.value = ANY(?))",
event.created_at,
event.id,
type(^requester_pubkeys, {:array, :string})
cond do
targets_giftwrap?(filter) and requester_pubkeys != [] ->
where(
query,
[event],
fragment(
"EXISTS (SELECT 1 FROM event_tags AS tag WHERE tag.event_created_at = ? AND tag.event_id = ? AND tag.name = 'p' AND tag.value = ANY(?))",
event.created_at,
event.id,
type(^requester_pubkeys, {:array, :string})
)
)
)
else
query
targets_giftwrap?(filter) ->
where(query, [_event], false)
true ->
query
end
end

View File

@@ -25,4 +25,26 @@ defmodule Parrhesia.Storage.Adapters.Memory.AdapterTest do
assert :ok = Admin.append_audit_log(%{}, %{method: "ping"})
assert {:ok, [%{method: "ping"}]} = Admin.list_audit_logs(%{}, [])
end
test "memory adapter enforces recipient visibility for giftwrap queries" do
recipient = String.duplicate("b", 64)
giftwrap_event = %{
"id" => String.duplicate("c", 64),
"pubkey" => "pk",
"kind" => 1059,
"tags" => [["p", recipient]],
"content" => "ciphertext"
}
assert {:ok, _event} = Events.put_event(%{}, giftwrap_event)
filters = [%{"kinds" => [1059], "#p" => [recipient]}]
assert {:ok, [result]} = Events.query(%{}, filters, requester_pubkeys: [recipient])
assert result["id"] == giftwrap_event["id"]
assert {:ok, []} = Events.query(%{}, filters, requester_pubkeys: [])
assert {:ok, 0} = Events.count(%{}, filters, requester_pubkeys: [])
end
end

View File

@@ -243,6 +243,9 @@ defmodule Parrhesia.Storage.Adapters.Postgres.EventsQueryCountTest do
Events.query(%{}, filters, requester_pubkeys: [recipient])
assert result["id"] == allowed["id"]
assert {:ok, []} = Events.query(%{}, filters, requester_pubkeys: [])
assert {:ok, 0} = Events.count(%{}, filters, requester_pubkeys: [])
end
test "query/3 supports #i keypackage reference lookups" do