Complete MIP-02 recipient-gated welcome conformance tests
This commit is contained in:
@@ -28,9 +28,9 @@ Spec source: `~/marmot/README.md` + MIP-00..05.
|
||||
|
||||
## M3 — MIP-02 (welcome events)
|
||||
|
||||
- [ ] Support wrapped Welcome delivery via NIP-59 (`1059`) recipient-gated reads
|
||||
- [x] Support wrapped Welcome delivery via NIP-59 (`1059`) recipient-gated reads
|
||||
- [x] Validate relay behavior for unsigned inner Welcome semantics (kind `444` envelope expectations)
|
||||
- [ ] Ensure durability/ack semantics support Commit-then-Welcome sequencing requirements
|
||||
- [x] Ensure durability/ack semantics support Commit-then-Welcome sequencing requirements
|
||||
- [x] Add negative tests for malformed wrapped Welcome payloads
|
||||
|
||||
## M4 — MIP-03 (group events)
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Parrhesia.Web.ConformanceTest do
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
alias Parrhesia.Protocol.EventValidator
|
||||
alias Parrhesia.Repo
|
||||
alias Parrhesia.Storage
|
||||
alias Parrhesia.Web.Connection
|
||||
|
||||
setup do
|
||||
@@ -42,7 +43,113 @@ defmodule Parrhesia.Web.ConformanceTest do
|
||||
assert Jason.decode!(frame) == ["OK", event["id"], true, "ok: event stored"]
|
||||
end
|
||||
|
||||
defp valid_event do
|
||||
test "wrapped kind 1059 welcome delivery is recipient-gated" do
|
||||
{:ok, state} = Connection.init(subscription_index: nil)
|
||||
recipient = String.duplicate("9", 64)
|
||||
|
||||
wrapped_welcome =
|
||||
valid_event(%{
|
||||
"kind" => 1059,
|
||||
"tags" => [["p", recipient], ["e", String.duplicate("a", 64)]],
|
||||
"content" => "encrypted-welcome-payload"
|
||||
})
|
||||
|
||||
assert {:push, {:text, ok_frame}, ^state} =
|
||||
Connection.handle_in(
|
||||
{Jason.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
|
||||
state
|
||||
)
|
||||
|
||||
assert Jason.decode!(ok_frame) == ["OK", wrapped_welcome["id"], true, "ok: event stored"]
|
||||
|
||||
req_payload = Jason.encode!(["REQ", "sub-welcome", %{"kinds" => [1059], "#p" => [recipient]}])
|
||||
|
||||
assert {:push, restricted_frames, ^state} =
|
||||
Connection.handle_in({req_payload, [opcode: :text]}, state)
|
||||
|
||||
decoded_restricted =
|
||||
Enum.map(restricted_frames, fn {:text, frame} -> Jason.decode!(frame) end)
|
||||
|
||||
assert [
|
||||
"CLOSED",
|
||||
"sub-welcome",
|
||||
"restricted: giftwrap access requires recipient authentication"
|
||||
] =
|
||||
Enum.find(decoded_restricted, fn frame -> List.first(frame) == "CLOSED" end)
|
||||
|
||||
auth_event = valid_auth_event(state.auth_challenge, recipient)
|
||||
|
||||
assert {:push, {:text, auth_frame}, authed_state} =
|
||||
Connection.handle_in({Jason.encode!(["AUTH", auth_event]), [opcode: :text]}, state)
|
||||
|
||||
assert Jason.decode!(auth_frame) == ["OK", auth_event["id"], true, "ok: auth accepted"]
|
||||
|
||||
assert {:push, frames, _next_state} =
|
||||
Connection.handle_in({req_payload, [opcode: :text]}, authed_state)
|
||||
|
||||
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
|
||||
|
||||
assert ["EVENT", "sub-welcome", result_event] =
|
||||
Enum.find(decoded, fn frame -> List.first(frame) == "EVENT" end)
|
||||
|
||||
assert result_event["id"] == wrapped_welcome["id"]
|
||||
assert List.last(decoded) == ["EOSE", "sub-welcome"]
|
||||
end
|
||||
|
||||
test "kind 445 commit ACK implies durable visibility before wrapped welcome ACK" do
|
||||
previous_features = Application.get_env(:parrhesia, :features, [])
|
||||
|
||||
Application.put_env(:parrhesia, :features, Keyword.put(previous_features, :nip_ee_mls, true))
|
||||
|
||||
on_exit(fn ->
|
||||
Application.put_env(:parrhesia, :features, previous_features)
|
||||
end)
|
||||
|
||||
{:ok, state} = Connection.init(subscription_index: nil)
|
||||
|
||||
commit_event =
|
||||
valid_event(%{
|
||||
"kind" => 445,
|
||||
"tags" => [["h", String.duplicate("b", 64)]],
|
||||
"content" => "commit-envelope"
|
||||
})
|
||||
|
||||
assert {:push, {:text, commit_ok_frame}, ^state} =
|
||||
Connection.handle_in(
|
||||
{Jason.encode!(["EVENT", commit_event]), [opcode: :text]},
|
||||
state
|
||||
)
|
||||
|
||||
assert Jason.decode!(commit_ok_frame) == ["OK", commit_event["id"], true, "ok: event stored"]
|
||||
|
||||
assert {:ok, persisted_commit} = Storage.events().get_event(%{}, commit_event["id"])
|
||||
assert persisted_commit["id"] == commit_event["id"]
|
||||
|
||||
wrapped_welcome =
|
||||
valid_event(%{
|
||||
"kind" => 1059,
|
||||
"tags" => [["p", String.duplicate("c", 64)], ["e", String.duplicate("d", 64)]],
|
||||
"content" => "encrypted-welcome-payload"
|
||||
})
|
||||
|
||||
assert {:push, {:text, welcome_ok_frame}, ^state} =
|
||||
Connection.handle_in(
|
||||
{Jason.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
|
||||
state
|
||||
)
|
||||
|
||||
assert Jason.decode!(welcome_ok_frame) == [
|
||||
"OK",
|
||||
wrapped_welcome["id"],
|
||||
true,
|
||||
"ok: event stored"
|
||||
]
|
||||
|
||||
assert {:ok, persisted_welcome} = Storage.events().get_event(%{}, wrapped_welcome["id"])
|
||||
assert persisted_welcome["id"] == wrapped_welcome["id"]
|
||||
end
|
||||
|
||||
defp valid_event(overrides \\ %{}) do
|
||||
now = System.system_time(:second)
|
||||
|
||||
base = %{
|
||||
@@ -54,6 +161,20 @@ defmodule Parrhesia.Web.ConformanceTest do
|
||||
"sig" => String.duplicate("2", 128)
|
||||
}
|
||||
|
||||
Map.put(base, "id", EventValidator.compute_id(base))
|
||||
event = Map.merge(base, overrides)
|
||||
Map.put(event, "id", EventValidator.compute_id(event))
|
||||
end
|
||||
|
||||
defp valid_auth_event(challenge, pubkey) do
|
||||
event = %{
|
||||
"pubkey" => pubkey,
|
||||
"created_at" => System.system_time(:second),
|
||||
"kind" => 22_242,
|
||||
"tags" => [["challenge", challenge]],
|
||||
"content" => "",
|
||||
"sig" => String.duplicate("8", 128)
|
||||
}
|
||||
|
||||
Map.put(event, "id", EventValidator.compute_id(event))
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user