Add configurable tag guardrails

This commit is contained in:
2026-03-18 13:36:40 +01:00
parent 8dbf05b7fe
commit 57fdb4ed85
9 changed files with 150 additions and 15 deletions

View File

@@ -6,6 +6,8 @@ defmodule Parrhesia.ConfigTest do
assert Parrhesia.Config.get([:limits, :max_event_bytes]) == 262_144
assert Parrhesia.Config.get([:limits, :max_event_future_skew_seconds]) == 900
assert Parrhesia.Config.get([:limits, :max_event_ingest_per_window]) == 120
assert Parrhesia.Config.get([:limits, :max_tags_per_event]) == 256
assert Parrhesia.Config.get([:limits, :max_tag_values_per_filter]) == 128
assert Parrhesia.Config.get([:limits, :event_ingest_window_seconds]) == 1
assert Parrhesia.Config.get([:limits, :auth_max_age_seconds]) == 600
assert Parrhesia.Config.get([:limits, :max_outbound_queue]) == 256

View File

@@ -140,6 +140,18 @@ defmodule Parrhesia.Protocol.EventValidatorMarmotTest do
EventValidator.validate(invalid_empty_content)
end
test "rejects events with too many tags" do
event =
valid_keypackage_event(%{
"tags" => Enum.map(1..257, fn index -> ["e", "ref-#{index}"] end)
})
assert {:error, :too_many_tags} = EventValidator.validate(event)
assert {:error, "invalid: event tags exceed configured limit"} =
Protocol.validate_event(event)
end
defp valid_keypackage_event(overrides \\ %{}) do
base_event = %{
"pubkey" => String.duplicate("1", 64),

View File

@@ -40,6 +40,15 @@ defmodule Parrhesia.Protocol.FilterTest do
assert {:error, :invalid_search} = Filter.validate_filters([%{"search" => ""}])
end
test "rejects tag filters with too many values" do
filter = %{"#e" => Enum.map(1..129, &"event-ref-#{&1}")}
assert {:error, :too_many_tag_values} = Filter.validate_filters([filter])
assert Filter.error_message(:too_many_tag_values) ==
"invalid: tag filters exceed configured value limit"
end
test "matches with AND semantics inside filter and OR across filters" do
event = valid_event()

View File

@@ -40,6 +40,38 @@ defmodule Parrhesia.Web.ConnectionTest do
assert payload["approximate"] == false
end
test "REQ rejects tag filters that exceed the configured value limit" do
state = connection_state()
payload =
JSON.encode!(["REQ", "sub-tag-limit", %{"#e" => Enum.map(1..129, &"ref-#{&1}")}])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert JSON.decode!(response) == [
"CLOSED",
"sub-tag-limit",
"invalid: tag filters exceed configured value limit"
]
end
test "COUNT rejects tag filters that exceed the configured value limit" do
state = connection_state()
payload =
JSON.encode!(["COUNT", "sub-tag-limit", %{"#e" => Enum.map(1..129, &"ref-#{&1}")}])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert JSON.decode!(response) == [
"CLOSED",
"sub-tag-limit",
"invalid: tag filters exceed configured value limit"
]
end
test "AUTH accepts valid challenge event" do
state = connection_state()