logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma
commit: 1e48af9acf01bf66bd03babccbf08089eb909788
parent: 60b54ee64a9130dd4a3245b90ab49943a9e881c6
Author: kaniini <ariadne@dereferenced.org>
Date:   Wed, 17 Jul 2019 19:45:40 +0000

Merge branch 'feature/instance-fetch-actor' into 'develop'

instance fetch service actor

See merge request pleroma/pleroma!1440

Diffstat:

MCHANGELOG.md1+
Mlib/pleroma/application.ex5+++++
Mlib/pleroma/user.ex17++++++++++-------
Mlib/pleroma/web/activity_pub/activity_pub_controller.ex18+++++++++++++++---
Alib/pleroma/web/activity_pub/internal_fetch_actor.ex20++++++++++++++++++++
Mlib/pleroma/web/activity_pub/relay.ex3++-
Mlib/pleroma/web/activity_pub/views/user_view.ex13++++++++++---
Mlib/pleroma/web/router.ex13+++++++++++--
Mlib/pleroma/web/web_finger/web_finger.ex2+-
Mtest/user_test.exs17+++++++++++++++++
Mtest/web/activity_pub/activity_pub_controller_test.exs11+++++++++++
11 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -43,6 +43,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options. - Addressable lists - Twitter API: added rate limit for `/api/account/password_reset` endpoint. +- ActivityPub: Add an internal service actor for fetching ActivityPub objects. ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex @@ -140,6 +140,11 @@ defmodule Pleroma.Application do id: :federator_init, start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]}, restart: :temporary + }, + %{ + id: :internal_fetch_init, + start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]}, + restart: :temporary } ] ++ streamer_child() ++ diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex @@ -1157,19 +1157,18 @@ defmodule Pleroma.User do end end - def get_or_create_instance_user do - relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay" - - if user = get_cached_by_ap_id(relay_uri) do + @doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing." + def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do + if user = get_cached_by_ap_id(uri) do user else changes = %User{info: %User.Info{}} |> cast(%{}, [:ap_id, :nickname, :local]) - |> put_change(:ap_id, relay_uri) - |> put_change(:nickname, nil) + |> put_change(:ap_id, uri) + |> put_change(:nickname, nickname) |> put_change(:local, true) - |> put_change(:follower_address, relay_uri <> "/followers") + |> put_change(:follower_address, uri <> "/followers") {:ok, user} = Repo.insert(changes) user @@ -1411,4 +1410,8 @@ defmodule Pleroma.User do end defp put_password_hash(changeset), do: changeset + + def is_internal_user?(%User{nickname: nil}), do: true + def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true + def is_internal_user?(_), do: false end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do alias Pleroma.Object.Fetcher alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.InternalFetchActor alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier @@ -206,9 +207,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do json(conn, dgettext("errors", "error")) end - def relay(conn, _params) do - with %User{} = user <- Relay.get_actor(), - {:ok, user} <- User.ensure_keys_present(user) do + defp represent_service_actor(%User{} = user, conn) do + with {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("user.json", %{user: user})) @@ -217,6 +217,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end end + defp represent_service_actor(nil, _), do: {:error, :not_found} + + def relay(conn, _params) do + Relay.get_actor() + |> represent_service_actor(conn) + end + + def internal_fetch(conn, _params) do + InternalFetchActor.get_actor() + |> represent_service_actor(conn) + end + def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do conn |> put_resp_header("content-type", "application/activity+json") diff --git a/lib/pleroma/web/activity_pub/internal_fetch_actor.ex b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.InternalFetchActor do + alias Pleroma.User + + require Logger + + def init do + # Wait for everything to settle. + Process.sleep(1000 * 5) + get_actor() + end + + def get_actor do + "#{Pleroma.Web.Endpoint.url()}/internal/fetch" + |> User.get_or_create_service_actor_by_ap_id("internal.fetch") + end +end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex @@ -10,7 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Relay do require Logger def get_actor do - User.get_or_create_instance_user() + "#{Pleroma.Web.Endpoint.url()}/relay" + |> User.get_or_create_service_actor_by_ap_id() end def follow(target_instance) do diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -31,8 +31,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do def render("endpoints.json", _), do: %{} - # the instance itself is not a Person, but instead an Application - def render("user.json", %{user: %{nickname: nil} = user}) do + def render("service.json", %{user: user}) do {:ok, user} = User.ensure_keys_present(user) {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) @@ -47,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", "name" => "Pleroma", - "summary" => "Virtual actor for Pleroma relay", + "summary" => + "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", "url" => user.ap_id, "manuallyApprovesFollowers" => false, "publicKey" => %{ @@ -60,6 +60,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do |> Map.merge(Utils.make_json_ld_header()) end + # the instance itself is not a Person, but instead an Application + def render("user.json", %{user: %User{nickname: nil} = user}), + do: render("service.json", %{user: user}) + + def render("user.json", %{user: %User{nickname: "internal." <> _} = user}), + do: render("service.json", %{user: user}) + def render("user.json", %{user: user}) do {:ok, user} = User.ensure_keys_present(user) {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex @@ -586,7 +586,7 @@ defmodule Pleroma.Web.Router do end end - pipeline :ap_relay do + pipeline :ap_service_actor do plug(:accepts, ["activity+json", "json"]) end @@ -663,8 +663,17 @@ defmodule Pleroma.Web.Router do end scope "/relay", Pleroma.Web.ActivityPub do - pipe_through(:ap_relay) + pipe_through(:ap_service_actor) + get("/", ActivityPubController, :relay) + post("/inbox", ActivityPubController, :inbox) + end + + scope "/internal/fetch", Pleroma.Web.ActivityPub do + pipe_through(:ap_service_actor) + + get("/", ActivityPubController, :internal_fetch) + post("/inbox", ActivityPubController, :inbox) end scope "/", Pleroma.Web.ActivityPub do diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.WebFinger do def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do host = Pleroma.Web.Endpoint.host() - regex = ~r/(acct:)?(?<username>\w+)@#{host}/ + regex = ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/ with %{"username" => username} <- Regex.named_captures(regex, resource), %User{} = user <- User.get_cached_by_nickname(username) do diff --git a/test/user_test.exs b/test/user_test.exs @@ -1310,4 +1310,21 @@ defmodule Pleroma.UserTest do assert following == 0 end end + + describe "is_internal_user?/1" do + test "non-internal user returns false" do + user = insert(:user) + refute User.is_internal_user?(user) + end + + test "user with no nickname returns true" do + user = insert(:user, %{nickname: nil}) + assert User.is_internal_user?(user) + end + + test "user with internal-prefixed nickname returns true" do + user = insert(:user, %{nickname: "internal.test"}) + assert User.is_internal_user?(user) + end + end end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs @@ -48,6 +48,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do end end + describe "/internal/fetch" do + test "it returns the internal fetch user", %{conn: conn} do + res = + conn + |> get(activity_pub_path(conn, :internal_fetch)) + |> json_response(200) + + assert res["id"] =~ "/fetch" + end + end + describe "/users/:nickname" do test "it returns a json representation of the user with accept application/json", %{ conn: conn