Add signature verification and lossless event tag storage

This commit is contained in:
2026-03-14 04:20:42 +01:00
parent 18e429e05a
commit e12085af2f
8 changed files with 152 additions and 46 deletions

View File

@@ -15,6 +15,7 @@ defmodule Parrhesia.ConfigTest do
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([:policies, :marmot_push_max_trigger_age_seconds]) == 120
assert Parrhesia.Config.get([:features, :verify_event_signatures]) == false
assert Parrhesia.Config.get([:features, :nip_50_search]) == true
assert Parrhesia.Config.get([:features, :marmot_push_notifications]) == false
end

View File

@@ -0,0 +1,63 @@
defmodule Parrhesia.Protocol.EventValidatorSignatureTest do
use ExUnit.Case, async: true
alias Parrhesia.Protocol.EventValidator
test "accepts valid Schnorr signatures when verification is enabled" do
previous_features = Application.get_env(:parrhesia, :features, [])
Application.put_env(
:parrhesia,
:features,
Keyword.put(previous_features, :verify_event_signatures, true)
)
on_exit(fn ->
Application.put_env(:parrhesia, :features, previous_features)
end)
event = signed_event()
assert :ok = EventValidator.validate(event)
end
test "rejects invalid Schnorr signatures when verification is enabled" do
previous_features = Application.get_env(:parrhesia, :features, [])
Application.put_env(
:parrhesia,
:features,
Keyword.put(previous_features, :verify_event_signatures, true)
)
on_exit(fn ->
Application.put_env(:parrhesia, :features, previous_features)
end)
event =
signed_event()
|> Map.put("sig", String.duplicate("0", 128))
assert {:error, :invalid_signature} = EventValidator.validate(event)
end
defp signed_event do
{seckey, pubkey} = Secp256k1.keypair(:xonly)
event = %{
"pubkey" => Base.encode16(pubkey, case: :lower),
"created_at" => System.system_time(:second),
"kind" => 1,
"tags" => [["e", String.duplicate("a", 64), "wss://relay.example", "reply"]],
"content" => "signed"
}
id = EventValidator.compute_id(event)
{:ok, id_bin} = Base.decode16(id, case: :lower)
sig = Secp256k1.schnorr_sign(id_bin, seckey)
event
|> Map.put("id", id)
|> Map.put("sig", Base.encode16(sig, case: :lower))
end
end

View File

@@ -11,6 +11,24 @@ defmodule Parrhesia.Storage.Adapters.Postgres.EventsLifecycleTest do
:ok
end
test "event tags round-trip without truncation" do
tagged_event =
event(%{
"kind" => 1,
"tags" => [
["e", String.duplicate("a", 64), "wss://relay.example", "reply"],
["-"],
["p", String.duplicate("b", 64), "wss://hint.example"]
],
"content" => "tag-roundtrip"
})
assert {:ok, _event} = Events.put_event(%{}, tagged_event)
assert {:ok, persisted_tagged_event} = Events.get_event(%{}, tagged_event["id"])
assert persisted_tagged_event["tags"] == tagged_event["tags"]
end
test "delete_by_request tombstones owned target events" do
target = event(%{"kind" => 1, "content" => "target"})
assert {:ok, _event} = Events.put_event(%{}, target)