c6d531086ec878844a84fd21bd1e40cbd1bcead3
[anni] / lib / pleroma / web / plugs / mapped_signature_to_identity_plug.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do
6   alias Pleroma.Helpers.AuthHelper
7   alias Pleroma.Signature
8   alias Pleroma.User
9   alias Pleroma.Web.ActivityPub.Utils
10
11   import Plug.Conn
12   require Logger
13
14   def init(options), do: options
15
16   def call(%{assigns: %{user: %User{}}} = conn, _opts), do: conn
17
18   # if this has payload make sure it is signed by the same actor that made it
19   def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
20     with actor_id <- Utils.get_ap_id(actor),
21          {:user, %User{} = user} <- {:user, user_from_key_id(conn)},
22          {:user_match, true} <- {:user_match, user.ap_id == actor_id} do
23       conn
24       |> assign(:user, user)
25       |> AuthHelper.skip_oauth()
26     else
27       {:user_match, false} ->
28         Logger.debug("Failed to map identity from signature (payload actor mismatch)")
29         Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{inspect(actor)}")
30         assign(conn, :valid_signature, false)
31
32       # remove me once testsuite uses mapped capabilities instead of what we do now
33       {:user, nil} ->
34         Logger.debug("Failed to map identity from signature (lookup failure)")
35         Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}")
36         conn
37     end
38   end
39
40   # no payload, probably a signed fetch
41   def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
42     with %User{} = user <- user_from_key_id(conn) do
43       conn
44       |> assign(:user, user)
45       |> AuthHelper.skip_oauth()
46     else
47       _ ->
48         Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
49         Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
50         assign(conn, :valid_signature, false)
51     end
52   end
53
54   # no signature at all
55   def call(conn, _opts), do: conn
56
57   defp key_id_from_conn(conn) do
58     with %{"keyId" => key_id} <- HTTPSignatures.signature_for_conn(conn),
59          {:ok, ap_id} <- Signature.key_id_to_actor_id(key_id) do
60       ap_id
61     else
62       _ ->
63         nil
64     end
65   end
66
67   defp user_from_key_id(conn) do
68     with key_actor_id when is_binary(key_actor_id) <- key_id_from_conn(conn),
69          {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(key_actor_id) do
70       user
71     else
72       _ ->
73         nil
74     end
75   end
76 end