Merge branch 'feature/instance-fetch-actor' into 'develop'
instance fetch service actor See merge request pleroma/pleroma!1440
This commit is contained in:
commit
1e48af9acf
|
@ -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.
|
- Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options.
|
||||||
- Addressable lists
|
- Addressable lists
|
||||||
- Twitter API: added rate limit for `/api/account/password_reset` endpoint.
|
- Twitter API: added rate limit for `/api/account/password_reset` endpoint.
|
||||||
|
- ActivityPub: Add an internal service actor for fetching ActivityPub objects.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
||||||
|
|
|
@ -140,6 +140,11 @@ def start(_type, _args) do
|
||||||
id: :federator_init,
|
id: :federator_init,
|
||||||
start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]},
|
start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]},
|
||||||
restart: :temporary
|
restart: :temporary
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :internal_fetch_init,
|
||||||
|
start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
|
||||||
|
restart: :temporary
|
||||||
}
|
}
|
||||||
] ++
|
] ++
|
||||||
streamer_child() ++
|
streamer_child() ++
|
||||||
|
|
|
@ -1157,19 +1157,18 @@ def get_or_fetch_by_ap_id(ap_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_or_create_instance_user do
|
@doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing."
|
||||||
relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay"
|
def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do
|
||||||
|
if user = get_cached_by_ap_id(uri) do
|
||||||
if user = get_cached_by_ap_id(relay_uri) do
|
|
||||||
user
|
user
|
||||||
else
|
else
|
||||||
changes =
|
changes =
|
||||||
%User{info: %User.Info{}}
|
%User{info: %User.Info{}}
|
||||||
|> cast(%{}, [:ap_id, :nickname, :local])
|
|> cast(%{}, [:ap_id, :nickname, :local])
|
||||||
|> put_change(:ap_id, relay_uri)
|
|> put_change(:ap_id, uri)
|
||||||
|> put_change(:nickname, nil)
|
|> put_change(:nickname, nickname)
|
||||||
|> put_change(:local, true)
|
|> put_change(:local, true)
|
||||||
|> put_change(:follower_address, relay_uri <> "/followers")
|
|> put_change(:follower_address, uri <> "/followers")
|
||||||
|
|
||||||
{:ok, user} = Repo.insert(changes)
|
{:ok, user} = Repo.insert(changes)
|
||||||
user
|
user
|
||||||
|
@ -1411,4 +1410,8 @@ defp put_password_hash(
|
||||||
end
|
end
|
||||||
|
|
||||||
defp put_password_hash(changeset), do: changeset
|
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
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
alias Pleroma.Object.Fetcher
|
alias Pleroma.Object.Fetcher
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||||
alias Pleroma.Web.ActivityPub.ObjectView
|
alias Pleroma.Web.ActivityPub.ObjectView
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
@ -206,9 +207,8 @@ def inbox(conn, params) do
|
||||||
json(conn, dgettext("errors", "error"))
|
json(conn, dgettext("errors", "error"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def relay(conn, _params) do
|
defp represent_service_actor(%User{} = user, conn) do
|
||||||
with %User{} = user <- Relay.get_actor(),
|
with {:ok, user} <- User.ensure_keys_present(user) do
|
||||||
{:ok, user} <- User.ensure_keys_present(user) do
|
|
||||||
conn
|
conn
|
||||||
|> put_resp_header("content-type", "application/activity+json")
|
|> put_resp_header("content-type", "application/activity+json")
|
||||||
|> json(UserView.render("user.json", %{user: user}))
|
|> json(UserView.render("user.json", %{user: user}))
|
||||||
|
@ -217,6 +217,18 @@ def relay(conn, _params) do
|
||||||
end
|
end
|
||||||
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
|
def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do
|
||||||
conn
|
conn
|
||||||
|> put_resp_header("content-type", "application/activity+json")
|
|> put_resp_header("content-type", "application/activity+json")
|
||||||
|
|
|
@ -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
|
|
@ -10,7 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def get_actor do
|
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
|
end
|
||||||
|
|
||||||
def follow(target_instance) do
|
def follow(target_instance) do
|
||||||
|
|
|
@ -31,8 +31,7 @@ def render("endpoints.json", %{user: %User{local: true} = _user}) do
|
||||||
|
|
||||||
def render("endpoints.json", _), do: %{}
|
def render("endpoints.json", _), do: %{}
|
||||||
|
|
||||||
# the instance itself is not a Person, but instead an Application
|
def render("service.json", %{user: user}) do
|
||||||
def render("user.json", %{user: %{nickname: nil} = user}) do
|
|
||||||
{:ok, user} = User.ensure_keys_present(user)
|
{:ok, user} = User.ensure_keys_present(user)
|
||||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||||
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
|
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",
|
"followers" => "#{user.ap_id}/followers",
|
||||||
"inbox" => "#{user.ap_id}/inbox",
|
"inbox" => "#{user.ap_id}/inbox",
|
||||||
"name" => "Pleroma",
|
"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,
|
"url" => user.ap_id,
|
||||||
"manuallyApprovesFollowers" => false,
|
"manuallyApprovesFollowers" => false,
|
||||||
"publicKey" => %{
|
"publicKey" => %{
|
||||||
|
@ -60,6 +60,13 @@ def render("user.json", %{user: %{nickname: nil} = user}) do
|
||||||
|> Map.merge(Utils.make_json_ld_header())
|
|> Map.merge(Utils.make_json_ld_header())
|
||||||
end
|
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
|
def render("user.json", %{user: user}) do
|
||||||
{:ok, user} = User.ensure_keys_present(user)
|
{:ok, user} = User.ensure_keys_present(user)
|
||||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||||
|
|
|
@ -586,7 +586,7 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :ap_relay do
|
pipeline :ap_service_actor do
|
||||||
plug(:accepts, ["activity+json", "json"])
|
plug(:accepts, ["activity+json", "json"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -663,8 +663,17 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/relay", Pleroma.Web.ActivityPub do
|
scope "/relay", Pleroma.Web.ActivityPub do
|
||||||
pipe_through(:ap_relay)
|
pipe_through(:ap_service_actor)
|
||||||
|
|
||||||
get("/", ActivityPubController, :relay)
|
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
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web.ActivityPub do
|
scope "/", Pleroma.Web.ActivityPub do
|
||||||
|
|
|
@ -32,7 +32,7 @@ def host_meta do
|
||||||
|
|
||||||
def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
|
def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
|
||||||
host = Pleroma.Web.Endpoint.host()
|
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),
|
with %{"username" => username} <- Regex.named_captures(regex, resource),
|
||||||
%User{} = user <- User.get_cached_by_nickname(username) do
|
%User{} = user <- User.get_cached_by_nickname(username) do
|
||||||
|
|
|
@ -1310,4 +1310,21 @@ test "without args", %{user: user} do
|
||||||
assert following == 0
|
assert following == 0
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -48,6 +48,17 @@ test "with the relay disabled, it returns 404", %{conn: conn} do
|
||||||
end
|
end
|
||||||
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
|
describe "/users/:nickname" do
|
||||||
test "it returns a json representation of the user with accept application/json", %{
|
test "it returns a json representation of the user with accept application/json", %{
|
||||||
conn: conn
|
conn: conn
|
||||||
|
|
Loading…
Reference in New Issue