diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/plugs/http_signature.ex | 49 | ||||
| -rw-r--r-- | lib/pleroma/plugs/mapped_signature_to_identity_plug.ex | 70 | ||||
| -rw-r--r-- | lib/pleroma/signature.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 1 | 
4 files changed, 92 insertions, 30 deletions
diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index e2874c469..d87fa52fa 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -3,7 +3,6 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do -  alias Pleroma.Web.ActivityPub.Utils    import Plug.Conn    require Logger @@ -16,38 +15,30 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do    end    def call(conn, _opts) do -    user = Utils.get_ap_id(conn.params["actor"]) -    Logger.debug("Checking sig for #{user}")      [signature | _] = get_req_header(conn, "signature") -    cond do -      signature && String.contains?(signature, user) -> -        # set (request-target) header to the appropriate value -        # we also replace the digest header with the one we computed -        conn = -          conn -          |> put_req_header( -            "(request-target)", -            String.downcase("#{conn.method}") <> " #{conn.request_path}" -          ) - -        conn = -          if conn.assigns[:digest] do -            conn -            |> put_req_header("digest", conn.assigns[:digest]) -          else -            conn -          end - -        assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) +    if signature do +      # set (request-target) header to the appropriate value +      # we also replace the digest header with the one we computed +      conn = +        conn +        |> put_req_header( +          "(request-target)", +          String.downcase("#{conn.method}") <> " #{conn.request_path}" +        ) -      signature -> -        Logger.debug("Signature not from actor") -        assign(conn, :valid_signature, false) +      conn = +        if conn.assigns[:digest] do +          conn +          |> put_req_header("digest", conn.assigns[:digest]) +        else +          conn +        end -      true -> -        Logger.debug("No signature header!") -        conn +      assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) +    else +      Logger.debug("No signature header!") +      conn      end    end  end diff --git a/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex b/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex new file mode 100644 index 000000000..ce8494b9d --- /dev/null +++ b/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex @@ -0,0 +1,70 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do +  alias Pleroma.Signature +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.Utils + +  import Plug.Conn +  require Logger + +  def init(options), do: options + +  defp key_id_from_conn(conn) do +    with %{"keyId" => key_id} <- HTTPSignatures.signature_for_conn(conn) do +      Signature.key_id_to_actor_id(key_id) +    else +      _ -> +        nil +    end +  end + +  defp user_from_key_id(conn) do +    with key_actor_id when is_binary(key_actor_id) <- key_id_from_conn(conn), +         {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(key_actor_id) do +      user +    else +      _ -> +        nil +    end +  end + +  def call(%{assigns: %{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 +    with actor_id <- Utils.get_ap_id(actor), +         {:user, %User{} = user} <- {:user, user_from_key_id(conn)}, +         {:user_match, true} <- {:user_match, user.ap_id == actor_id} do +      assign(conn, :user, user) +    else +      {:user_match, false} -> +        Logger.debug("Failed to map identity from signature (payload actor mismatch)") +        Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}") +        assign(conn, :valid_signature, false) + +      # remove me once testsuite uses mapped capabilities instead of what we do now +      {:user, nil} -> +        Logger.debug("Failed to map identity from signature (lookup failure)") +        Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}") +        conn +    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) do +      assign(conn, :user, user) +    else +      _ -> +        Logger.debug("Failed to map identity from signature (no payload actor mismatch)") +        Logger.debug("key_id=#{key_id_from_conn(conn)}") +        assign(conn, :valid_signature, false) +    end +  end + +  # no signature at all +  def call(conn, _opts), do: conn +end diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index a45c70a9d..2a0823ecf 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Signature do    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub -  defp key_id_to_actor_id(key_id) do +  def key_id_to_actor_id(key_id) do      URI.parse(key_id)      |> Map.put(:fragment, nil)      |> URI.to_string() diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8095ac4b1..518720d38 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -617,6 +617,7 @@ defmodule Pleroma.Web.Router do    pipeline :activitypub do      plug(:accepts, ["activity+json", "json"])      plug(Pleroma.Web.Plugs.HTTPSignaturePlug) +    plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)    end    scope "/", Pleroma.Web.ActivityPub do  | 
