Merge pull request 'Ensure only requests with Host header set to target instance pass through HTTP signatures.' (#7893) from phnt/pleroma:host-verification into develop
Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/7893
This commit is contained in:
commit
c5737898f5
9 changed files with 322 additions and 6 deletions
1
changelog.d/host-header-verification.security
Normal file
1
changelog.d/host-header-verification.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Ensure Host header is present and matches instance URI
|
||||||
|
|
@ -303,7 +303,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
|
def inbox(
|
||||||
|
%{
|
||||||
|
assigns: %{valid_signature: true, valid_host_header: true}
|
||||||
|
} = conn,
|
||||||
|
%{"nickname" => nickname} = params
|
||||||
|
) do
|
||||||
with {:recipient_exists, %User{} = recipient} <-
|
with {:recipient_exists, %User{} = recipient} <-
|
||||||
{:recipient_exists, User.get_cached_by_nickname(nickname)},
|
{:recipient_exists, User.get_cached_by_nickname(nickname)},
|
||||||
{:sender_exists, {:ok, %User{} = actor}} <-
|
{:sender_exists, {:ok, %User{} = actor}} <-
|
||||||
|
|
@ -342,7 +347,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
|
def inbox(%{assigns: %{valid_signature: true, valid_host_header: true}} = conn, params) do
|
||||||
Federator.incoming_ap_doc(params)
|
Federator.incoming_ap_doc(params)
|
||||||
json(conn, "ok")
|
json(conn, "ok")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
63
lib/pleroma/web/plugs/ensure_host_matches_plug.ex
Normal file
63
lib/pleroma/web/plugs/ensure_host_matches_plug.ex
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2026 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.EnsureHostMatchesPlug do
|
||||||
|
@moduledoc "Ensures Host header matches instance"
|
||||||
|
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
|
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
def init(options), do: options
|
||||||
|
|
||||||
|
@spec call(Plug.Conn.t(), Plug.opts()) :: Plug.Conn.t()
|
||||||
|
def call(%Plug.Conn{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
|
# Host header is scheme-less, URI.parse needs the //
|
||||||
|
host_header = get_req_header(conn, "host")
|
||||||
|
host_uri = URI.parse("//#{host_header}")
|
||||||
|
instance_uri = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
case host_header do
|
||||||
|
[host] ->
|
||||||
|
cond do
|
||||||
|
host == "" ->
|
||||||
|
resp(conn, 400, "Host header not provided") |> halt()
|
||||||
|
|
||||||
|
true ->
|
||||||
|
if host_matches?(host_uri, instance_uri),
|
||||||
|
do: assign(conn, :valid_host_header, true),
|
||||||
|
else: resp(conn, 400, "Host header does not match this instance") |> halt()
|
||||||
|
end
|
||||||
|
|
||||||
|
[_head | _rest] ->
|
||||||
|
conn
|
||||||
|
|> resp(400, "More than one Host header provided")
|
||||||
|
|> halt()
|
||||||
|
|
||||||
|
[] ->
|
||||||
|
conn
|
||||||
|
|> resp(400, "Host header not provided")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Host header may not be provided, but signature verification failed anyway
|
||||||
|
def call(conn, _opts), do: conn
|
||||||
|
|
||||||
|
defp case_insensitive_compare(checked, authority) do
|
||||||
|
String.downcase(checked) == String.downcase(authority)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Host header did not provide port
|
||||||
|
# Host header is scheme-less, URI.parse does not provide default port
|
||||||
|
defp host_matches?(%URI{host: req_host, port: nil}, %URI{host: instance_host}),
|
||||||
|
do: case_insensitive_compare(req_host, instance_host)
|
||||||
|
|
||||||
|
# Host header provided a port
|
||||||
|
# Any port specified in the Endpoint url configuration is valid here
|
||||||
|
defp host_matches?(%URI{host: req_host, port: port}, %URI{host: instance_host, port: port}),
|
||||||
|
do: case_insensitive_compare(req_host, instance_host)
|
||||||
|
|
||||||
|
defp host_matches?(_, _), do: false
|
||||||
|
end
|
||||||
|
|
@ -216,6 +216,7 @@ defmodule Pleroma.Web.Router do
|
||||||
pipeline :http_signature do
|
pipeline :http_signature do
|
||||||
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
||||||
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
||||||
|
plug(Pleroma.Web.Plugs.EnsureHostMatchesPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :inbox_guard do
|
pipeline :inbox_guard do
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
|
alias Pleroma.Web.Plugs.EnsureHostMatchesPlug
|
||||||
alias Pleroma.Web.Plugs.MappedSignatureToIdentityPlug
|
alias Pleroma.Web.Plugs.MappedSignatureToIdentityPlug
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
@ -48,6 +49,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
|
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
|
||||||
{:signature, true} <- {:signature, validate_signature(conn_data)},
|
{:signature, true} <- {:signature, validate_signature(conn_data)},
|
||||||
{:same_actor, true} <- {:same_actor, validate_same_actor(conn_data)},
|
{:same_actor, true} <- {:same_actor, validate_same_actor(conn_data)},
|
||||||
|
{:host_header, true} <- {:host_header, validate_host_header(conn_data)},
|
||||||
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
||||||
unless Instances.reachable?(params["actor"]) do
|
unless Instances.reachable?(params["actor"]) do
|
||||||
domain = URI.parse(params["actor"]).host
|
domain = URI.parse(params["actor"]).host
|
||||||
|
|
@ -103,6 +105,16 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_host_header(conn_data) do
|
||||||
|
case EnsureHostMatchesPlug.call(conn_data, []) do
|
||||||
|
%Plug.Conn{assigns: %{valid_signature: true, valid_host_header: true}} ->
|
||||||
|
true
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp validate_same_actor(conn_data) do
|
defp validate_same_actor(conn_data) do
|
||||||
case MappedSignatureToIdentityPlug.call(conn_data, []) do
|
case MappedSignatureToIdentityPlug.call(conn_data, []) do
|
||||||
%Plug.Conn{assigns: %{valid_signature: true}} ->
|
%Plug.Conn{assigns: %{valid_signature: true}} ->
|
||||||
|
|
@ -170,6 +182,10 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
{:same_actor, false} ->
|
{:same_actor, false} ->
|
||||||
{:cancel, :actor_signature_mismatch}
|
{:cancel, :actor_signature_mismatch}
|
||||||
|
|
||||||
|
# Host header from request not for us
|
||||||
|
{:host_header, false} ->
|
||||||
|
{:cancel, :host_header_mismatch}
|
||||||
|
|
||||||
# Origin / URL validation failed somewhere possibly due to spoofing
|
# Origin / URL validation failed somewhere possibly due to spoofing
|
||||||
{:error, :origin_containment_failed} ->
|
{:error, :origin_containment_failed} ->
|
||||||
{:cancel, :origin_containment_failed}
|
{:cancel, :origin_containment_failed}
|
||||||
|
|
@ -234,6 +250,7 @@ defmodule Pleroma.Workers.SignatureRetryWorker do
|
||||||
defp log_signature_retry_rejection({:cancel, reason}, context)
|
defp log_signature_retry_rejection({:cancel, reason}, context)
|
||||||
when reason in [
|
when reason in [
|
||||||
:actor_signature_mismatch,
|
:actor_signature_mismatch,
|
||||||
|
:host_header_mismatch,
|
||||||
:invalid_signature,
|
:invalid_signature,
|
||||||
:invalid_signature_retry_metadata,
|
:invalid_signature_retry_metadata,
|
||||||
:missing_signature_retry_metadata,
|
:missing_signature_retry_metadata,
|
||||||
|
|
|
||||||
|
|
@ -950,6 +950,50 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
||||||
refute Activity.get_by_ap_id(data["id"])
|
refute Activity.get_by_ap_id(data["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "does not process post with Host header not for us", %{conn: conn} do
|
||||||
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
object_id = "https://one.com/objects/inbox-forged-note"
|
||||||
|
|
||||||
|
data = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"id" => "https://one.com/activities/inbox-forged-create",
|
||||||
|
"context" => "https://one.com/contexts/inbox-forged-create",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => [],
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"id" => object_id,
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"attributedTo" => alice.ap_id,
|
||||||
|
"context" => "https://one.com/contexts/inbox-forged-create",
|
||||||
|
"content" => "forged post",
|
||||||
|
"published" => "2024-07-25T13:33:31Z",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Plug will complain when replacing raw host header with put_req_header.
|
||||||
|
# The Plug way is updating conn.host, but that isn't the raw header
|
||||||
|
# and that isn't used in the EnsureHostMatchesPlug, because it doesn't include the port.
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign_valid_signature_for_actor(alice)
|
||||||
|
|> delete_req_header("host")
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|
||||||
|
conn = %{conn | req_headers: conn.req_headers ++ [{"host", "invalid.example.com"}]}
|
||||||
|
conn = post(conn, "/inbox", data)
|
||||||
|
|
||||||
|
assert "Host header does not match this instance" == conn.resp_body
|
||||||
|
assert 400 == conn.status
|
||||||
|
assert true == conn.halted
|
||||||
|
|
||||||
|
refute Activity.get_by_ap_id(data["id"])
|
||||||
|
refute Object.get_by_ap_id(object_id)
|
||||||
|
end
|
||||||
|
|
||||||
test "accept follow activity", %{conn: conn} do
|
test "accept follow activity", %{conn: conn} do
|
||||||
clear_config([:instance, :federating], true)
|
clear_config([:instance, :federating], true)
|
||||||
relay = Relay.get_actor()
|
relay = Relay.get_actor()
|
||||||
|
|
|
||||||
121
test/pleroma/web/plugs/ensure_host_matches_plug_test.exs
Normal file
121
test/pleroma/web/plugs/ensure_host_matches_plug_test.exs
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2026 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.EnsureHostMatchesPlugTest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Plugs.EnsureHostMatchesPlug
|
||||||
|
|
||||||
|
import Plug.Conn
|
||||||
|
import Tesla.Mock
|
||||||
|
|
||||||
|
setup do
|
||||||
|
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp set_host(conn, host), do: %{conn | req_headers: conn.req_headers ++ [{"host", host}]}
|
||||||
|
|
||||||
|
describe "EnsureHostMatchesPlug" do
|
||||||
|
setup do
|
||||||
|
conn = build_conn(:post, "/cofe") |> assign(:valid_signature, true)
|
||||||
|
[conn: conn]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "gracefully handles no Host header", %{conn: conn} do
|
||||||
|
conn = EnsureHostMatchesPlug.call(conn, %{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header not provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "gracefully handles empty Host header", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header not provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint URL", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("invalid.example.com")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint with port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("invalid.example.com:#{endpoint.port}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects Host header not matching Endpoint port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}:25")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "Host header does not match this instance"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects multiple Host headers", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("host1.example.com")
|
||||||
|
|> set_host("host2.example.com")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.resp_body == "More than one Host header provided"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works for Host header without port", %{conn: conn} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.halted == false
|
||||||
|
assert Map.get(conn.assigns, :valid_host_header, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works for Host header with port same as Endpoint", %{
|
||||||
|
conn: conn
|
||||||
|
} do
|
||||||
|
endpoint = URI.parse(Endpoint.url())
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> set_host("#{endpoint.host}:#{endpoint.port}")
|
||||||
|
|> EnsureHostMatchesPlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.halted == false
|
||||||
|
assert Map.get(conn.assigns, :valid_host_header, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -16,12 +16,13 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
alias Pleroma.Signature
|
alias Pleroma.Signature
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.UserView
|
alias Pleroma.Web.ActivityPub.UserView
|
||||||
|
alias Pleroma.Web.Endpoint
|
||||||
alias Pleroma.Web.Federator
|
alias Pleroma.Web.Federator
|
||||||
alias Pleroma.Workers.SignatureRetryWorker
|
alias Pleroma.Workers.SignatureRetryWorker
|
||||||
|
|
||||||
defp signature_headers_for(%User{} = signer) do
|
defp signature_headers_for(%User{} = signer) do
|
||||||
[
|
[
|
||||||
{"host", "local.test"},
|
{"host", "#{URI.parse(Endpoint.url()).host}"},
|
||||||
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
||||||
{"digest", "SHA-256=fake-digest"},
|
{"digest", "SHA-256=fake-digest"},
|
||||||
{"content-type", "application/activity+json"},
|
{"content-type", "application/activity+json"},
|
||||||
|
|
@ -245,6 +246,66 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
refute Activity.get_by_ap_id(create["id"])
|
refute Activity.get_by_ap_id(create["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "cancels when the Host header does not match Endpoint" do
|
||||||
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
|
||||||
|
create = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"id" => "https://one.com/activities/invalid-signature-create",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => [],
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"id" => "https://one.com/objects/invalid-signature-note",
|
||||||
|
"actor" => alice.ap_id,
|
||||||
|
"attributedTo" => alice.ap_id,
|
||||||
|
"content" => "forged post",
|
||||||
|
"published" => "2024-07-25T13:33:31Z",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_signature_from(alice)
|
||||||
|
|
||||||
|
headers =
|
||||||
|
[
|
||||||
|
{"host", "invalid.example.com"},
|
||||||
|
{"date", "Thu, 25 Jul 2024 13:33:31 GMT"},
|
||||||
|
{"digest", "SHA-256=fake-digest"},
|
||||||
|
{"content-type", "application/activity+json"},
|
||||||
|
{
|
||||||
|
"signature",
|
||||||
|
"keyId=\"#{alice.ap_id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"fake-signature\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert {:ok, oban_job} =
|
||||||
|
Federator.incoming_failed_signature_ap_doc(%{
|
||||||
|
method: "POST",
|
||||||
|
req_headers: headers,
|
||||||
|
request_path: "/inbox",
|
||||||
|
params: create,
|
||||||
|
query_string: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
log =
|
||||||
|
capture_log([level: :warning], fn ->
|
||||||
|
assert {:cancel, :host_header_mismatch} = SignatureRetryWorker.perform(oban_job)
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert log =~ "Failed-signature inbox retry rejected"
|
||||||
|
assert log =~ "reason=:host_header_mismatch"
|
||||||
|
assert log =~ "payload_actor=\"https://one.com/users/alice\""
|
||||||
|
assert log =~ "signature_actor=\"https://one.com/users/alice\""
|
||||||
|
assert log =~ "activity_id=\"https://one.com/activities/invalid-signature-create\""
|
||||||
|
assert log =~ "type=\"Create\""
|
||||||
|
assert log =~ "request_path=\"/inbox\""
|
||||||
|
|
||||||
|
refute Activity.get_by_ap_id(create["id"])
|
||||||
|
end
|
||||||
|
|
||||||
test "processes the activity after refetching a valid matching signature" do
|
test "processes the activity after refetching a valid matching signature" do
|
||||||
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
alice = insert(:user, local: false, ap_id: "https://one.com/users/alice")
|
||||||
|
|
||||||
|
|
@ -309,11 +370,11 @@ defmodule Pleroma.Workers.SignatureRetryWorkerTest do
|
||||||
"content-type" => "application/activity+json",
|
"content-type" => "application/activity+json",
|
||||||
date: date,
|
date: date,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
host: "local.test"
|
host: "#{URI.parse(Endpoint.url()).host}"
|
||||||
})
|
})
|
||||||
|
|
||||||
req_headers = [
|
req_headers = [
|
||||||
["host", "local.test"],
|
["host", "#{URI.parse(Endpoint.url()).host}"],
|
||||||
["date", date],
|
["date", date],
|
||||||
["digest", digest],
|
["digest", digest],
|
||||||
["content-type", "application/activity+json"],
|
["content-type", "application/activity+json"],
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,10 @@ defmodule Pleroma.Web.ConnCase do
|
||||||
DataCase.stub_pipeline()
|
DataCase.stub_pipeline()
|
||||||
|
|
||||||
Mox.verify_on_exit!()
|
Mox.verify_on_exit!()
|
||||||
|
endpoint = URI.parse(Pleroma.Web.Endpoint.url())
|
||||||
|
conn = Phoenix.ConnTest.build_conn()
|
||||||
|
conn = %{conn | req_headers: [{"host", "#{endpoint.host}:#{endpoint.port}"}]}
|
||||||
|
|
||||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
{:ok, conn: conn}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue