diff --git a/CHANGELOG.md b/CHANGELOG.md
index 73346617e..6b99a0e3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Non-admin users now cannot register `admin` scope tokens (not security-critical, they didn't work before, but you _could_ create them)
- Admin scopes will be dropped on create
- Rich media will now backoff for 20 minutes after a failure
+- Simplified HTTP signature processing
### Fixed
- /api/v1/accounts/lookup will now respect restrict\_unauthenticated
diff --git a/lib/pleroma/web/o_auth/scopes.ex b/lib/pleroma/web/o_auth/scopes.ex
index d5e7c29d6..344ecd631 100644
--- a/lib/pleroma/web/o_auth/scopes.ex
+++ b/lib/pleroma/web/o_auth/scopes.ex
@@ -61,7 +61,7 @@ def to_string(scopes), do: Enum.join(scopes, " ")
def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []],
do: {:error, :missing_scopes}
- def validate(scopes, app_scopes, %Pleroma.User{is_admin: is_admin}) do
+ def validate(scopes, app_scopes, _user) do
validate_scopes_are_supported(scopes, app_scopes)
end
diff --git a/lib/pleroma/web/plugs/ensure_http_signature_plug.ex b/lib/pleroma/web/plugs/ensure_http_signature_plug.ex
new file mode 100644
index 000000000..c75501a2d
--- /dev/null
+++ b/lib/pleroma/web/plugs/ensure_http_signature_plug.ex
@@ -0,0 +1,31 @@
+# Akkoma: Magically expressive social media
+# Copyright © 2022-2022 Akkoma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.EnsureHTTPSignaturePlug do
+ @moduledoc """
+ Ensures HTTP signature has been validated by previous plugs on ActivityPub requests.
+ """
+ import Plug.Conn
+ import Phoenix.Controller, only: [get_format: 1, text: 2]
+
+ alias Pleroma.Config
+
+ def init(options) do
+ options
+ end
+
+ def call(%{assigns: %{valid_signature: true}} = conn, _), do: conn
+
+ def call(conn, _) do
+ with true <- get_format(conn) in ["json", "activity+json"],
+ true <- Config.get([:activitypub, :authorized_fetch_mode], true) do
+ conn
+ |> put_status(:unauthorized)
+ |> text("Request not signed")
+ |> halt()
+ else
+ _ -> conn
+ end
+ end
+end
diff --git a/lib/pleroma/web/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex
index 5ed3235e2..4ffaa6e98 100644
--- a/lib/pleroma/web/plugs/http_signature_plug.ex
+++ b/lib/pleroma/web/plugs/http_signature_plug.ex
@@ -4,7 +4,7 @@
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
import Plug.Conn
- import Phoenix.Controller, only: [get_format: 1, text: 2]
+ import Phoenix.Controller, only: [get_format: 1]
alias Pleroma.Activity
alias Pleroma.Web.Router
alias Pleroma.Signature
@@ -22,7 +22,7 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
end
def call(conn, _opts) do
- if get_format(conn) == "activity+json" do
+ if get_format(conn) in ["json", "activity+json"] do
conn
|> maybe_assign_valid_signature()
|> maybe_require_signature()
@@ -113,18 +113,7 @@ defp maybe_require_signature(
conn
end
- defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn
-
- defp maybe_require_signature(conn) do
- if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do
- conn
- |> put_status(:unauthorized)
- |> text("Request not signed")
- |> halt()
- else
- conn
- end
- end
+ defp maybe_require_signature(conn), do: conn
defp signature_host(conn) do
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index f47041b0b..f984ad598 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -147,6 +147,7 @@ defmodule Pleroma.Web.Router do
pipeline :http_signature do
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
+ plug(Pleroma.Web.Plugs.EnsureHTTPSignaturePlug)
end
pipeline :static_fe do
diff --git a/test/pleroma/web/plugs/ensure_http_signature_plug_test.exs b/test/pleroma/web/plugs/ensure_http_signature_plug_test.exs
new file mode 100644
index 000000000..35dabbe1c
--- /dev/null
+++ b/test/pleroma/web/plugs/ensure_http_signature_plug_test.exs
@@ -0,0 +1,68 @@
+# Akkoma: Magically expressive social media
+# Copyright © 2022-2022 Akkoma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.EnsureHTTPSignaturePlugTest do
+ use Pleroma.Web.ConnCase
+ alias Pleroma.Web.Plugs.EnsureHTTPSignaturePlug
+
+ import Plug.Conn
+ import Phoenix.Controller, only: [put_format: 2]
+
+ import Pleroma.Tests.Helpers, only: [clear_config: 2]
+
+ describe "requires a signature when `authorized_fetch_mode` is enabled" do
+ setup do
+ clear_config([:activitypub, :authorized_fetch_mode], true)
+
+ conn =
+ build_conn(:get, "/doesntmatter")
+ |> put_format("activity+json")
+
+ [conn: conn]
+ end
+
+ test "and signature has been set as invalid", %{conn: conn} do
+ conn =
+ conn
+ |> assign(:valid_signature, false)
+ |> EnsureHTTPSignaturePlug.call(%{})
+
+ assert conn.halted == true
+ assert conn.status == 401
+ assert conn.state == :sent
+ assert conn.resp_body == "Request not signed"
+ end
+
+ test "and signature has been set as valid", %{conn: conn} do
+ conn =
+ conn
+ |> assign(:valid_signature, true)
+ |> EnsureHTTPSignaturePlug.call(%{})
+
+ assert conn.halted == false
+ end
+
+ test "does nothing for non-ActivityPub content types", %{conn: conn} do
+ conn =
+ conn
+ |> assign(:valid_signature, false)
+ |> put_format("html")
+ |> EnsureHTTPSignaturePlug.call(%{})
+
+ assert conn.halted == false
+ end
+ end
+
+ test "does nothing on invalid signature when `authorized_fetch_mode` is disabled" do
+ clear_config([:activitypub, :authorized_fetch_mode], false)
+
+ conn =
+ build_conn(:get, "/doesntmatter")
+ |> put_format("activity+json")
+ |> assign(:valid_signature, false)
+ |> EnsureHTTPSignaturePlug.call(%{})
+
+ assert conn.halted == false
+ end
+end
diff --git a/test/pleroma/web/plugs/http_signature_plug_test.exs b/test/pleroma/web/plugs/http_signature_plug_test.exs
index 49e0b9808..34d0dc00e 100644
--- a/test/pleroma/web/plugs/http_signature_plug_test.exs
+++ b/test/pleroma/web/plugs/http_signature_plug_test.exs
@@ -108,10 +108,6 @@ test "and signature is present and incorrect", %{conn: conn} do
|> HTTPSignaturePlug.call(%{})
assert conn.assigns.valid_signature == false
- assert conn.halted == true
- assert conn.status == 401
- assert conn.state == :sent
- assert conn.resp_body == "Request not signed"
assert called(HTTPSignatures.validate_conn(:_))
end
@@ -125,17 +121,12 @@ test "and signature is correct", %{conn: conn} do
|> HTTPSignaturePlug.call(%{})
assert conn.assigns.valid_signature == true
- assert conn.halted == false
assert called(HTTPSignatures.validate_conn(:_))
end
test "and halts the connection when `signature` header is not present", %{conn: conn} do
conn = HTTPSignaturePlug.call(conn, %{})
assert conn.assigns[:valid_signature] == nil
- assert conn.halted == true
- assert conn.status == 401
- assert conn.state == :sent
- assert conn.resp_body == "Request not signed"
end
end