Merge branch 'feature/activitypub-semantics' into 'develop'

activitypub semantics

See merge request pleroma/pleroma!1798
This commit is contained in:
kaniini 2019-10-21 07:54:48 +00:00
commit 2ebe8c416a
15 changed files with 168 additions and 10 deletions

View File

@ -88,6 +88,9 @@ def superuser?(%User{local: true, info: %User.Info{is_admin: true}}), do: true
def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true
def superuser?(_), do: false
def invisible?(%User{info: %User.Info{invisible: true}}), do: true
def invisible?(_), do: false
def avatar_url(user, options \\ []) do
case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href

View File

@ -53,6 +53,7 @@ defmodule Pleroma.User.Info do
field(:fields, {:array, :map}, default: nil)
field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false)
field(:invisible, :boolean, default: false)
field(:notification_settings, :map,
default: %{
@ -266,7 +267,8 @@ def remote_user_creation(info, params) do
:follower_count,
:fields,
:following_count,
:discoverable
:discoverable,
:invisible
])
|> validate_fields(true)
end
@ -393,6 +395,14 @@ def set_source_data(info, source_data) do
|> validate_required([:source_data])
end
def set_invisible(info, invisible) do
params = %{invisible: invisible}
info
|> cast(params, [:invisible])
|> validate_required([:invisible])
end
def admin_api_update(info, params) do
info
|> cast(params, [

View File

@ -1106,6 +1106,7 @@ defp object_to_user_data(data) do
locked = data["manuallyApprovesFollowers"] || false
data = Transmogrifier.maybe_fix_user_object(data)
discoverable = data["discoverable"] || false
invisible = data["invisible"] || false
user_data = %{
ap_id: data["id"],
@ -1115,7 +1116,8 @@ defp object_to_user_data(data) do
banner: banner,
fields: fields,
locked: locked,
discoverable: discoverable
discoverable: discoverable,
invisible: invisible
},
avatar: avatar,
name: data["name"],

View File

@ -10,8 +10,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do
require Logger
def get_actor do
actor =
"#{Pleroma.Web.Endpoint.url()}/relay"
|> User.get_or_create_service_actor_by_ap_id()
{:ok, actor} = User.update_info(actor, &User.Info.set_invisible(&1, true))
actor
end
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}

View File

@ -596,13 +596,19 @@ def handle_incoming(
data,
_options
)
when object_type in ["Person", "Application", "Service", "Organization"] do
when object_type in [
"Person",
"Application",
"Service",
"Organization"
] do
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
banner = new_user_data[:info][:banner]
locked = new_user_data[:info][:locked] || false
attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || []
invisible = new_user_data[:info][:invisible] || false
fields =
attachment
@ -612,7 +618,7 @@ def handle_incoming(
update_data =
new_user_data
|> Map.take([:name, :bio, :avatar])
|> Map.put(:info, %{banner: banner, locked: locked, fields: fields})
|> Map.put(:info, %{banner: banner, locked: locked, fields: fields, invisible: invisible})
actor
|> User.upgrade_changeset(update_data, true)

View File

@ -491,11 +491,15 @@ def add_announce_to_object(
%Activity{data: %{"actor" => actor}},
object
) do
unless actor |> User.get_cached_by_ap_id() |> User.invisible?() do
announcements = take_announcements(object)
with announcements <- Enum.uniq([actor | announcements]) do
update_element_in_object("announcement", announcements, object)
end
else
{:ok, object}
end
end
def add_announce_to_object(_, object), do: {:ok, object}

View File

@ -55,7 +55,8 @@ def render("service.json", %{user: user}) do
"owner" => user.ap_id,
"publicKeyPem" => public_key
},
"endpoints" => endpoints
"endpoints" => endpoints,
"invisible" => User.invisible?(user)
}
|> Map.merge(Utils.make_json_ld_header())
end

View File

