@@ -356,4 +356,14 @@ defmodule Pleroma.Activity do | |||||
actor = user_actor(activity) | actor = user_actor(activity) | ||||
activity.id in actor.pinned_activities | activity.id in actor.pinned_activities | ||||
end | end | ||||
@spec get_by_object_ap_id_with_object(String.t()) :: t() | nil | |||||
def get_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do | |||||
ap_id | |||||
|> Queries.by_object_id() | |||||
|> with_preloaded_object() | |||||
|> Repo.one() | |||||
end | |||||
def get_by_object_ap_id_with_object(_), do: nil | |||||
end | end |
@@ -710,6 +710,22 @@ defmodule Pleroma.Web.ActivityPub.Utils do | |||||
Enum.map(statuses || [], &build_flag_object/1) | Enum.map(statuses || [], &build_flag_object/1) | ||||
end | end | ||||
defp build_flag_object(%Activity{} = activity) do | |||||
activity_actor = User.get_by_ap_id(activity.object.data["actor"]) | |||||
%{ | |||||
"type" => "Note", | |||||
"id" => activity.data["id"], | |||||
"content" => activity.object.data["content"], | |||||
"published" => activity.object.data["published"], | |||||
"actor" => | |||||
AccountView.render( | |||||
"show.json", | |||||
%{user: activity_actor, skip_visibility_check: true} | |||||
) | |||||
} | |||||
end | |||||
defp build_flag_object(act) when is_map(act) or is_binary(act) do | defp build_flag_object(act) when is_map(act) or is_binary(act) do | ||||
id = | id = | ||||
case act do | case act do | ||||
@@ -720,22 +736,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do | |||||
case Activity.get_by_ap_id_with_object(id) do | case Activity.get_by_ap_id_with_object(id) do | ||||
%Activity{} = activity -> | %Activity{} = activity -> | ||||
activity_actor = User.get_by_ap_id(activity.object.data["actor"]) | |||||
%{ | |||||
"type" => "Note", | |||||
"id" => activity.data["id"], | |||||
"content" => activity.object.data["content"], | |||||
"published" => activity.object.data["published"], | |||||
"actor" => | |||||
AccountView.render( | |||||
"show.json", | |||||
%{user: activity_actor, skip_visibility_check: true} | |||||
) | |||||
} | |||||
_ -> | |||||
%{"id" => id, "deleted" => true} | |||||
build_flag_object(activity) | |||||
nil -> | |||||
if activity = Activity.get_by_object_ap_id_with_object(id) do | |||||
build_flag_object(activity) | |||||
else | |||||
%{"id" => id, "deleted" => true} | |||||
end | |||||
end | end | ||||
end | end | ||||
@@ -0,0 +1,67 @@ | |||||
{ | |||||
"@context": [ | |||||
"https://www.w3.org/ns/activitystreams", | |||||
"https://w3id.org/security/v1", | |||||
{ | |||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers", | |||||
"toot": "http://joinmastodon.org/ns#", | |||||
"featured": { | |||||
"@id": "toot:featured", | |||||
"@type": "@id" | |||||
}, | |||||
"alsoKnownAs": { | |||||
"@id": "as:alsoKnownAs", | |||||
"@type": "@id" | |||||
}, | |||||
"movedTo": { | |||||
"@id": "as:movedTo", | |||||
"@type": "@id" | |||||
}, | |||||
"schema": "http://schema.org#", | |||||
"PropertyValue": "schema:PropertyValue", | |||||
"value": "schema:value", | |||||
"IdentityProof": "toot:IdentityProof", | |||||
"discoverable": "toot:discoverable", | |||||
"Device": "toot:Device", | |||||
"Ed25519Signature": "toot:Ed25519Signature", | |||||
"Ed25519Key": "toot:Ed25519Key", | |||||
"Curve25519Key": "toot:Curve25519Key", | |||||
"EncryptedMessage": "toot:EncryptedMessage", | |||||
"publicKeyBase64": "toot:publicKeyBase64", | |||||
"deviceId": "toot:deviceId", | |||||
"claim": { | |||||
"@type": "@id", | |||||
"@id": "toot:claim" | |||||
}, | |||||
"fingerprintKey": { | |||||
"@type": "@id", | |||||
"@id": "toot:fingerprintKey" | |||||
}, | |||||
"identityKey": { | |||||
"@type": "@id", | |||||
"@id": "toot:identityKey" | |||||
}, | |||||
"devices": { | |||||
"@type": "@id", | |||||
"@id": "toot:devices" | |||||
}, | |||||
"messageFranking": "toot:messageFranking", | |||||
"messageType": "toot:messageType", | |||||
"cipherText": "toot:cipherText" | |||||
} | |||||
], | |||||
"id": "https://{{DOMAIN}}/actor", | |||||
"type": "Application", | |||||
"inbox": "https://{{DOMAIN}}/actor/inbox", | |||||
"preferredUsername": "{{DOMAIN}}", | |||||
"url": "https://{{DOMAIN}}/about/more?instance_actor=true", | |||||
"manuallyApprovesFollowers": true, | |||||
"publicKey": { | |||||
"id": "https://{{DOMAIN}}/actor#main-key", | |||||
"owner": "https://{{DOMAIN}}/actor", | |||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAA0CA08AMIIBCgKCAQEAyi2T2FFZJgRPY+96YQrn\n6J6eF2P60J+nz+/pRc/acv/Nx+NLxxPyXby0F2s60MV7uALRQbBBnf7oNKCd/T4S\nvbr7UXMCWTdaJBpYubMKWT9uBlaUUkUfqL+WTV+IQnlcKtssQ4+AwrAKAZXza8ws\nZypevOsLHzayyEzztmm1KQC9GCUOITCLf7Q6qEhy8z/HuqLBEC0Own0pD7QsbfcS\no1peuZY7g1E/jJ9HR9GqJccMaR0H28KmJ7tT1Yzlyf5uZMRIdPxsoMR9sGLjR2B8\noegSwaf9SogR3ScP395Tt/9Ud1VVzuhpoS8Uy7jKSs+3CuLJsEGoMrib8VyOwadS\n9wIDAQAB\n-----END PUBLIC KEY-----\n" | |||||
}, | |||||
"endpoints": { | |||||
"sharedInbox": "https://{{DOMAIN}}/inbox" | |||||
} | |||||
} |
@@ -874,6 +874,65 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do | |||||
html_body: ~r/Reported Account:/i | html_body: ~r/Reported Account:/i | ||||
) | ) | ||||
end | end | ||||
test "forwarded report from mastodon", %{conn: conn} do | |||||
admin = insert(:user, is_admin: true) | |||||
actor = insert(:user, local: false) | |||||
remote_domain = URI.parse(actor.ap_id).host | |||||
remote_actor = "https://#{remote_domain}/actor" | |||||
reported_user = insert(:user) | |||||
note = insert(:note_activity, user: reported_user) | |||||
mock_json_body = | |||||
"test/fixtures/mastodon/application_actor.json" | |||||
|> File.read!() | |||||
|> String.replace("{{DOMAIN}}", remote_domain) | |||||
Tesla.Mock.mock(fn %{url: ^remote_actor} -> | |||||
%Tesla.Env{ | |||||
status: 200, | |||||
body: mock_json_body, | |||||
headers: [{"content-type", "application/activity+json"}] | |||||
} | |||||
end) | |||||
data = %{ | |||||
"@context" => "https://www.w3.org/ns/activitystreams", | |||||
"actor" => remote_actor, | |||||
"content" => "test report", | |||||
"id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8", | |||||
"nickname" => reported_user.nickname, | |||||
"object" => [ | |||||
reported_user.ap_id, | |||||
note.data["object"] | |||||
], | |||||
"type" => "Flag" | |||||
} | |||||
conn | |||||
|> assign(:valid_signature, true) | |||||
|> put_req_header("content-type", "application/activity+json") | |||||
|> post("/users/#{reported_user.nickname}/inbox", data) | |||||
|> json_response(200) | |||||
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) | |||||
assert Pleroma.Repo.aggregate(Activity, :count, :id) == 2 | |||||
flag_activity = "Flag" |> Pleroma.Activity.Queries.by_type() |> Pleroma.Repo.one() | |||||
reported_user_ap_id = reported_user.ap_id | |||||
[^reported_user_ap_id, flag_data] = flag_activity.data["object"] | |||||
Enum.each(~w(actor content id published type), &Map.has_key?(flag_data, &1)) | |||||
ObanHelpers.perform_all() | |||||
Swoosh.TestAssertions.assert_email_sent( | |||||
to: {admin.name, admin.email}, | |||||
html_body: ~r/#{note.data["object"]}/i | |||||
) | |||||
end | |||||
end | end | ||||
describe "GET /users/:nickname/outbox" do | describe "GET /users/:nickname/outbox" do | ||||