Fix http signature plug tests
This commit is contained in:
parent
4d3f52dcc6
commit
161d071f14
7 changed files with 63 additions and 27 deletions
|
@ -111,14 +111,20 @@ def private_pem_to_public_pem(private_pem) do
|
||||||
@doc """
|
@doc """
|
||||||
Given a user, return the public key for that user in binary format.
|
Given a user, return the public key for that user in binary format.
|
||||||
"""
|
"""
|
||||||
def public_key(%User{signing_key: %__MODULE__{public_key: public_key_pem}}) do
|
def public_key(%User{} = user) do
|
||||||
key =
|
case Repo.preload(user, :signing_key) do
|
||||||
public_key_pem
|
%User{signing_key: %__MODULE__{public_key: public_key_pem}} ->
|
||||||
|> :public_key.pem_decode()
|
key =
|
||||||
|> hd()
|
public_key_pem
|
||||||
|> :public_key.pem_entry_decode()
|
|> :public_key.pem_decode()
|
||||||
|
|> hd()
|
||||||
|
|> :public_key.pem_entry_decode()
|
||||||
|
|
||||||
{:ok, key}
|
{:ok, key}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{:error, "key not found"}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def public_key(_), do: {:error, "key not found"}
|
def public_key(_), do: {:error, "key not found"}
|
||||||
|
@ -133,6 +139,7 @@ def public_key_pem(%User{} = user) do
|
||||||
def public_key_pem(e) do
|
def public_key_pem(e) do
|
||||||
{:error, "key not found"}
|
{:error, "key not found"}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec private_key(User.t()) :: {:ok, binary()} | {:error, String.t()}
|
@spec private_key(User.t()) :: {:ok, binary()} | {:error, String.t()}
|
||||||
@doc """
|
@doc """
|
||||||
Given a user, return the private key for that user in binary format.
|
Given a user, return the private key for that user in binary format.
|
||||||
|
|
|
@ -60,7 +60,6 @@ defp relay_active?(conn, _) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Render the user's AP data
|
Render the user's AP data
|
||||||
WARNING: we cannot actually check if the request has a fragment! so let's play defensively
|
WARNING: we cannot actually check if the request has a fragment! so let's play defensively
|
||||||
|
|
|
@ -12,6 +12,7 @@ def init(options), do: options
|
||||||
|
|
||||||
def call(conn, _opts) do
|
def call(conn, _opts) do
|
||||||
key_id = key_id_from_conn(conn)
|
key_id = key_id_from_conn(conn)
|
||||||
|
|
||||||
unless is_nil(key_id) do
|
unless is_nil(key_id) do
|
||||||
SigningKey.fetch_remote_key(key_id)
|
SigningKey.fetch_remote_key(key_id)
|
||||||
# now we SHOULD have the user that owns the key locally. maybe.
|
# now we SHOULD have the user that owns the key locally. maybe.
|
||||||
|
|
|
@ -139,12 +139,17 @@ defp maybe_require_signature(
|
||||||
defp maybe_require_signature(conn), do: conn
|
defp maybe_require_signature(conn), do: conn
|
||||||
|
|
||||||
defp signature_host(conn) do
|
defp signature_host(conn) do
|
||||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
with {:key_id, %{"keyId" => kid}} <- {:key_id, HTTPSignatures.signature_for_conn(conn)},
|
||||||
{:ok, actor_id} <- Signature.key_id_to_actor_id(kid) do
|
{:actor_id, {:ok, actor_id}} <- {:actor_id, Signature.key_id_to_actor_id(kid)} do
|
||||||
actor_id
|
actor_id
|
||||||
else
|
else
|
||||||
e ->
|
{:key_id, e} ->
|
||||||
{:error, e}
|
Logger.error("Failed to extract key_id from signature: #{inspect(e)}")
|
||||||
|
nil
|
||||||
|
|
||||||
|
{:actor_id, e} ->
|
||||||
|
Logger.error("Failed to extract actor_id from signature: #{inspect(e)}")
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -609,8 +609,10 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn} do
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||||
|
|
||||||
sender_url = data["actor"]
|
sender_url = data["actor"]
|
||||||
sender = insert(:user, ap_id: data["actor"])
|
|
||||||
|> with_signing_key()
|
sender =
|
||||||
|
insert(:user, ap_id: data["actor"])
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
Instances.set_consistently_unreachable(sender_url)
|
Instances.set_consistently_unreachable(sender_url)
|
||||||
refute Instances.reachable?(sender_url)
|
refute Instances.reachable?(sender_url)
|
||||||
|
@ -976,8 +978,10 @@ test "it accepts announces with to as string instead of array", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
{:ok, post} = CommonAPI.post(user, %{status: "hey"})
|
{:ok, post} = CommonAPI.post(user, %{status: "hey"})
|
||||||
announcer = insert(:user, local: false)
|
|
||||||
|> with_signing_key()
|
announcer =
|
||||||
|
insert(:user, local: false)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
data = %{
|
data = %{
|
||||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
@ -1007,8 +1011,10 @@ test "it accepts messages from actors that are followed by the user", %{
|
||||||
data: data
|
data: data
|
||||||
} do
|
} do
|
||||||
recipient = insert(:user)
|
recipient = insert(:user)
|
||||||
actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
|
|
||||||
|> with_signing_key()
|
actor =
|
||||||
|
insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
{:ok, recipient, actor} = User.follow(recipient, actor)
|
{:ok, recipient, actor} = User.follow(recipient, actor)
|
||||||
|
|
||||||
|
@ -1061,8 +1067,10 @@ test "it returns a note activity in a collection", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
|
test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
|
||||||
user = insert(:user)
|
user =
|
||||||
|> with_signing_key()
|
insert(:user)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
data = Map.put(data, "bcc", [user.ap_id])
|
data = Map.put(data, "bcc", [user.ap_id])
|
||||||
|
|
||||||
sender_host = URI.parse(data["actor"]).host
|
sender_host = URI.parse(data["actor"]).host
|
||||||
|
@ -1085,7 +1093,6 @@ test "it removes all follower collections but actor's", %{conn: conn} do
|
||||||
[actor, recipient] = insert_pair(:user)
|
[actor, recipient] = insert_pair(:user)
|
||||||
actor = with_signing_key(actor)
|
actor = with_signing_key(actor)
|
||||||
|
|
||||||
|
|
||||||
to = [
|
to = [
|
||||||
recipient.ap_id,
|
recipient.ap_id,
|
||||||
recipient.follower_address,
|
recipient.follower_address,
|
||||||
|
@ -1149,8 +1156,11 @@ test "it requires authentication", %{conn: conn} do
|
||||||
@tag capture_log: true
|
@tag capture_log: true
|
||||||
test "forwarded report", %{conn: conn} do
|
test "forwarded report", %{conn: conn} do
|
||||||
admin = insert(:user, is_admin: true)
|
admin = insert(:user, is_admin: true)
|
||||||
actor = insert(:user, local: false)
|
|
||||||
|> with_signing_key()
|
actor =
|
||||||
|
insert(:user, local: false)
|
||||||
|
|> with_signing_key()
|
||||||
|
|
||||||
remote_domain = URI.parse(actor.ap_id).host
|
remote_domain = URI.parse(actor.ap_id).host
|
||||||
reported_user = insert(:user)
|
reported_user = insert(:user)
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,15 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
|
||||||
import Phoenix.Controller, only: [put_format: 2]
|
import Phoenix.Controller, only: [put_format: 2]
|
||||||
import Mock
|
import Mock
|
||||||
|
|
||||||
|
setup do
|
||||||
|
user =
|
||||||
|
:user
|
||||||
|
|> insert(%{ ap_id: "http://mastodon.example.org/users/admin" })
|
||||||
|
|> with_signing_key(%{ key_id: "http://mastodon.example.org/users/admin#main-key" })
|
||||||
|
|
||||||
|
{:ok, %{user: user}}
|
||||||
|
end
|
||||||
|
|
||||||
setup_with_mocks([
|
setup_with_mocks([
|
||||||
{HTTPSignatures, [],
|
{HTTPSignatures, [],
|
||||||
[
|
[
|
||||||
|
@ -46,15 +55,15 @@ defp submit_to_plug(host, method, path) do
|
||||||
|> HTTPSignaturePlug.call(%{})
|
|> HTTPSignaturePlug.call(%{})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it call HTTPSignatures to check validity if the actor signed it" do
|
test "it call HTTPSignatures to check validity if the actor signed it", %{user: user} do
|
||||||
params = %{"actor" => "http://mastodon.example.org/users/admin"}
|
params = %{"actor" => user.ap_id}
|
||||||
conn = build_conn(:get, "/doesntmattter", params)
|
conn = build_conn(:get, "/doesntmattter", params)
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> put_req_header(
|
|> put_req_header(
|
||||||
"signature",
|
"signature",
|
||||||
"keyId=\"http://mastodon.example.org/users/admin#main-key"
|
"keyId=\"#{user.signing_key.key_id}\""
|
||||||
)
|
)
|
||||||
|> put_format("activity+json")
|
|> put_format("activity+json")
|
||||||
|> HTTPSignaturePlug.call(%{})
|
|> HTTPSignaturePlug.call(%{})
|
||||||
|
|
|
@ -88,14 +88,18 @@ def user_factory(attrs \\ %{}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
attrs = Map.delete(attrs, :domain)
|
attrs = Map.delete(attrs, :domain)
|
||||||
|
|
||||||
user
|
user
|
||||||
|> Map.put(:raw_bio, user.bio)
|
|> Map.put(:raw_bio, user.bio)
|
||||||
|> Map.merge(urls)
|
|> Map.merge(urls)
|
||||||
|> merge_attributes(attrs)
|
|> merge_attributes(attrs)
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_signing_key(%User{} = user) do
|
def with_signing_key(%User{} = user, attrs \\ %{}) do
|
||||||
|
|
||||||
signing_key = build(:signing_key, %{user: user, key_id: "#{user.ap_id}#main-key"})
|
signing_key = build(:signing_key, %{user: user, key_id: "#{user.ap_id}#main-key"})
|
||||||
|
|> merge_attributes(attrs)
|
||||||
|
|
||||||
insert(signing_key)
|
insert(signing_key)
|
||||||
%{user | signing_key: signing_key}
|
%{user | signing_key: signing_key}
|
||||||
end
|
end
|
||||||
|
@ -104,6 +108,7 @@ def signing_key_factory(attrs \\ %{}) do
|
||||||
pem = Enum.random(@rsa_keys)
|
pem = Enum.random(@rsa_keys)
|
||||||
user = attrs[:user] || insert(:user)
|
user = attrs[:user] || insert(:user)
|
||||||
{:ok, public_key} = Pleroma.User.SigningKey.private_pem_to_public_pem(pem)
|
{:ok, public_key} = Pleroma.User.SigningKey.private_pem_to_public_pem(pem)
|
||||||
|
|
||||||
%Pleroma.User.SigningKey{
|
%Pleroma.User.SigningKey{
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
public_key: public_key,
|
public_key: public_key,
|
||||||
|
|
Loading…
Reference in a new issue