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

instance fetch service actor

See merge request pleroma/pleroma!1440
This commit is contained in:
kaniini 2019-07-17 19:45:40 +00:00
commit 1e48af9acf
11 changed files with 103 additions and 17 deletions

View file

@ -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

View file

@ -140,6 +140,11 @@ def start(_type, _args) 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() ++

View file

@ -1157,19 +1157,18 @@ def get_or_fetch_by_ap_id(ap_id) 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 @@ defp put_password_hash(
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

View file

@ -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 @@ def inbox(conn, params) 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 @@ def relay(conn, _params) 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")

View file

@ -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

View file

@ -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

View file

@ -31,8 +31,7 @@ def render("endpoints.json", %{user: %User{local: true} = _user}) 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 @@ def render("user.json", %{user: %{nickname: nil} = user}) 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 @@ def render("user.json", %{user: %{nickname: nil} = user}) 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)

View file

@ -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

View file

@ -32,7 +32,7 @@ def host_meta 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

View file

@ -1310,4 +1310,21 @@ test "without args", %{user: user} 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

View file

@ -48,6 +48,17 @@ test "with the relay disabled, it returns 404", %{conn: conn} 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