@ -19,6 +19,7 @@
"value": "schema:value",
"sensitive": "as:sensitive",
"litepub": "http://litepub.social/ns#",
"invisible": "litepub:invisible",
"directMessage": "litepub:directMessage",
"listMessage": {
"@id": "litepub:listMessage",

View File

@ -0,0 +1,55 @@
{
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"sensitive": "as:sensitive",
"movedTo": "as:movedTo",
"Hashtag": "as:Hashtag",
"ostatus": "http://ostatus.org#",
"atomUri": "ostatus:atomUri",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji"
}],
"id": "http://mastodon.example.org/users/admin",
"type": "Application",
"invisible": true,
"following": "http://mastodon.example.org/users/admin/following",
"followers": "http://mastodon.example.org/users/admin/followers",
"inbox": "http://mastodon.example.org/users/admin/inbox",
"outbox": "http://mastodon.example.org/users/admin/outbox",
"preferredUsername": "admin",
"name": null,
"summary": "\u003cp\u003e\u003c/p\u003e",
"url": "http://mastodon.example.org/@admin",
"manuallyApprovesFollowers": false,
"publicKey": {
"id": "http://mastodon.example.org/users/admin#main-key",
"owner": "http://mastodon.example.org/users/admin",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n"
},
"attachment": [{
"type": "PropertyValue",
"name": "foo",
"value": "bar"
},
{
"type": "PropertyValue",
"name": "foo1",
"value": "bar1"
}
],
"endpoints": {
"sharedInbox": "http://mastodon.example.org/inbox"
},
"icon": {
"type": "Image",
"mediaType": "image/jpeg",
"url": "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
},
"image": {
"type": "Image",
"mediaType": "image/png",
"url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
}
}

View File

@ -348,6 +348,14 @@ def get("http://mastodon.example.org/users/admin", _, _, Accept: "application/ac
}}
end
def get("http://mastodon.example.org/users/relay", _, _, Accept: "application/activity+json") do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json")
}}
end
def get("http://mastodon.example.org/users/gargron", _, _, Accept: "application/activity+json") do
{:error, :nxdomain}
end

View File

@ -1232,6 +1232,20 @@ test "returns true for local admins" do
end
end
describe "invisible?/1" do
test "returns true for an invisible user" do
user = insert(:user, local: true, info: %{invisible: true})
assert User.invisible?(user)
end
test "returns false for a non-invisible user" do
user = insert(:user, local: true)
refute User.invisible?(user)
end
end
describe "visible_for?/2" do
test "returns true when the account is itself" do
user = insert(:user, local: true)

View File

@ -179,6 +179,12 @@ test "it returns a user" do
assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
end
test "it returns a user that is invisible" do
user_id = "http://mastodon.example.org/users/relay"
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
assert User.invisible?(user)
end
test "it fetches the appropriate tag-restricted posts" do
user = insert(:user)

View File

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay
@ -19,6 +20,11 @@ test "gets an actor for the relay" do
assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay"
end
test "relay actor is invisible" do
user = Relay.get_actor()
assert User.invisible?(user)
end
describe "follow/1" do
test "returns errors when user not found" do
assert capture_log(fn ->

View File

@ -76,6 +76,12 @@ test "Does not add an avatar image if the user hasn't set one" do
assert result["image"]["url"] == "https://somebanner"
end
test "renders an invisible user with the invisible property set to true" do
user = insert(:user, %{info: %{invisible: true}})
assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
end
describe "endpoints" do
test "local users have a usable endpoints structure" do
user = insert(:user)

View File

@ -12,12 +12,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
clear_config([:instance, :federating])
clear_config([:instance, :allow_relay])
describe "posting statuses" do
setup do
user = insert(:user)
@ -29,6 +33,34 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
[conn: conn]
end
test "posting a status does not increment reblog_count when relaying", %{conn: conn} do
Pleroma.Config.put([:instance, :federating], true)
Pleroma.Config.get([:instance, :allow_relay], true)
user = insert(:user)
response =
conn
|> assign(:user, user)
|> post("api/v1/statuses", %{
"content_type" => "text/plain",
"source" => "Pleroma FE",
"status" => "Hello world",
"visibility" => "public"
})
|> json_response(200)
assert response["reblogs_count"] == 0
ObanHelpers.perform_all()
response =
conn
|> assign(:user, user)
|> get("api/v1/statuses/#{response["id"]}", %{})
|> json_response(200)
assert response["reblogs_count"] == 0
end
test "posting a status", %{conn: conn} do
idempotency_key = "Pikachu rocks!"