Implement M5 media metadata policy hooks and query coverage

This commit is contained in:
2026-03-13 22:21:28 +01:00
parent 619c1a0bdf
commit a42c2b656e
8 changed files with 419 additions and 3 deletions

View File

@@ -8,6 +8,8 @@ defmodule Parrhesia.ConfigTest do
assert Parrhesia.Config.get([:limits, :max_outbound_queue]) == 256
assert Parrhesia.Config.get([:limits, :max_filter_limit]) == 500
assert Parrhesia.Config.get([:policies, :auth_required_for_writes]) == false
assert Parrhesia.Config.get([:policies, :marmot_media_max_imeta_tags_per_event]) == 8
assert Parrhesia.Config.get([:policies, :marmot_media_reject_mip04_v1]) == true
assert Parrhesia.Config.get([:features, :nip_50_search]) == true
assert Parrhesia.Config.get([:features, :nip_ee_mls]) == false
end

View File

@@ -98,6 +98,131 @@ defmodule Parrhesia.Policy.EventPolicyTest do
EventPolicy.authorize_read([wide_window], MapSet.new())
end
test "accepts MIP-04 media metadata events as regular Nostr events" do
media_event = %{
"kind" => 1,
"tags" => [
[
"imeta",
"url",
"https://media.example/blob",
"m",
"image/jpeg",
"x",
String.duplicate("a", 64),
"v",
"mip04-v2"
]
],
"pubkey" => String.duplicate("d", 64),
"id" => ""
}
assert :ok =
EventPolicy.authorize_write(media_event, MapSet.new([String.duplicate("d", 64)]))
end
test "enforces media metadata tag limits" do
Application.put_env(
:parrhesia,
:policies,
marmot_media_max_imeta_tags_per_event: 1,
marmot_media_max_field_value_bytes: 1024,
marmot_media_max_url_bytes: 2048,
marmot_media_allowed_mime_prefixes: [],
marmot_media_reject_mip04_v1: true
)
event = %{
"kind" => 1,
"tags" => [
[
"imeta",
"url",
"https://media.example/1",
"m",
"image/jpeg",
"x",
String.duplicate("a", 64)
],
[
"imeta",
"url",
"https://media.example/2",
"m",
"image/jpeg",
"x",
String.duplicate("b", 64)
]
],
"pubkey" => String.duplicate("d", 64),
"id" => ""
}
assert {:error, :media_metadata_tags_exceeded} =
EventPolicy.authorize_write(event, MapSet.new([String.duplicate("d", 64)]))
end
test "rejects disallowed media mime types and unsupported versions" do
Application.put_env(
:parrhesia,
:policies,
marmot_media_max_imeta_tags_per_event: 8,
marmot_media_max_field_value_bytes: 1024,
marmot_media_max_url_bytes: 2048,
marmot_media_allowed_mime_prefixes: ["image/"],
marmot_media_reject_mip04_v1: true
)
invalid_mime_event = %{
"kind" => 1,
"tags" => [
[
"imeta",
"url",
"https://media.example/1",
"m",
"video/mp4",
"x",
String.duplicate("a", 64)
]
],
"pubkey" => String.duplicate("d", 64),
"id" => ""
}
unsupported_version_event = %{
"kind" => 1,
"tags" => [
[
"imeta",
"url",
"https://media.example/1",
"m",
"image/jpeg",
"x",
String.duplicate("a", 64),
"v",
"mip04-v1"
]
],
"pubkey" => String.duplicate("d", 64),
"id" => ""
}
assert {:error, :media_metadata_mime_not_allowed} =
EventPolicy.authorize_write(
invalid_mime_event,
MapSet.new([String.duplicate("d", 64)])
)
assert {:error, :media_metadata_unsupported_version} =
EventPolicy.authorize_write(
unsupported_version_event,
MapSet.new([String.duplicate("d", 64)])
)
end
test "rejects mls kinds when feature is disabled" do
Application.put_env(:parrhesia, :features, nip_ee_mls: false)

View File

@@ -248,6 +248,44 @@ defmodule Parrhesia.Storage.Adapters.Postgres.EventsQueryCountTest do
assert {:ok, 0} = Events.count(%{}, filters, requester_pubkeys: [])
end
test "query/3 combines search and media metadata tag filters" do
media_hash = String.duplicate("a", 64)
matching =
persist_event(%{
"kind" => 1,
"tags" => [
["imeta", "url", "https://media.example/blob", "m", "image/jpeg", "x", media_hash],
["m", "image/jpeg"],
["x", media_hash]
],
"content" => "photo attachment from group"
})
_wrong_mime =
persist_event(%{
"kind" => 1,
"tags" => [["m", "video/mp4"], ["x", media_hash]],
"content" => "photo attachment from group"
})
_wrong_search =
persist_event(%{
"kind" => 1,
"tags" => [["m", "image/jpeg"], ["x", media_hash]],
"content" => "document attachment"
})
filters = [
%{"kinds" => [1], "search" => "photo", "#m" => ["image/jpeg"], "#x" => [media_hash]}
]
assert {:ok, [result]} = Events.query(%{}, filters, [])
assert result["id"] == matching["id"]
assert {:ok, 1} = Events.count(%{}, filters, [])
end
test "query/3 supports #i keypackage reference lookups" do
keypackage_ref = String.duplicate("a", 64)

View File

@@ -189,6 +189,40 @@ defmodule Parrhesia.Web.ConnectionTest do
]
end
test "unsupported media metadata version EVENT is rejected by policy" do
state = connection_state()
event =
valid_event()
|> Map.put("kind", 1)
|> Map.put("tags", [
[
"imeta",
"url",
"https://media.example/blob",
"m",
"image/jpeg",
"x",
String.duplicate("a", 64),
"v",
"mip04-v1"
]
])
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
"OK",
event["id"],
false,
"blocked: media metadata version is not supported"
]
end
test "NEG sessions open and close" do
state = connection_state()