Adapt to new http_signature API
This commit is contained in:
parent
fefc884f22
commit
f2ca71f1ad
12 changed files with 206 additions and 262 deletions
|
|
@ -233,9 +233,9 @@ defp make_signature(id, date) do
|
|||
signature =
|
||||
InternalFetchActor.get_actor()
|
||||
|> Signature.sign(%{
|
||||
"(request-target)": "get #{uri.path}",
|
||||
host: uri.host,
|
||||
date: date
|
||||
"(request-target)" => "get #{uri.path}",
|
||||
"host" => uri.host,
|
||||
"date" => date
|
||||
})
|
||||
|
||||
{"signature", signature}
|
||||
|
|
|
|||
|
|
@ -5,44 +5,55 @@
|
|||
defmodule Pleroma.Signature do
|
||||
@behaviour HTTPSignatures.Adapter
|
||||
|
||||
alias HTTPSignatures.HTTPKey
|
||||
alias Pleroma.User
|
||||
alias Pleroma.User.SigningKey
|
||||
require Logger
|
||||
|
||||
def fetch_public_key(conn) do
|
||||
with {_, %{"keyId" => kid}} <- {:keyid, HTTPSignatures.signature_for_conn(conn)},
|
||||
{_, {:ok, %SigningKey{} = sk}, _} <-
|
||||
{:fetch, SigningKey.get_or_fetch_by_key_id(kid), kid},
|
||||
def fetch_public_key(kid, _) do
|
||||
with {_, {:ok, %SigningKey{} = sk}} <- {:fetch, SigningKey.get_or_fetch_by_key_id(kid)},
|
||||
{_, {%User{} = key_user, _}} <- {:user, {User.get_by_id(sk.user_id), sk.user_id}},
|
||||
{_, {:ok, decoded_key}} <- {:decode, SigningKey.public_key_decoded(sk)} do
|
||||
{:ok, decoded_key}
|
||||
{:ok, %HTTPKey{key: decoded_key, user_data: %{"key_user" => key_user}}}
|
||||
else
|
||||
{:fetch, error, kid} ->
|
||||
Logger.error("Failed to acquire key from signature: #{kid} #{inspect(error)}")
|
||||
{:error, {:fetch, error}}
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
handle_common_errors(e, kid, "acquire")
|
||||
end
|
||||
end
|
||||
|
||||
def refetch_public_key(conn) do
|
||||
with {_, %{"keyId" => kid}} <- {:keyid, HTTPSignatures.signature_for_conn(conn)},
|
||||
{_, {:ok, %SigningKey{} = sk}, _} <- {:fetch, SigningKey.refresh_by_key_id(kid), kid},
|
||||
def refetch_public_key(kid, _) do
|
||||
with {_, {:ok, %SigningKey{} = sk}} <- {:fetch, SigningKey.refresh_by_key_id(kid)},
|
||||
{_, {%User{} = key_user, _}} <- {:user, {User.get_by_id(sk.user_id), sk.user_id}},
|
||||
{_, {:ok, decoded_key}} <- {:decode, SigningKey.public_key_decoded(sk)} do
|
||||
{:ok, decoded_key}
|
||||
{:ok, %HTTPKey{key: decoded_key, user_data: %{"key_user" => key_user}}}
|
||||
else
|
||||
{:fetch, {:error, :too_young}, kid} ->
|
||||
{:fetch, {:error, :too_young}} ->
|
||||
Logger.debug("Refusing to refetch recently updated key: #{kid}")
|
||||
{:error, {:fetch, :too_young}}
|
||||
{:error, {:too_young, kid}}
|
||||
|
||||
{:fetch, {:error, :unknown}, kid} ->
|
||||
{:fetch, {:error, :unknown}} ->
|
||||
Logger.warning("Attempted to refresh unknown key; this should not happen: #{kid}")
|
||||
{:error, {:fetch, :unknown}}
|
||||
{:error, {:unknown, kid}}
|
||||
|
||||
{:fetch, error, kid} ->
|
||||
Logger.error("Failed to refresh stale key from signature: #{kid} #{inspect(error)}")
|
||||
e ->
|
||||
handle_common_errors(e, kid, "refresh stale")
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_common_errors(error, kid, action_name) do
|
||||
case error do
|
||||
{:fetch, {:error, :not_found}} ->
|
||||
{:halt, {:error, :gone}}
|
||||
|
||||
{:fetch, error} ->
|
||||
Logger.error("Failed to #{action_name} key from signature: #{kid} #{inspect(error)}")
|
||||
{:error, {:fetch, error}}
|
||||
|
||||
{:user, {_, uid}} ->
|
||||
Logger.warning(
|
||||
"Failed to resolve user (id=#{uid}) for retrieved signing key. Race condition?"
|
||||
)
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
end
|
||||
|
|
@ -50,7 +61,11 @@ def refetch_public_key(conn) do
|
|||
|
||||
def sign(%User{} = user, headers) do
|
||||
with {:ok, private_key} <- SigningKey.private_key(user) do
|
||||
HTTPSignatures.sign(private_key, SigningKey.local_key_id(user.ap_id), headers)
|
||||
HTTPSignatures.sign(
|
||||
%HTTPKey{key: private_key},
|
||||
SigningKey.local_key_id(user.ap_id),
|
||||
headers
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,11 @@ def fetch_remote_key(key_id) do
|
|||
else
|
||||
e ->
|
||||
Logger.debug("Failed to fetch remote key: #{inspect(e)}")
|
||||
{:error, "Could not fetch key"}
|
||||
|
||||
case e do
|
||||
{:error, e} -> {:error, e}
|
||||
_ -> {:error, {"Could not fetch key", e}}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ def publish_one(
|
|||
|
||||
signature =
|
||||
Pleroma.Signature.sign(actor, %{
|
||||
"(request-target)": "post #{path}",
|
||||
host: signature_host(uri),
|
||||
"content-length": byte_size(json),
|
||||
digest: digest,
|
||||
date: date
|
||||
"(request-target)" => "post #{path}",
|
||||
"host" => signature_host(uri),
|
||||
"content-length" => byte_size(json),
|
||||
"digest" => digest,
|
||||
"date" => date
|
||||
})
|
||||
|
||||
with {:ok, %{status: code}} = result when code in 200..299 <-
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
import Plug.Conn
|
||||
import Phoenix.Controller, only: [get_format: 1]
|
||||
|
||||
alias HTTPSignatures.HTTPKey
|
||||
|
||||
use Pleroma.Web, :verified_routes
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Instances
|
||||
alias Pleroma.User.SigningKey
|
||||
require Logger
|
||||
|
||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||
|
|
@ -26,7 +27,7 @@ def call(conn, _opts) do
|
|||
if get_format(conn) in ["json", "activity+json"] do
|
||||
conn
|
||||
|> maybe_assign_valid_signature()
|
||||
|> maybe_require_signature()
|
||||
|> maybe_record_signature_success()
|
||||
else
|
||||
conn
|
||||
end
|
||||
|
|
@ -44,44 +45,46 @@ def route_aliases(%{path_info: ["objects", id], query_string: query_string}) do
|
|||
|
||||
def route_aliases(_), do: []
|
||||
|
||||
def maybe_put_created_psudoheader(conn) do
|
||||
case HTTPSignatures.signature_for_conn(conn) do
|
||||
%{"created" => created} ->
|
||||
put_req_header(conn, "(created)", created)
|
||||
defp maybe_log_error_and_try_aliases(conn, verification_error, remaining_aliases) do
|
||||
case verification_error do
|
||||
{:gone, key_id} ->
|
||||
# We can't verify the data since the actor was deleted and not previously known.
|
||||
# Likely we just received the actor’s Delete activity, so just silently drop.
|
||||
Logger.debug("Unable to verify request signature of deleted actor; dropping (#{key_id})")
|
||||
conn
|
||||
|
||||
_ ->
|
||||
:wrong_signature ->
|
||||
assign_valid_signature_on_route_aliases(conn, remaining_aliases)
|
||||
|
||||
error ->
|
||||
Logger.error("Failed to verify request signature due to fatal error: #{inspect(error)}")
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_put_expires_psudoheader(conn) do
|
||||
case HTTPSignatures.signature_for_conn(conn) do
|
||||
%{"expires" => expires} ->
|
||||
put_req_header(conn, "(expires)", expires)
|
||||
|
||||
_ ->
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(conn, []), do: conn
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(%{assigns: %{valid_signature: true}} = conn, _),
|
||||
do: conn
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(conn, []) do
|
||||
Logger.warning("Received request with invalid signature!\n#{inspect(conn)}")
|
||||
conn
|
||||
end
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(conn, [path | rest]) do
|
||||
request_target = String.downcase("#{conn.method}") <> " #{path}"
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> maybe_put_created_psudoheader()
|
||||
|> maybe_put_expires_psudoheader()
|
||||
case HTTPSignatures.validate_conn(conn, request_target) do
|
||||
{:ok, %HTTPKey{user_data: ud}} ->
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> assign(:signature_user, ud["key_user"])
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
|> assign(:signature_actor_id, signature_host(conn))
|
||||
|> assign_valid_signature_on_route_aliases(rest)
|
||||
{:error, e} ->
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
|> assign(:signature_user, nil)
|
||||
|> maybe_log_error_and_try_aliases(e, rest)
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_assign_valid_signature(conn) do
|
||||
|
|
@ -108,8 +111,8 @@ defp has_signature_header?(conn) do
|
|||
conn |> get_req_header("signature") |> Enum.at(0, false)
|
||||
end
|
||||
|
||||
defp maybe_require_signature(
|
||||
%{assigns: %{valid_signature: true, signature_actor_id: actor_id}} = conn
|
||||
defp maybe_record_signature_success(
|
||||
%{assigns: %{valid_signature: true, signature_user: signature_user}} = conn
|
||||
) do
|
||||
# inboxes implicitly need http signatures for authentication
|
||||
# so we don't really know if the instance will have broken federation after
|
||||
|
|
@ -117,7 +120,7 @@ defp maybe_require_signature(
|
|||
#
|
||||
# to "check" this is a signed fetch, verify if method is GET
|
||||
if conn.method == "GET" do
|
||||
actor_host = URI.parse(actor_id).host
|
||||
actor_host = URI.parse(signature_user.ap_id).host
|
||||
|
||||
case @cachex.get(:request_signatures_cache, actor_host) do
|
||||
{:ok, nil} ->
|
||||
|
|
@ -138,22 +141,5 @@ defp maybe_require_signature(
|
|||
conn
|
||||
end
|
||||
|
||||
defp maybe_require_signature(conn), do: conn
|
||||
|
||||
defp signature_host(conn) do
|
||||
with {:key_id, %{"keyId" => kid}} <- {:key_id, HTTPSignatures.signature_for_conn(conn)},
|
||||
{:actor_id, actor_id, _} when actor_id != nil <-
|
||||
{:actor_id, SigningKey.key_id_to_ap_id(kid), kid} do
|
||||
actor_id
|
||||
else
|
||||
{:key_id, e} ->
|
||||
Logger.error("Failed to extract key_id from signature: #{inspect(e)}")
|
||||
nil
|
||||
|
||||
{:actor_id, _, kid} ->
|
||||
# SigningKeys SHOULD have been fetched before this gets called!
|
||||
Logger.error("Failed to extract actor_id from signature: signing key #{kid} not known")
|
||||
nil
|
||||
end
|
||||
end
|
||||
defp maybe_record_signature_success(conn), do: conn
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,101 +15,60 @@ def init(options), do: options
|
|||
def call(%{assigns: %{user: %User{}}} = conn, _opts), do: conn
|
||||
|
||||
# if this has payload make sure it is signed by the same actor that made it
|
||||
def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
|
||||
def call(
|
||||
%{
|
||||
assigns: %{valid_signature: true, signature_user: signature_user},
|
||||
params: %{"actor" => actor}
|
||||
} = conn,
|
||||
_opts
|
||||
) do
|
||||
with actor_id <- Utils.get_ap_id(actor),
|
||||
{:user, %User{} = user} <- {:user, user_from_key_id(conn)},
|
||||
{:federate, true} <- {:federate, should_federate?(user)},
|
||||
{:user_match, true} <- {:user_match, user.ap_id == actor_id} do
|
||||
{:federate, true} <- {:federate, should_federate?(signature_user)},
|
||||
{:user_match, true} <- {:user_match, signature_user.ap_id == actor_id} do
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> assign(:user, signature_user)
|
||||
|> AuthHelper.skip_oauth()
|
||||
else
|
||||
{:user_match, false} ->
|
||||
Logger.debug("Failed to map identity from signature (payload actor mismatch)")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{inspect(actor)}")
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
Logger.debug(
|
||||
"key_user=#{signature_user.id}(#{signature_user.ap_id}), actor=#{inspect(actor)}"
|
||||
)
|
||||
|
||||
# remove me once testsuite uses mapped capabilities instead of what we do now
|
||||
{:user, _} ->
|
||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}")
|
||||
assign(conn, :valid_signature, false)
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
|
||||
{:federate, false} ->
|
||||
Logger.debug("Identity from signature is instance blocked")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}")
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
error ->
|
||||
handle_common_errors(conn, actor, signature_user, error)
|
||||
end
|
||||
end
|
||||
|
||||
# no payload, probably a signed fetch
|
||||
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||
with %User{} = user <- user_from_key_id(conn),
|
||||
{:federate, true} <- {:federate, should_federate?(user)} do
|
||||
def call(%{assigns: %{valid_signature: true, signature_user: signature_user}} = conn, _opts) do
|
||||
with {:federate, true} <- {:federate, should_federate?(signature_user)} do
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> assign(:user, signature_user)
|
||||
|> AuthHelper.skip_oauth()
|
||||
else
|
||||
{:federate, false} ->
|
||||
Logger.debug("Identity from signature is instance blocked")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
|
||||
nil ->
|
||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
|
||||
_ ->
|
||||
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
||||
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, false)
|
||||
error -> handle_common_errors(conn, nil, signature_user, error)
|
||||
end
|
||||
end
|
||||
|
||||
# supposedly valid signature but no user (this isn’t supposed to happen)
|
||||
def call(%{assigns: %{valid_signature: true}} = conn, _opts),
|
||||
do: assign(conn, :valid_signature, false)
|
||||
|
||||
# no signature at all
|
||||
def call(conn, _opts), do: conn
|
||||
|
||||
defp key_id_from_conn(conn) do
|
||||
case HTTPSignatures.signature_for_conn(conn) do
|
||||
%{"keyId" => key_id} when is_binary(key_id) ->
|
||||
key_id
|
||||
def handle_common_errors(conn, actor, signature_user, error) do
|
||||
actor_str = if actor == nil, do: "", else: " actor=#{inspect(actor)}"
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp user_from_key_id(conn) do
|
||||
with {:key_id, key_id} when is_binary(key_id) <- {:key_id, key_id_from_conn(conn)},
|
||||
{:mapped_ap_id, ap_id} when is_binary(ap_id) <-
|
||||
{:mapped_ap_id, User.SigningKey.key_id_to_ap_id(key_id)},
|
||||
{:user_fetch, {:ok, %User{} = user}} <- {:user_fetch, User.get_or_fetch_by_ap_id(ap_id)} do
|
||||
user
|
||||
else
|
||||
{:key_id, nil} ->
|
||||
Logger.debug("Failed to map identity from signature (no key ID)")
|
||||
{:key_id, nil}
|
||||
|
||||
{:mapped_ap_id, nil} ->
|
||||
Logger.debug("Failed to map identity from signature (could not map key ID to AP ID)")
|
||||
{:mapped_ap_id, nil}
|
||||
|
||||
{:user_fetch, {:error, _}} ->
|
||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||
{:user_fetch, nil}
|
||||
case error do
|
||||
{:federate, false} ->
|
||||
Logger.debug("Identity from signature is instance blocked")
|
||||
Logger.debug("key_user=#{signature_user.nickname}(#{signature_user.id})#{actor_str}")
|
||||
assign(conn, :valid_signature, false)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
4
mix.exs
4
mix.exs
|
|
@ -161,8 +161,8 @@ defp deps do
|
|||
{:ueberauth, "== 0.10.5"},
|
||||
{:linkify, "~> 0.5.3"},
|
||||
{:http_signatures,
|
||||
git: "https://akkoma.dev/AkkomaGang/http_signatures.git",
|
||||
ref: "d44c43d66758c6a73eaa4da9cffdbee0c5da44ae"},
|
||||
git: "https://akkoma.dev/Oneric/http_signatures.git",
|
||||
ref: "6a9d2f368bda48413009d7cdcf7d163e5658366e"},
|
||||
{:telemetry, "~> 1.2"},
|
||||
{:telemetry_poller, "~> 1.0"},
|
||||
{:telemetry_metrics, "~> 0.6"},
|
||||
|
|
|
|||
2
mix.lock
2
mix.lock
|
|
@ -58,7 +58,7 @@
|
|||
"hackney": {:hex, :hackney, "1.23.0", "55cc09077112bcb4a69e54be46ed9bc55537763a96cd4a80a221663a7eafd767", [:rebar3], [{:certifi, "~> 2.14.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "6cd1c04cd15c81e5a493f167b226a15f0938a84fc8f0736ebe4ddcab65c0b44e"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
||||
"http_signatures": {:git, "https://akkoma.dev/AkkomaGang/http_signatures.git", "d44c43d66758c6a73eaa4da9cffdbee0c5da44ae", [ref: "d44c43d66758c6a73eaa4da9cffdbee0c5da44ae"]},
|
||||
"http_signatures": {:git, "https://akkoma.dev/Oneric/http_signatures.git", "6a9d2f368bda48413009d7cdcf7d163e5658366e", [ref: "6a9d2f368bda48413009d7cdcf7d163e5658366e"]},
|
||||
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"igniter": {:hex, :igniter, "0.5.29", "6bf7ddaf15e88ae75f6dad514329530ec8f4721ba14782f6386a7345c1be99fd", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "beb6e0f69fc6d4e3975ffa26c5459fc63fd96f85cfaeba984c2dfd3d7333b6ad"},
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ defmodule Pleroma.SignatureTest do
|
|||
import Tesla.Mock
|
||||
import Mock
|
||||
|
||||
alias HTTPSignatures.HTTPKey
|
||||
alias Pleroma.Signature
|
||||
alias Pleroma.User.SigningKey
|
||||
|
||||
setup do
|
||||
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
|
|
@ -28,20 +30,27 @@ defmodule Pleroma.SignatureTest do
|
|||
65_537
|
||||
}
|
||||
|
||||
defp make_fake_signature(key_id), do: "keyId=\"#{key_id}\""
|
||||
defp keyid(user = %Pleroma.User{}), do: keyid(user.ap_id)
|
||||
defp keyid(user_ap_id), do: user_ap_id <> "#main-key"
|
||||
|
||||
defp make_fake_conn(key_id),
|
||||
do: %Plug.Conn{req_headers: %{"signature" => make_fake_signature(key_id <> "#main-key")}}
|
||||
defp assert_key(retval, refkey, refuser) do
|
||||
assert match?(
|
||||
{:ok, %HTTPKey{key: ^refkey, user_data: %{"key_user" => %Pleroma.User{}}}},
|
||||
retval
|
||||
)
|
||||
|
||||
{:ok, key} = retval
|
||||
# Avoid comparison failures from (not) loaded Ecto associations etc
|
||||
assert refuser.id == key.user_data["key_user"].id
|
||||
end
|
||||
|
||||
describe "fetch_public_key/1" do
|
||||
test "it returns the key" do
|
||||
expected_result = {:ok, @rsa_public_key}
|
||||
|
||||
user =
|
||||
insert(:user)
|
||||
|> with_signing_key(public_key: @public_key)
|
||||
|
||||
assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == expected_result
|
||||
assert_key(Signature.fetch_public_key(keyid(user), nil), @rsa_public_key, user)
|
||||
end
|
||||
|
||||
test "it returns error if public key is nil" do
|
||||
|
|
@ -50,7 +59,7 @@ test "it returns error if public key is nil" do
|
|||
key_id = user.ap_id <> "#main-key"
|
||||
Tesla.Mock.mock(fn %{url: ^key_id} -> {:ok, %{status: 404}} end)
|
||||
|
||||
assert {:error, _} = Signature.fetch_public_key(make_fake_conn(user.ap_id))
|
||||
assert {:error, _} = Signature.fetch_public_key(keyid(user), nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -60,16 +69,17 @@ test "it returns key" do
|
|||
ap_id = "https://mastodon.social/users/lambadalambda"
|
||||
|
||||
%Pleroma.User{signing_key: sk} =
|
||||
user =
|
||||
Pleroma.User.get_or_fetch_by_ap_id(ap_id)
|
||||
|> then(fn {:ok, u} -> u end)
|
||||
|> Pleroma.User.SigningKey.load_key()
|
||||
|> SigningKey.load_key()
|
||||
|
||||
{:ok, _} =
|
||||
%{sk | public_key: "-----BEGIN PUBLIC KEY-----\nasdfghjkl"}
|
||||
|> Ecto.Changeset.change()
|
||||
|> Pleroma.Repo.update()
|
||||
|
||||
assert Signature.refetch_public_key(make_fake_conn(ap_id)) == {:ok, @rsa_public_key}
|
||||
assert_key(Signature.refetch_public_key(keyid(ap_id), nil), @rsa_public_key, user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -111,8 +121,8 @@ test "it returns signature headers" do
|
|||
|> with_signing_key(private_key: @private_key)
|
||||
|
||||
headers = %{
|
||||
host: "test.test",
|
||||
"content-length": "100"
|
||||
"host" => "test.test",
|
||||
"content-length" => "100"
|
||||
}
|
||||
|
||||
assert_signature_equal(
|
||||
|
|
|
|||
|
|
@ -555,14 +555,12 @@ test "cached purged after activity deletion", %{conn: conn} do
|
|||
describe "/inbox" do
|
||||
test "it inserts an incoming activity into the database", %{conn: conn} do
|
||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||
{:ok, actor} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header(
|
||||
"signature",
|
||||
"keyId=\"http://mastodon.example.org/users/admin#main-key\""
|
||||
)
|
||||
|> assign(:signature_user, actor)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|
||||
|
|
@ -592,7 +590,7 @@ test "it inserts an incoming activity into the database" <>
|
|||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{user.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, user)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|
||||
|
|
@ -617,7 +615,7 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn} do
|
|||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{sender.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|
||||
|
|
@ -642,7 +640,7 @@ test "accept follow activity", %{conn: conn} do
|
|||
assert "ok" ==
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{followed_relay.ap_id}#main-key\"")
|
||||
|> assign(:signature_user, followed_relay)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", accept)
|
||||
|> json_response(200)
|
||||
|
|
@ -681,10 +679,11 @@ test "accepts Add/Remove activities", %{conn: conn} do
|
|||
actor = "https://example.com/users/lain"
|
||||
key_id = "#{actor}#main-key"
|
||||
|
||||
insert(:user,
|
||||
ap_id: actor,
|
||||
featured_address: "https://example.com/users/lain/collections/featured"
|
||||
)
|
||||
sender =
|
||||
insert(:user,
|
||||
ap_id: actor,
|
||||
featured_address: "https://example.com/users/lain/collections/featured"
|
||||
)
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{
|
||||
|
|
@ -741,7 +740,7 @@ test "accepts Add/Remove activities", %{conn: conn} do
|
|||
assert "ok" ==
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -764,7 +763,7 @@ test "accepts Add/Remove activities", %{conn: conn} do
|
|||
assert "ok" ==
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor}#main-key\"")
|
||||
|> assign(:signature_user, user)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -863,7 +862,7 @@ test "mastodon pin/unpin", %{conn: conn} do
|
|||
assert "ok" ==
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{sender.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -883,7 +882,7 @@ test "mastodon pin/unpin", %{conn: conn} do
|
|||
assert "ok" ==
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -912,10 +911,12 @@ test "it inserts an incoming activity into the database", %{conn: conn, data: da
|
|||
|> Map.put("bcc", [user.ap_id])
|
||||
|> Kernel.put_in(["object", "bcc"], [user.ap_id])
|
||||
|
||||
{:ok, sender} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{data["actor"]}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -936,10 +937,12 @@ test "it accepts messages with to as string instead of array", %{conn: conn, dat
|
|||
|> Kernel.put_in(["object", "to"], user.ap_id)
|
||||
|> Kernel.put_in(["object", "cc"], [])
|
||||
|
||||
{:ok, sender} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{data["actor"]}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -958,10 +961,12 @@ test "it accepts messages with cc as string instead of array", %{conn: conn, dat
|
|||
|> Kernel.put_in(["object", "to"], [])
|
||||
|> Kernel.put_in(["object", "cc"], user.ap_id)
|
||||
|
||||
{:ok, sender} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{data["actor"]}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -985,10 +990,12 @@ test "it accepts messages with bcc as string instead of array", %{conn: conn, da
|
|||
|> Kernel.put_in(["object", "cc"], [])
|
||||
|> Kernel.put_in(["object", "bcc"], user.ap_id)
|
||||
|
||||
{:ok, sender} = User.get_or_fetch_by_ap_id(data["actor"])
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{data["actor"]}#main-key\"")
|
||||
|> assign(:signature_user, sender)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -1019,7 +1026,7 @@ test "it accepts announces with to as string instead of array", %{conn: conn} do
|
|||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{announcer.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, announcer)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -1053,7 +1060,7 @@ test "it accepts messages from actors that are followed by the user", %{
|
|||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, actor)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{recipient.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -1103,7 +1110,7 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn, da
|
|||
conn =
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{user.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, user)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{user.nickname}/inbox", data)
|
||||
|
||||
|
|
@ -1143,7 +1150,7 @@ test "it removes all follower collections but actor's", %{conn: conn} do
|
|||
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, actor)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{recipient.nickname}/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -1239,7 +1246,7 @@ test "forwarded report", %{conn: conn} do
|
|||
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{actor.signing_key.key_id}\"")
|
||||
|> assign(:signature_user, actor)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{reported_user.nickname}/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
@ -1260,39 +1267,15 @@ test "forwarded report from mastodon", %{conn: conn} do
|
|||
admin = insert(:user, is_admin: true)
|
||||
actor = insert(:user, local: false)
|
||||
remote_domain = URI.parse(actor.ap_id).host
|
||||
remote_actor = "https://#{remote_domain}/actor"
|
||||
[reported_user, another] = insert_list(2, :user)
|
||||
|
||||
note = insert(:note_activity, user: reported_user)
|
||||
|
||||
Pleroma.Web.CommonAPI.favorite(another, note.id)
|
||||
|
||||
mock_json_body =
|
||||
"test/fixtures/mastodon/application_actor.json"
|
||||
|> File.read!()
|
||||
|> String.replace("{{DOMAIN}}", remote_domain)
|
||||
|
||||
key_url = "#{remote_actor}#main-key"
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{url: ^remote_actor} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: mock_json_body,
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}
|
||||
|
||||
%{url: ^key_url} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: mock_json_body,
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}
|
||||
end)
|
||||
|
||||
data = %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"actor" => remote_actor,
|
||||
"actor" => actor.ap_id,
|
||||
"content" => "test report",
|
||||
"id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8",
|
||||
"object" => [
|
||||
|
|
@ -1304,7 +1287,7 @@ test "forwarded report from mastodon", %{conn: conn} do
|
|||
|
||||
conn
|
||||
|> assign(:valid_signature, true)
|
||||
|> put_req_header("signature", "keyId=\"#{remote_actor}#main-key\"")
|
||||
|> assign(:signature_user, actor)
|
||||
|> put_req_header("content-type", "application/activity+json")
|
||||
|> post("/users/#{reported_user.nickname}/inbox", data)
|
||||
|> json_response(200)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
|
|||
import Phoenix.Controller, only: [put_format: 2]
|
||||
import Mock
|
||||
|
||||
@user_ap_id "http://mastodon.example.org/users/admin"
|
||||
|
||||
setup do
|
||||
user =
|
||||
:user
|
||||
|
|
@ -26,15 +28,13 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
|
|||
setup_with_mocks([
|
||||
{HTTPSignatures, [],
|
||||
[
|
||||
signature_for_conn: fn _ ->
|
||||
%{
|
||||
"keyId" => "http://mastodon.example.org/users/admin#main-key",
|
||||
"created" => "1234567890",
|
||||
"expires" => "1234567890"
|
||||
}
|
||||
end,
|
||||
validate_conn: fn conn ->
|
||||
Map.get(conn.assigns, :valid_signature, true)
|
||||
validate_conn: fn conn, _ ->
|
||||
if Map.get(conn.assigns, :valid_signature, true) do
|
||||
{:ok, user} = Pleroma.User.get_or_fetch_by_ap_id(@user_ap_id)
|
||||
{:ok, %HTTPSignatures.HTTPKey{key: "aaa", user_data: %{"key_user" => user}}}
|
||||
else
|
||||
{:error, :wrong_signature}
|
||||
end
|
||||
end
|
||||
]}
|
||||
]) do
|
||||
|
|
@ -69,9 +69,9 @@ test "it call HTTPSignatures to check validity if the actor signed it", %{user:
|
|||
|> HTTPSignaturePlug.call(%{})
|
||||
|
||||
assert conn.assigns.valid_signature == true
|
||||
assert conn.assigns.signature_actor_id == params["actor"]
|
||||
assert conn.assigns.signature_user.ap_id == params["actor"]
|
||||
assert conn.halted == false
|
||||
assert called(HTTPSignatures.validate_conn(:_))
|
||||
assert called(HTTPSignatures.validate_conn(:_, :_))
|
||||
end
|
||||
|
||||
test "it sets request signatures property on the instance" do
|
||||
|
|
@ -122,7 +122,7 @@ test "and signature is present and incorrect", %{conn: conn} do
|
|||
|> HTTPSignaturePlug.call(%{})
|
||||
|
||||
assert conn.assigns.valid_signature == false
|
||||
assert called(HTTPSignatures.validate_conn(:_))
|
||||
assert called(HTTPSignatures.validate_conn(:_, :_))
|
||||
end
|
||||
|
||||
test "and signature is correct", %{conn: conn} do
|
||||
|
|
@ -135,7 +135,7 @@ test "and signature is correct", %{conn: conn} do
|
|||
|> HTTPSignaturePlug.call(%{})
|
||||
|
||||
assert conn.assigns.valid_signature == true
|
||||
assert called(HTTPSignatures.validate_conn(:_))
|
||||
assert called(HTTPSignatures.validate_conn(:_, :_))
|
||||
end
|
||||
|
||||
test "and halts the connection when `signature` header is not present", %{conn: conn} do
|
||||
|
|
@ -154,18 +154,4 @@ test "aliases redirected /object endpoints", _ do
|
|||
assert ["/notice/#{act.id}", "/notice/#{act.id}?actor=someparam"] ==
|
||||
HTTPSignaturePlug.route_aliases(conn)
|
||||
end
|
||||
|
||||
test "(created) psudoheader", _ do
|
||||
conn = build_conn(:get, "/doesntmattter")
|
||||
conn = HTTPSignaturePlug.maybe_put_created_psudoheader(conn)
|
||||
created_header = List.keyfind(conn.req_headers, "(created)", 0)
|
||||
assert {_, "1234567890"} = created_header
|
||||
end
|
||||
|
||||
test "(expires) psudoheader", _ do
|
||||
conn = build_conn(:get, "/doesntmattter")
|
||||
conn = HTTPSignaturePlug.maybe_put_expires_psudoheader(conn)
|
||||
expires_header = List.keyfind(conn.req_headers, "(expires)", 0)
|
||||
assert {_, "1234567890"} = expires_header
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,16 +22,21 @@ defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do
|
|||
{:ok, %{user: user}}
|
||||
end
|
||||
|
||||
defp set_signature(conn, ap_id) do
|
||||
defp set_signature(conn, %Pleroma.User{} = user) do
|
||||
conn
|
||||
|> put_req_header("signature", "keyId=\"#{ap_id}#main-key\"")
|
||||
|> assign(:valid_signature, true)
|
||||
|> assign(:signature_user, user)
|
||||
end
|
||||
|
||||
defp set_signature(conn, ap_id) when is_binary(ap_id) do
|
||||
{:ok, user} = Pleroma.User.get_or_fetch_by_ap_id(ap_id)
|
||||
set_signature(conn, user)
|
||||
end
|
||||
|
||||
test "it successfully maps a valid identity with a valid signature", %{user: user} do
|
||||
conn =
|
||||
build_conn(:get, "/doesntmattter")
|
||||
|> set_signature(user.ap_id)
|
||||
|> set_signature(user)
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
refute is_nil(conn.assigns.user)
|
||||
|
|
@ -40,7 +45,7 @@ test "it successfully maps a valid identity with a valid signature", %{user: use
|
|||
test "it successfully maps a valid identity with a valid signature with payload", %{user: user} do
|
||||
conn =
|
||||
build_conn(:post, "/doesntmattter", %{"actor" => user.ap_id})
|
||||
|> set_signature(user.ap_id)
|
||||
|> set_signature(user)
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
refute is_nil(conn.assigns.user)
|
||||
|
|
@ -52,7 +57,9 @@ test "it considers a mapped identity to be invalid when it mismatches a payload"
|
|||
|> set_signature("https://niu.moe/users/rye")
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
assert %{valid_signature: false} == conn.assigns
|
||||
assert conn.assigns.valid_signature == false
|
||||
refute is_nil(conn.assigns.signature_user)
|
||||
refute match?(%{user: _}, conn.assigns)
|
||||
end
|
||||
|
||||
test "it considers a mapped identity to be invalid when the associated instance is blocked", %{
|
||||
|
|
@ -74,10 +81,12 @@ test "it considers a mapped identity to be invalid when the associated instance
|
|||
|
||||
conn =
|
||||
build_conn(:post, "/doesntmattter", %{"actor" => user.ap_id})
|
||||
|> set_signature(user.ap_id)
|
||||
|> set_signature(user)
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
assert %{valid_signature: false} == conn.assigns
|
||||
assert conn.assigns.valid_signature == false
|
||||
refute is_nil(conn.assigns.signature_user)
|
||||
refute match?(%{user: _}, conn.assigns)
|
||||
end
|
||||
|
||||
test "allowlist federation: it considers a mapped identity to be valid when the associated instance is allowed",
|
||||
|
|
@ -97,7 +106,7 @@ test "allowlist federation: it considers a mapped identity to be valid when the
|
|||
|
||||
conn =
|
||||
build_conn(:post, "/doesntmattter", %{"actor" => user.ap_id})
|
||||
|> set_signature(user.ap_id)
|
||||
|> set_signature(user)
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
assert conn.assigns[:valid_signature]
|
||||
|
|
@ -119,19 +128,11 @@ test "allowlist federation: it considers a mapped identity to be invalid when th
|
|||
|
||||
conn =
|
||||
build_conn(:post, "/doesntmattter", %{"actor" => user.ap_id})
|
||||
|> set_signature(user.ap_id)
|
||||
|> set_signature(user)
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
assert %{valid_signature: false} == conn.assigns
|
||||
end
|
||||
|
||||
@tag skip: "known breakage; the testsuite presently depends on it"
|
||||
test "it considers a mapped identity to be invalid when the identity cannot be found" do
|
||||
conn =
|
||||
build_conn(:post, "/doesntmattter", %{"actor" => "http://mastodon.example.org/users/admin"})
|
||||
|> set_signature("http://niu.moe/users/rye")
|
||||
|> MappedSignatureToIdentityPlug.call(%{})
|
||||
|
||||
assert %{valid_signature: false} == conn.assigns
|
||||
assert conn.assigns.valid_signature == false
|
||||
refute is_nil(conn.assigns.signature_user)
|
||||
refute match?(%{user: _}, conn.assigns)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue