From 748baff8f3c9b03a6369176ddd28787d3ff74c37 Mon Sep 17 00:00:00 2001 From: miraikumiko Date: Sun, 29 Jun 2025 08:35:12 +0200 Subject: [PATCH] Add inbox_controller_test.exs --- .../controllers/inbox_controller_test.exs | 71 +++++++++++++++++++ test/support/fixtures/data.ex | 50 +++++++------ 2 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 test/nulla_web/controllers/inbox_controller_test.exs diff --git a/test/nulla_web/controllers/inbox_controller_test.exs b/test/nulla_web/controllers/inbox_controller_test.exs new file mode 100644 index 0000000..57dea6b --- /dev/null +++ b/test/nulla_web/controllers/inbox_controller_test.exs @@ -0,0 +1,71 @@ +defmodule NullaWeb.InboxControllerTest do + use NullaWeb.ConnCase + alias Nulla.Snowflake + alias Nulla.Models.User + alias Nulla.Models.Actor + + setup do + Nulla.Fixtures.Data.create() + :ok + end + + describe "POST /users/username/inbox" do + test "Validate follow request", %{conn: conn} do + actor = Actor.get_actor(preferredUsername: "test") + target_actor = Actor.get_actor(preferredUsername: "test2") + user = User.get_user(id: actor.id) + + follow_activity = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => Snowflake.next_id(), + "type" => "Follow", + "actor" => actor.ap_id, + "object" => target_actor.ap_id + } + + body = Jason.encode!(follow_activity) + + digest = "SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64()) + date = Calendar.strftime(DateTime.utc_now(), "%a, %d %b %Y %H:%M:%S GMT") + uri = URI.parse("/users/test2/inbox") + + signature_string = """ + (request-target): post #{uri.path} + host: localhost + date: #{date} + digest: #{digest} + """ + + private_key = + case :public_key.pem_decode(user.privateKeyPem) do + [entry] -> :public_key.pem_entry_decode(entry) + _ -> raise "Invalid PEM format" + end + + signature = + :public_key.sign(signature_string, :sha256, private_key) + |> Base.encode64() + + signature_header = + """ + keyId="#{actor.publicKey["id"]}", + algorithm="rsa-sha256", + headers="(request-target) host date digest", + signature="#{signature}" + """ + |> String.replace("\n", "") + |> String.trim() + + conn = + conn + |> put_req_header("content-type", "application/activity+json") + |> put_req_header("accept", "application/activity+json") + |> put_req_header("date", date) + |> put_req_header("digest", digest) + |> put_req_header("signature", signature_header) + |> post("/users/test2/inbox", body) + + assert conn.status == 200 + end + end +end diff --git a/test/support/fixtures/data.ex b/test/support/fixtures/data.ex index 571888f..1327dca 100644 --- a/test/support/fixtures/data.ex +++ b/test/support/fixtures/data.ex @@ -5,23 +5,29 @@ defmodule Nulla.Fixtures.Data do alias Nulla.Models.Note def create do + endpoint_config = Application.fetch_env!(:nulla, NullaWeb.Endpoint) + ip = endpoint_config[:http][:ip] + host = :inet_parse.ntoa(ip) |> to_string() + port = endpoint_config[:http][:port] + base_url = "http://#{host}:#{port}" + {publicKeyPem, privateKeyPem} = KeyGen.gen() {:ok, actor} = Actor.create_actor(%{ domain: "localhost", - ap_id: "http://localhost/users/test", + ap_id: "#{base_url}/users/test", type: "Person", - following: "http://localhost/users/test/following", - followers: "http://localhost/users/test/followers", - inbox: "http://localhost/users/test/inbox", - outbox: "http://localhost/users/test/outbox", - featured: "http://localhost/users/test/collections/featured", - featuredTags: "http://localhost/users/test/collections/tags", + following: "#{base_url}/users/test/following", + followers: "#{base_url}/users/test/followers", + inbox: "#{base_url}/users/test/inbox", + outbox: "#{base_url}/users/test/outbox", + featured: "#{base_url}/users/test/collections/featured", + featuredTags: "#{base_url}/users/test/collections/tags", preferredUsername: "test", name: "Test", summary: "Test User", - url: "http://localhost/@test", + url: "#{base_url}/@test", manuallyApprovesFollowers: false, discoverable: true, indexable: true, @@ -29,11 +35,11 @@ defmodule Nulla.Fixtures.Data do memorial: false, publicKey: Jason.OrderedObject.new( - id: "http://localhost/users/test#main-key", - owner: "http://localhost/users/test", + id: "#{base_url}/users/test#main-key", + owner: "#{base_url}/users/test", publicKeyPem: publicKeyPem ), - endpoints: Jason.OrderedObject.new(sharedInbox: "http://localhost/inbox") + endpoints: Jason.OrderedObject.new(sharedInbox: "#{base_url}/inbox") }) User.create_user(%{ @@ -56,18 +62,18 @@ defmodule Nulla.Fixtures.Data do {:ok, actor} = Actor.create_actor(%{ domain: "localhost", - ap_id: "http://localhost/users/test2", + ap_id: "#{base_url}/users/test2", type: "Person", - following: "http://localhost/users/test2/following", - followers: "http://localhost/users/test2/followers", - inbox: "http://localhost/users/test2/inbox", - outbox: "http://localhost/users/test2/outbox", - featured: "http://localhost/users/test2/collections/featured", - featuredTags: "http://localhost/users/test2/collections/tags", + following: "#{base_url}/users/test2/following", + followers: "#{base_url}/users/test2/followers", + inbox: "#{base_url}/users/test2/inbox", + outbox: "#{base_url}/users/test2/outbox", + featured: "#{base_url}/users/test2/collections/featured", + featuredTags: "#{base_url}/users/test2/collections/tags", preferredUsername: "test2", name: "Test", summary: "Test User", - url: "http://localhost/@test2", + url: "#{base_url}/@test2", manuallyApprovesFollowers: false, discoverable: true, indexable: true, @@ -75,11 +81,11 @@ defmodule Nulla.Fixtures.Data do memorial: false, publicKey: Jason.OrderedObject.new( - id: "http://localhost/users/test2#main-key", - owner: "http://localhost/users/test2", + id: "#{base_url}/users/test2#main-key", + owner: "#{base_url}/users/test2", publicKeyPem: publicKeyPem ), - endpoints: Jason.OrderedObject.new(sharedInbox: "http://localhost/inbox") + endpoints: Jason.OrderedObject.new(sharedInbox: "#{base_url}/inbox") }) User.create_user(%{