Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into no-async-clear-config
This commit is contained in:
commit
18ab36d70c
|
@ -1,6 +1,7 @@
|
|||
image: git.pleroma.social:5050/pleroma/pleroma/ci-base
|
||||
|
||||
variables: &global_variables
|
||||
# Only used for the release
|
||||
ELIXIR_VER: 1.12.3
|
||||
POSTGRES_DB: pleroma_test
|
||||
POSTGRES_USER: postgres
|
||||
|
@ -319,8 +320,9 @@ amd64:
|
|||
- deps
|
||||
variables: &release-variables
|
||||
MIX_ENV: prod
|
||||
VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS
|
||||
before_script: &before-release
|
||||
- apt-get update && apt-get install -y cmake libmagic-dev
|
||||
- apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev
|
||||
- echo "import Config" > config/prod.secret.exs
|
||||
- mix local.hex --force
|
||||
- mix local.rebar --force
|
||||
|
@ -341,7 +343,7 @@ amd64-musl:
|
|||
cache: *release-cache
|
||||
variables: *release-variables
|
||||
before_script: &before-release-musl
|
||||
- apk add git build-base cmake file-dev openssl
|
||||
- apk add git build-base cmake file-dev openssl vips-dev
|
||||
- echo "import Config" > config/prod.secret.exs
|
||||
- mix local.hex --force
|
||||
- mix local.rebar --force
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Support /authorize-interaction route used by Mastodon
|
|
@ -0,0 +1 @@
|
|||
Optimistic Inbox reduces the processing overhead of incoming activities without instantly verifiable signatures.
|
|
@ -2136,7 +2136,7 @@ def public_key(%{public_key: public_key_pem}) when is_binary(public_key_pem) do
|
|||
def public_key(_), do: {:error, "key not found"}
|
||||
|
||||
def get_public_key_for_ap_id(ap_id) do
|
||||
with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id),
|
||||
with %User{} = user <- get_cached_by_ap_id(ap_id),
|
||||
{:ok, public_key} <- public_key(user) do
|
||||
{:ok, public_key}
|
||||
else
|
||||
|
|
|
@ -287,10 +287,9 @@ def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
|
|||
json(conn, "ok")
|
||||
end
|
||||
|
||||
def inbox(%{assigns: %{valid_signature: false}} = conn, _params) do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json("Invalid HTTP Signature")
|
||||
def inbox(%{assigns: %{valid_signature: false}, req_headers: req_headers} = conn, params) do
|
||||
Federator.incoming_ap_doc(%{req_headers: req_headers, params: params})
|
||||
json(conn, "ok")
|
||||
end
|
||||
|
||||
# POST /relay/inbox -or- POST /internal/fetch/inbox
|
||||
|
|
|
@ -35,6 +35,17 @@ def allowed_thread_distance?(distance) do
|
|||
end
|
||||
|
||||
# Client API
|
||||
def incoming_ap_doc(%{params: params, req_headers: req_headers}) do
|
||||
ReceiverWorker.enqueue(
|
||||
"incoming_ap_doc",
|
||||
%{"req_headers" => req_headers, "params" => params, "timeout" => :timer.seconds(20)},
|
||||
priority: 2
|
||||
)
|
||||
end
|
||||
|
||||
def incoming_ap_doc(%{"type" => "Delete"} = params) do
|
||||
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params}, priority: 3)
|
||||
end
|
||||
|
||||
def incoming_ap_doc(params) do
|
||||
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params})
|
||||
|
|
|
@ -471,6 +471,8 @@ defmodule Pleroma.Web.Router do
|
|||
get("/main/ostatus", UtilController, :show_subscribe_form)
|
||||
get("/ostatus_subscribe", RemoteFollowController, :follow)
|
||||
post("/ostatus_subscribe", RemoteFollowController, :do_follow)
|
||||
|
||||
get("/authorize_interaction", RemoteFollowController, :authorize_interaction)
|
||||
end
|
||||
|
||||
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
|
||||
|
|
|
@ -121,6 +121,13 @@ def do_follow(%{assigns: %{user: nil}} = conn, _) do
|
|||
render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
|
||||
end
|
||||
|
||||
# GET /authorize_interaction
|
||||
#
|
||||
def authorize_interaction(conn, %{"uri" => uri}) do
|
||||
conn
|
||||
|> redirect(to: Routes.remote_follow_path(conn, :follow, %{acct: uri}))
|
||||
end
|
||||
|
||||
defp handle_follow_error(conn, {:mfa_token, followee, _} = _) do
|
||||
render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
|
||||
end
|
||||
|
|
|
@ -3,24 +3,56 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.ReceiverWorker do
|
||||
alias Pleroma.Signature
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.Federator
|
||||
|
||||
use Pleroma.Workers.WorkerHelper, queue: "federator_incoming"
|
||||
|
||||
@impl Oban.Worker
|
||||
|
||||
def perform(%Job{
|
||||
args: %{"op" => "incoming_ap_doc", "req_headers" => req_headers, "params" => params}
|
||||
}) do
|
||||
# Oban's serialization converts our tuple headers to lists.
|
||||
# Revert it for the signature validation.
|
||||
req_headers = Enum.into(req_headers, [], &List.to_tuple(&1))
|
||||
|
||||
conn_data = %{params: params, req_headers: req_headers}
|
||||
|
||||
with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
|
||||
{:ok, _public_key} <- Signature.refetch_public_key(conn_data),
|
||||
{:signature, true} <- {:signature, HTTPSignatures.validate_conn(conn_data)},
|
||||
{:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
||||
{:ok, res}
|
||||
else
|
||||
e -> process_errors(e)
|
||||
end
|
||||
end
|
||||
|
||||
def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
|
||||
with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
||||
{:ok, res}
|
||||
else
|
||||
e -> process_errors(e)
|
||||
end
|
||||
end
|
||||
|
||||
@impl Oban.Worker
|
||||
def timeout(%_{args: %{"timeout" => timeout}}), do: timeout
|
||||
|
||||
def timeout(_job), do: :timer.seconds(5)
|
||||
|
||||
defp process_errors(errors) do
|
||||
case errors do
|
||||
{:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
|
||||
{:error, :already_present} -> {:cancel, :already_present}
|
||||
{:error, {:validate_object, reason}} -> {:cancel, reason}
|
||||
{:error, {:error, {:validate, reason}}} -> {:cancel, reason}
|
||||
{:error, {:reject, reason}} -> {:cancel, reason}
|
||||
{:signature, false} -> {:cancel, :invalid_signature}
|
||||
{:error, {:error, reason = "Object has been deleted"}} -> {:cancel, reason}
|
||||
e -> e
|
||||
end
|
||||
end
|
||||
|
||||
@impl Oban.Worker
|
||||
def timeout(_job), do: :timer.seconds(5)
|
||||
end
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -181,7 +181,7 @@ defp deps do
|
|||
{:majic, "~> 1.0"},
|
||||
{:open_api_spex, "~> 3.16"},
|
||||
{:ecto_psql_extras, "~> 0.6"},
|
||||
{:vix, "~> 0.25.0"},
|
||||
{:vix, "~> 0.26.0"},
|
||||
{:elixir_make, "~> 0.7.7", override: true},
|
||||
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
|
||||
|
||||
|
|
2
mix.lock
2
mix.lock
|
@ -137,7 +137,7 @@
|
|||
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
|
||||
"vix": {:hex, :vix, "0.25.0", "b294ca3140c0357b262d86e9966949949844282b81923bb990668c1ee5a35337", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "be09c96982978bc2d0c501a73e0b65ba58ec94c1afb94e3617029d6ce7ae8c3f"},
|
||||
"vix": {:hex, :vix, "0.26.0", "027f10b6969b759318be84bd0bd8c88af877445e4e41cf96a0460392cea5399c", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "71b0a79ae7f199cacfc8e679b0e4ba25ee47dc02e182c5b9097efb29fbe14efd"},
|
||||
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
|
||||
|
|
|
@ -43,10 +43,7 @@ test "it returns key" do
|
|||
end
|
||||
|
||||
test "it returns error when not found user" do
|
||||
assert capture_log(fn ->
|
||||
assert Signature.fetch_public_key(make_fake_conn("https://test-ap-id")) ==
|
||||
{:error, :error}
|
||||
end) =~ "[error] Could not decode user"
|
||||
assert Signature.fetch_public_key(make_fake_conn("https://test-ap-id")) == {:error, :error}
|
||||
end
|
||||
|
||||
test "it returns error if public key is nil" do
|
||||
|
|
|
@ -1951,8 +1951,8 @@ test "unsuggests a user" do
|
|||
end
|
||||
end
|
||||
|
||||
test "get_public_key_for_ap_id fetches a user that's not in the db" do
|
||||
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
||||
test "get_public_key_for_ap_id returns correctly for user that's not in the db" do
|
||||
assert :error = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
||||
end
|
||||
|
||||
describe "per-user rich-text filtering" do
|
||||
|
|
|
@ -89,6 +89,7 @@ test "api routes are detected correctly" do
|
|||
"api",
|
||||
"main",
|
||||
"ostatus_subscribe",
|
||||
"authorize_interaction",
|
||||
"oauth",
|
||||
"objects",
|
||||
"activities",
|
||||
|
|
|
@ -460,4 +460,38 @@ test "local avatar is not proxied" do
|
|||
assert avatar_url == "#{Pleroma.Web.Endpoint.url()}/localuser/avatar.png"
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /authorize_interaction - authorize_interaction/2" do
|
||||
test "redirects to /ostatus_subscribe", %{conn: conn} do
|
||||
Tesla.Mock.mock(fn
|
||||
%{method: :get, url: "https://mastodon.social/users/emelie"} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-type", "application/activity+json"}],
|
||||
body: File.read!("test/fixtures/tesla_mock/emelie.json")
|
||||
}
|
||||
|
||||
%{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-type", "application/activity+json"}],
|
||||
body:
|
||||
File.read!("test/fixtures/users_mock/masto_featured.json")
|
||||
|> String.replace("{{domain}}", "mastodon.social")
|
||||
|> String.replace("{{nickname}}", "emelie")
|
||||
}
|
||||
end)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> get(
|
||||
remote_follow_path(conn, :authorize_interaction, %{
|
||||
uri: "https://mastodon.social/users/emelie"
|
||||
})
|
||||
)
|
||||
|
||||
assert redirected_to(conn) ==
|
||||
remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue