Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into pleroma-instance-domain-blocks

This commit is contained in:
Lain Soykaf 2026-01-16 14:24:14 +04:00
commit 656c4368d3
288 changed files with 6024 additions and 1531 deletions

View file

@ -0,0 +1,34 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/multikey/v1",
{
"Hashtag": "as:Hashtag"
}
],
"attributedTo": "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0",
"cc": [
"https://mymath.rocks/endpoints/30zoCe7haKBEFolH4rbAmKj-t9_bG0c2X2kMQkJk5qY",
"https://mastodon.social/users/nikclayton"
],
"content": "<blockquote class=\"h-quote\">\n<p>I note that mymath.rocks does not provide this information.</p>\n</blockquote>\n<p>I&#39;m a big believer in &quot;Do as I say, not as I <strong>did</strong>&quot;.</p>\n<p>I could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.</p>\n<p>I think the above statement also addresses a main failure of the Fediverse. People, e.g. me, would love to fix stuff. Unfortunately, we lack the focus to address a lot of issues, e.g. nodeinfo sucks. So stuff gets done in a broken way.</p>\n<p>I think the main challenge the Fediverse has faced, and failed at, is avoiding the above situation. To continue the example, there is no way for somebody to say: Let&#39;s fix nodeinfo and people will follow their ideas.</p>\n",
"id": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026",
"inReplyTo": "https://mastodon.social/users/nikclayton/statuses/115496665258618127",
"likes": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/likes",
"published": "2025-11-06T08:21:17.790Z",
"replies": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/replies",
"shares": "https://mymath.rocks/objects/2b89e564-30cf-4eeb-97ca-7e638a154026/shares",
"source": {
"content": "> I note that mymath.rocks does not provide this information.\n\nI'm a big believer in \"Do as I say, not as I __did__\".\n\nI could give a long list of technical reasons, which boil down to: nodeinfo is pretty nonsensical with the way I write stuff.\n\nI think the above statement also addresses a main failure of the Fediverse. People, e.g. me, would love to fix stuff. Unfortunately, we lack the focus to address a lot of issues, e.g. nodeinfo sucks. So stuff gets done in a broken way.\n\nI think the main challenge the Fediverse has faced, and failed at, is avoiding the above situation. To continue the example, there is no way for somebody to say: Let's fix nodeinfo and people will follow their ideas.",
"mediaType": "text/markdown"
},
"tag": {
"href": "https://mastodon.social/users/nikclayton",
"name": "https://mastodon.social/users/nikclayton",
"type": "Mention"
},
"to": "as:Public",
"type": "Note"
}

View file

@ -0,0 +1,93 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"ostatus": "http://ostatus.org#",
"atomUri": "ostatus:atomUri",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"sensitive": "as:sensitive",
"toot": "http://joinmastodon.org/ns#",
"votersCount": "toot:votersCount",
"quote": "https://w3id.org/fep/044f#quote",
"quoteUri": "http://fedibird.com/ns#quoteUri",
"_misskey_quote": "https://misskey-hub.net/ns#_misskey_quote",
"quoteAuthorization": {
"@id": "https://w3id.org/fep/044f#quoteAuthorization",
"@type": "@id"
},
"gts": "https://gotosocial.org/ns#",
"interactionPolicy": {
"@id": "gts:interactionPolicy",
"@type": "@id"
},
"canQuote": {
"@id": "gts:canQuote",
"@type": "@id"
},
"automaticApproval": {
"@id": "gts:automaticApproval",
"@type": "@id"
},
"manualApproval": {
"@id": "gts:manualApproval",
"@type": "@id"
}
}
],
"id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171",
"type": "Note",
"summary": null,
"inReplyTo": null,
"published": "2025-10-09T17:54:47Z",
"url": "https://mastodon.social/@gwynnion/115345489087257171",
"attributedTo": "https://mastodon.social/users/gwynnion",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://mastodon.social/users/gwynnion/followers"
],
"sensitive": false,
"atomUri": "https://mastodon.social/users/gwynnion/statuses/115345489087257171",
"inReplyToAtomUri": null,
"conversation": "https://mastodon.social/contexts/109836797527169643-115345489087257171",
"context": "https://mastodon.social/contexts/109836797527169643-115345489087257171",
"content": "<p class=\"quote-inline\">RE: <a href=\"https://mastodon.social/@404mediaco/115344945575874225\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">mastodon.social/@404mediaco/11</span><span class=\"invisible\">5344945575874225</span></a></p><p>Every age verification system is just a scheme for companies and hackers to steal your identity.</p>",
"contentMap": {
"en": "<p class=\"quote-inline\">RE: <a href=\"https://mastodon.social/@404mediaco/115344945575874225\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">mastodon.social/@404mediaco/11</span><span class=\"invisible\">5344945575874225</span></a></p><p>Every age verification system is just a scheme for companies and hackers to steal your identity.</p>"
},
"quote": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
"_misskey_quote": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
"quoteUri": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
"quoteAuthorization": "https://mastodon.social/users/404mediaco/quote_authorizations/115345489087269783",
"interactionPolicy": {
"canQuote": {
"automaticApproval": [
"https://www.w3.org/ns/activitystreams#Public"
]
}
},
"attachment": [],
"tag": [],
"replies": {
"id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies",
"type": "Collection",
"first": {
"type": "CollectionPage",
"next": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies?only_other_accounts=true&page=true",
"partOf": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies",
"items": []
}
},
"likes": {
"id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/likes",
"type": "Collection",
"totalItems": 26
},
"shares": {
"id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/shares",
"type": "Collection",
"totalItems": 28
}
}

View file

@ -0,0 +1,41 @@
{
"alsoKnownAs": [],
"attachment": [],
"capabilities": {},
"discoverable": true,
"endpoints": {},
"featured": "https://queef.in/cute_cat/collections/featured",
"followers": "https://queef.in/cute_cat/followers",
"following": "https://queef.in/cute_cat/following",
"icon": {
"type": "Image",
"url": [
"https://queef.in/storage/profile.webp",
"https://example.com/image"
]
},
"id": "https://queef.in/cute_cat",
"image": {
"type": "Image",
"url": [
"https://queef.in/storage/banner.gif",
"https://example.com/image"
]
},
"inbox": "https://queef.in/cute_cat/inbox",
"manuallyApprovesFollowers": false,
"name": "cute_cat",
"outbox": "https://queef.in/cute_cat/outbox",
"preferredUsername": "cute_cat",
"publicKey": {
"id": "https://queef.in/cute_cat#main-key",
"owner": "https://queef.in/cute_cat"
},
"published": "2025-08-18T01:16:10.000Z",
"summary": "A cute cat",
"tag": [],
"type": "Person",
"url": "https://queef.in/cute_cat",
"vcard:bday": null,
"webfinger": "acct:cute_cat@queef.in"
}

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.PleromaTest do
use ExUnit.Case, async: true
use ExUnit.Case, async: false
import Mix.Pleroma
setup_all do

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.AppTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
setup_all do
Mix.shell(Mix.Shell.Process)

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.DatabaseTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Activity

View file

@ -261,23 +261,27 @@ defmodule Pleroma.ActivityTest do
test "add_by_params_query/3" do
user = insert(:user)
note = insert(:note_activity, user: user)
note_activity = insert(:note_activity, user: user)
insert(:add_activity, user: user, note: note)
insert(:add_activity, user: user, note: note)
insert(:add_activity, user: user, note_activity: note_activity)
insert(:add_activity, user: user, note_activity: note_activity)
insert(:add_activity, user: user)
assert Repo.aggregate(Activity, :count, :id) == 4
assert Repo.aggregate(Activity, :count, :id) == 5
add_query =
Activity.add_by_params_query(note.data["object"], user.ap_id, user.featured_address)
Activity.add_by_params_query(
note_activity.data["object"],
user.ap_id,
user.featured_address
)
assert Repo.aggregate(add_query, :count, :id) == 2
Repo.delete_all(add_query)
assert Repo.aggregate(add_query, :count, :id) == 0
assert Repo.aggregate(Activity, :count, :id) == 2
assert Repo.aggregate(Activity, :count, :id) == 3
end
describe "associated_object_id() sql function" do

View file

@ -332,7 +332,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
# When it's a reply from the blocked user
{:ok, _direct2} =
CommonAPI.post(blocked, %{
status: "reply",
status: "@#{third_user.nickname}, #{blocker.nickname} reply",
visibility: "direct",
in_reply_to_conversation_id: blocked_participation.id
})

View file

@ -66,8 +66,10 @@ defmodule Pleroma.ConversationTest do
jafnhar = insert(:user, local: false)
tridi = insert(:user)
to = [har.nickname, jafnhar.nickname, tridi.nickname]
{:ok, activity} =
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct", to: to})
object = Pleroma.Object.normalize(activity, fetch: false)
context = object.data["context"]
@ -88,7 +90,8 @@ defmodule Pleroma.ConversationTest do
CommonAPI.post(jafnhar, %{
status: "Hey @#{har.nickname}",
visibility: "direct",
in_reply_to_status_id: activity.id
in_reply_to_status_id: activity.id,
to: to
})
object = Pleroma.Object.normalize(activity, fetch: false)
@ -112,7 +115,8 @@ defmodule Pleroma.ConversationTest do
CommonAPI.post(tridi, %{
status: "Hey @#{har.nickname}",
visibility: "direct",
in_reply_to_status_id: activity.id
in_reply_to_status_id: activity.id,
to: to
})
object = Pleroma.Object.normalize(activity, fetch: false)

View file

@ -3,10 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTPTest do
use ExUnit.Case, async: true
use ExUnit.Case, async: false
use Pleroma.Tests.Helpers
import Tesla.Mock
alias Pleroma.HTTP
alias Pleroma.Utils.URIEncoding
setup do
mock(fn
@ -28,6 +31,36 @@ defmodule Pleroma.HTTPTest do
%{method: :get, url: "https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz"} ->
%Tesla.Env{status: 200, body: "emoji data"}
%{
method: :get,
url: "https://example.com/media/foo/bar%20!$&'()*+,;=/:%20@a%20%5Bbaz%5D.mp4"
} ->
%Tesla.Env{status: 200, body: "video data"}
%{method: :get, url: "https://example.com/media/unicode%20%F0%9F%99%82%20.gif"} ->
%Tesla.Env{status: 200, body: "unicode data"}
%{
method: :get,
url:
"https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8"
} ->
%Tesla.Env{status: 200, body: "Guardian image quirk"}
%{
method: :get,
url:
"https://i.guim.co.uk/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz"
} ->
%Tesla.Env{status: 200, body: "Space in query with Guardian quirk"}
%{
method: :get,
url:
"https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
} ->
%Tesla.Env{status: 200, body: "AWS S3 data"}
end)
:ok
@ -85,5 +118,100 @@ defmodule Pleroma.HTTPTest do
{:ok, result} = HTTP.get(properly_encoded_url)
assert result.status == 200
url_with_reserved_chars = "https://example.com/media/foo/bar !$&'()*+,;=/: @a [baz].mp4"
{:ok, result} = HTTP.get(url_with_reserved_chars)
assert result.status == 200
url_with_unicode = "https://example.com/media/unicode 🙂 .gif"
{:ok, result} = HTTP.get(url_with_unicode)
assert result.status == 200
end
test "decodes URL first by default" do
clear_config(:test_url_encoding, true)
normal_url = "https://example.com/media/file%20with%20space.jpg?name=a+space.jpg"
result = URIEncoding.encode_url(normal_url)
assert result == "https://example.com/media/file%20with%20space.jpg?name=a+space.jpg"
end
test "doesn't decode URL first when specified" do
clear_config(:test_url_encoding, true)
normal_url = "https://example.com/media/file%20with%20space.jpg"
result = URIEncoding.encode_url(normal_url, bypass_decode: true)
assert result == "https://example.com/media/file%2520with%2520space.jpg"
end
test "properly applies Guardian image query quirk" do
clear_config(:test_url_encoding, true)
url =
"https://i.guim.co.uk/img/media/1069ef13c447908272c4de94174cec2b6352cb2f/0_91_2000_1201/master/2000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&precrop=40:21,offset-x50,offset-y0&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctb3BpbmlvbnMtYWdlLTIwMTkucG5n&enable=upscale&s=cba21427a73512fdc9863c486c03fdd8"
result = URIEncoding.encode_url(url)
assert result == url
{:ok, result_get} = HTTP.get(result)
assert result_get.status == 200
end
test "properly encodes spaces as \"pluses\" in query when using quirks" do
clear_config(:test_url_encoding, true)
url =
"https://i.guim.co.uk/emoji/Pack 1/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar baz"
properly_encoded_url =
"https://i.guim.co.uk/emoji/Pack%201/koronebless.png?precrop=40:21,overlay-x0,overlay-y0&foo=bar+baz"
result = URIEncoding.encode_url(url)
assert result == properly_encoded_url
{:ok, result_get} = HTTP.get(result)
assert result_get.status == 200
end
test "properly encode AWS S3 queries" do
clear_config(:test_url_encoding, true)
url =
"https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY%2F20130721%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
unencoded_url =
"https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=accessKEY/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host"
result = URIEncoding.encode_url(url)
result_unencoded = URIEncoding.encode_url(unencoded_url)
assert result == url
assert result == result_unencoded
{:ok, result_get} = HTTP.get(result)
assert result_get.status == 200
end
test "preserves query key order" do
clear_config(:test_url_encoding, true)
url = "https://example.com/foo?hjkl=qwertz&xyz=abc&bar=baz"
result = URIEncoding.encode_url(url)
assert result == url
end
end

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
import Pleroma.Factory
import Pleroma.Tests.Helpers
alias Pleroma.ConfigDB

View file

@ -396,18 +396,29 @@ defmodule Pleroma.ReverseProxyTest do
end
end
# Hackey is used for Reverse Proxy when Hackney or Finch is the Tesla Adapter
# Hackney is used for Reverse Proxy when Hackney or Finch is the Tesla Adapter
# Gun is able to proxy through Tesla, so it does not need testing as the
# test cases in the Pleroma.HTTPTest module are sufficient
describe "Hackney URL encoding:" do
setup do
ClientMock
|> expect(:request, fn :get,
"https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz",
_headers,
_body,
_opts ->
{:ok, 200, [{"content-type", "image/png"}], "It works!"}
|> expect(:request, fn
:get,
"https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz",
_headers,
_body,
_opts ->
{:ok, 200, [{"content-type", "image/png"}], "It works!"}
:get,
"https://example.com/media/foo/bar%20!$&'()*+,;=/:%20@a%20%5Bbaz%5D.mp4",
_headers,
_body,
_opts ->
{:ok, 200, [{"content-type", "video/mp4"}], "Allowed reserved chars."}
:get, "https://example.com/media/unicode%20%F0%9F%99%82%20.gif", _headers, _body, _opts ->
{:ok, 200, [{"content-type", "image/gif"}], "Unicode emoji in path"}
end)
|> stub(:stream_body, fn _ -> :done end)
|> stub(:close, fn _ -> :ok end)
@ -430,5 +441,21 @@ defmodule Pleroma.ReverseProxyTest do
assert result.status == 200
end
test "properly encodes URLs with allowed reserved characters", %{conn: conn} do
url_with_reserved_chars = "https://example.com/media/foo/bar !$&'()*+,;=/: @a [baz].mp4"
result = ReverseProxy.call(conn, url_with_reserved_chars)
assert result.status == 200
end
test "properly encodes URLs with unicode in path", %{conn: conn} do
url_with_unicode = "https://example.com/media/unicode 🙂 .gif"
result = ReverseProxy.call(conn, url_with_unicode)
assert result.status == 200
end
end
end

View file

@ -25,8 +25,8 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocationTest do
assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered}
{exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.#{type}"])
{exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.#{type}"])
{exif_original, 0} = System.cmd("exiftool", ["-m", "test/fixtures/DSCN0010.#{type}"])
{exif_filtered, 0} = System.cmd("exiftool", ["-m", "test/fixtures/DSCN0010_tmp.#{type}"])
assert String.match?(exif_original, ~r/GPS/)
refute String.match?(exif_filtered, ~r/GPS/)

View file

@ -227,20 +227,35 @@ defmodule Pleroma.UploadTest do
assert Path.basename(attachment_url["href"]) == "an%E2%80%A6%20image.jpg"
end
test "escapes reserved uri characters" do
test "escapes disallowed reserved characters in uri path" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: ":?#[]@!$&\\'()*+,;=.jpg"
filename: ":?#[]@!$&'()*+,;=.jpg"
}
{:ok, data} = Upload.store(file)
[attachment_url | _] = data["url"]
assert Path.basename(attachment_url["href"]) ==
"%3A%3F%23%5B%5D%40%21%24%26%5C%27%28%29%2A%2B%2C%3B%3D.jpg"
":%3F%23%5B%5D@!$&'()*+,;=.jpg"
end
test "double %-encodes filename" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "file with %20.jpg"
}
{:ok, data} = Upload.store(file)
[attachment_url | _] = data["url"]
assert Path.basename(attachment_url["href"]) == "file%20with%20%2520.jpg"
end
end
@ -267,4 +282,23 @@ defmodule Pleroma.UploadTest do
refute String.starts_with?(url, base_url <> "/media/")
end
end
describe "Setting a link_name for uploaded media" do
setup do: clear_config([Pleroma.Upload, :link_name], true)
test "encodes name parameter in query" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "test file.jpg"
}
{:ok, data} = Upload.store(file)
[attachment_url | _] = data["url"]
assert Path.basename(attachment_url["href"]) == "test%20file.jpg?name=test+file.jpg"
end
end
end

View file

@ -366,5 +366,13 @@ defmodule Pleroma.UserSearchTest do
assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
end
test "find users accepting chat messages only" do
user1 = insert(:user, nickname: "user1", accepts_chat_messages: true)
insert(:user, nickname: "user2", accepts_chat_messages: false)
[found_user1] = User.search("user", capabilities: ["accepts_chat_messages"])
assert found_user1.id == user1.id
end
end
end

View file

@ -430,7 +430,133 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
end
describe "/objects/:uuid/replies" do
test "it renders the top-level collection", %{
conn: conn
} do
user = insert(:user)
note = insert(:note_activity)
note = Pleroma.Activity.get_by_id_with_object(note.id)
uuid = String.split(note.object.data["id"], "/") |> List.last()
{:ok, _} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: note.id})
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get("/objects/#{uuid}/replies")
assert match?(
%{
"id" => _,
"type" => "OrderedCollection",
"totalItems" => 1,
"first" => %{
"id" => _,
"type" => "OrderedCollectionPage",
"orderedItems" => [_]
}
},
json_response(conn, 200)
)
end
test "first page id includes `?page=true`", %{conn: conn} do
user = insert(:user)
note = insert(:note_activity)
note = Pleroma.Activity.get_by_id_with_object(note.id)
uuid = String.split(note.object.data["id"], "/") |> List.last()
{:ok, _} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: note.id})
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get("/objects/#{uuid}/replies")
%{"id" => collection_id, "first" => %{"id" => page_id, "partOf" => part_of}} =
json_response(conn, 200)
assert part_of == collection_id
assert String.contains?(page_id, "page=true")
end
test "unknown query params do not crash the endpoint", %{conn: conn} do
user = insert(:user)
note = insert(:note_activity)
note = Pleroma.Activity.get_by_id_with_object(note.id)
uuid = String.split(note.object.data["id"], "/") |> List.last()
{:ok, _} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: note.id})
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get("/objects/#{uuid}/replies?unknown_param=1")
assert %{"type" => "OrderedCollection"} = json_response(conn, 200)
end
test "it renders a collection page", %{
conn: conn
} do
user = insert(:user)
note = insert(:note_activity)
note = Pleroma.Activity.get_by_id_with_object(note.id)
uuid = String.split(note.object.data["id"], "/") |> List.last()
{:ok, r1} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: note.id})
{:ok, r2} =
CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: note.id})
{:ok, _} =
CommonAPI.post(user, %{status: "reply3", in_reply_to_status_id: note.id})
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get("/objects/#{uuid}/replies?page=true&min_id=#{r1.object.id}&limit=1")
expected_uris = [r2.object.data["id"]]
assert match?(
%{
"id" => _,
"type" => "OrderedCollectionPage",
"prev" => _,
"next" => _,
"orderedItems" => ^expected_uris
},
json_response(conn, 200)
)
end
end
describe "/activities/:uuid" do
test "it does not include a top-level replies collection on activities", %{conn: conn} do
clear_config([:activitypub, :note_replies_output_limit], 1)
activity = insert(:note_activity)
activity = Activity.get_by_id_with_object(activity.id)
uuid = String.split(activity.data["id"], "/") |> List.last()
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get("/activities/#{uuid}")
res = json_response(conn, 200)
refute Map.has_key?(res, "replies")
assert get_in(res, ["object", "replies", "id"]) == activity.object.data["id"] <> "/replies"
end
test "it doesn't return a local-only activity", %{conn: conn} do
user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
@ -1580,6 +1706,41 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert object["content"] == activity["object"]["content"]
end
test "it inserts an incoming reply create activity into the database", %{conn: conn} do
user = insert(:user)
replying_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "cofe"})
data = %{
type: "Create",
object: %{
to: [Pleroma.Constants.as_public(), user.ap_id],
cc: [replying_user.follower_address],
inReplyTo: activity.object.data["id"],
content: "green tea",
type: "Note"
}
}
result =
conn
|> assign(:user, replying_user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{replying_user.nickname}/outbox", data)
|> json_response(201)
updated_object = Object.normalize(activity.object.data["id"], fetch: false)
assert Activity.get_by_ap_id(result["id"])
assert result["object"]
assert %Object{data: object} = Object.normalize(result["object"], fetch: false)
assert object["content"] == data.object.content
assert Pleroma.Web.ActivityPub.Visibility.public?(object)
assert object["inReplyTo"] == activity.object.data["id"]
assert updated_object.data["repliesCount"] == 1
end
test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do
user = insert(:user)
@ -1706,6 +1867,289 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert note_object == Object.normalize(note_activity, fetch: false)
end
test "it rejects Add to other user's collection", %{conn: conn} do
user = insert(:user)
target_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "Post"})
object = Object.normalize(activity, fetch: false)
object_id = object.data["id"]
data = %{
type: "Add",
target:
"#{Pleroma.Web.Endpoint.url()}/users/#{target_user.nickname}/collections/featured",
object: object_id
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
assert json_response(conn, 400)
end
test "it rejects Remove to other user's collection", %{conn: conn} do
user = insert(:user)
target_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "Post"})
object = Object.normalize(activity, fetch: false)
object_id = object.data["id"]
data = %{
type: "Remove",
target:
"#{Pleroma.Web.Endpoint.url()}/users/#{target_user.nickname}/collections/featured",
object: object_id
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
assert json_response(conn, 400)
end
test "it rejects updating Actor's profile", %{conn: conn} do
user = insert(:user, local: true)
user_object = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
user_object_new = Map.put(user_object, "name", "lain")
data = %{
type: "Update",
object: user_object_new
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{user.nickname}/outbox", data)
updated_user_object = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
assert updated_user_object == user_object
assert json_response(conn, 400)
end
# Actor publicKey tests are redundant with above test,
# left here for the case that Updating Actors is ever supported
test "it rejects updating Actor's publicKey", %{conn: conn} do
user = insert(:user, local: true)
{:ok, pem} = Pleroma.Keys.generate_rsa_pem()
{:ok, _, public_key} = Pleroma.Keys.keys_from_pem(pem)
# Taken from UserView
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key])
user_object = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
user_object_public_key = Map.fetch!(user_object, "publicKey")
user_object_public_key = Map.put(user_object_public_key, "publicKeyPem", public_key)
user_object_new = Map.put(user_object, "publicKey", user_object_public_key)
refute user_object == user_object_new
data = %{
type: "Update",
object: user_object_new
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{user.nickname}/outbox", data)
new_user_object = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
assert user_object == new_user_object
assert json_response(conn, 400)
end
test "it rejects updating Actor's publicKey of another user", %{conn: conn} do
user = insert(:user)
target_user = insert(:user, local: true)
{:ok, pem} = Pleroma.Keys.generate_rsa_pem()
{:ok, _, public_key} = Pleroma.Keys.keys_from_pem(pem)
# Taken from UserView
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key])
target_user_object =
Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: target_user})
target_user_object_public_key = Map.fetch!(target_user_object, "publicKey")
target_user_object_public_key =
Map.put(target_user_object_public_key, "publicKeyPem", public_key)
target_user_object_new =
Map.put(target_user_object, "publicKey", target_user_object_public_key)
refute target_user_object == target_user_object_new
data = %{
type: "Update",
object: target_user_object_new
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{target_user.nickname}/outbox", data)
new_target_user_object =
Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: target_user})
assert target_user_object == new_target_user_object
assert json_response(conn, 403)
end
test "it rejects creating Actors of type Application", %{conn: conn} do
user = insert(:user, local: true)
data = %{
type: "Create",
object: %{
type: "Application"
}
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{user.nickname}/outbox", data)
assert json_response(conn, 400)
end
test "it rejects creating Actors of type Person", %{conn: conn} do
user = insert(:user, local: true)
data = %{
type: "Create",
object: %{
type: "Person"
}
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{user.nickname}/outbox", data)
assert json_response(conn, 400)
end
test "it rejects creating Actors of type Service", %{conn: conn} do
user = insert(:user, local: true)
data = %{
type: "Create",
object: %{
type: "Service"
}
}
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> post("/users/#{user.nickname}/outbox", data)
assert json_response(conn, 400)
end
test "it rejects like activity to object invisible to actor", %{conn: conn} do
user = insert(:user)
stranger = insert(:user, local: true)
{:ok, post} = CommonAPI.post(user, %{status: "cofe", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(post)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(post, stranger)
post_object = Object.normalize(post, fetch: false)
data = %{
type: "Like",
object: %{
id: post_object.data["id"]
}
}
conn =
conn
|> assign(:user, stranger)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{stranger.nickname}/outbox", data)
assert json_response(conn, 403)
end
test "it rejects announce activity to object invisible to actor", %{conn: conn} do
user = insert(:user)
stranger = insert(:user, local: true)
{:ok, post} = CommonAPI.post(user, %{status: "cofe", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(post)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(post, stranger)
post_object = Object.normalize(post, fetch: false)
data = %{
type: "Announce",
object: %{
id: post_object.data["id"]
}
}
conn =
conn
|> assign(:user, stranger)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{stranger.nickname}/outbox", data)
assert json_response(conn, 403)
end
test "it rejects emojireact activity to object invisible to actor", %{conn: conn} do
user = insert(:user)
stranger = insert(:user, local: true)
{:ok, post} = CommonAPI.post(user, %{status: "cofe", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(post)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(post, stranger)
post_object = Object.normalize(post, fetch: false)
data = %{
type: "EmojiReact",
object: %{
id: post_object.data["id"]
},
content: "😀"
}
conn =
conn
|> assign(:user, stranger)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{stranger.nickname}/outbox", data)
assert json_response(conn, 403)
end
test "it increases like count when receiving a like action", %{conn: conn} do
note_activity = insert(:note_activity)
note_object = Object.normalize(note_activity, fetch: false)

View file

@ -465,6 +465,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
test "works with avatar/banner href as list" do
user_id = "https://queef.in/cute_cat"
user_data =
"test/fixtures/users_mock/href_as_array.json"
|> File.read!()
|> Jason.decode!()
|> Map.delete("featured")
|> Jason.encode!()
Tesla.Mock.mock(fn
%{
method: :get,
url: ^user_id
} ->
%Tesla.Env{
status: 200,
body: user_data,
headers: [{"content-type", "application/activity+json"}]
}
end)
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
assert length(user.avatar["url"]) == 1
assert length(user.banner["url"]) == 1
assert user.avatar["url"] |> List.first() |> Map.fetch!("href") ==
"https://queef.in/storage/profile.webp"
assert user.banner["url"] |> List.first() |> Map.fetch!("href") ==
"https://queef.in/storage/banner.gif"
end
test "it fetches the appropriate tag-restricted posts" do
user = insert(:user)
@ -831,7 +865,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"})
ap_id = activity.data["id"]
quote_data = %{status: "1", quote_id: activity.id}
quote_data = %{status: "1", quoted_status_id: activity.id}
# public
{:ok, _} = CommonAPI.post(user2, Map.put(quote_data, :visibility, "public"))

View file

@ -109,4 +109,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do
{:ok, filtered} = InlineQuotePolicy.filter(activity)
assert filtered == activity
end
# Mastodon uses p tags instead of span in their quote posts
# URLs in quoteUri and post content are already mismatched
test "skips objects which already have an .inline-quote p" do
object = File.read!("test/fixtures/quote_post/mastodon_quote_post.json") |> Jason.decode!()
# Normally the ObjectValidator will fix this before it reaches MRF
object = Map.put(object, "quoteUrl", object["quoteUri"])
activity = %{
"type" => "Create",
"actor" => "https://mastodon.social/users/gwynnion",
"object" => object
}
{:ok, filtered} = InlineQuotePolicy.filter(activity)
assert filtered == activity
end
end

View file

@ -1,5 +1,5 @@
defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
alias Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy

View file

@ -59,4 +59,37 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidatorTest do
assert validated.valid?
assert {:context, note["context"]} in validated.changes
end
test "a Create/Note without addressing falls back to the Note's recipients" do
user = insert(:user)
note = %{
"id" => Utils.generate_object_id(),
"type" => "Note",
"actor" => user.ap_id,
"to" => [user.follower_address],
"cc" => [],
"content" => "Hello world",
"context" => Utils.generate_context_id()
}
note_activity = %{
"id" => Utils.generate_activity_id(),
"type" => "Create",
"actor" => note["actor"],
"object" => note,
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => Utils.generate_context_id()
}
# Build metadata
{:ok, object_data} = ObjectValidator.cast_and_apply(note_activity["object"])
meta = [object_data: ObjectValidator.stringify_keys(object_data)]
validated = CreateGenericValidator.cast_and_validate(note_activity, meta)
assert validated.valid?
assert Ecto.Changeset.get_field(validated, :to) == note["to"]
assert Ecto.Changeset.get_field(validated, :cc) == note["cc"]
end
end

View file

@ -1,14 +1,46 @@
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Transmogrifier
test "it encodes the id to be a valid url" do
name = "hanapog"
url = "https://misskey.local.live/emojis/hana pog.png"
tag = Transmogrifier.build_emoji_tag({name, url})
tag = Pleroma.Emoji.build_emoji_tag({name, url})
assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png"
end
test "it does not double-encode already encoded urls" do
name = "hanapog"
url = "https://misskey.local.live/emojis/hana%20pog.png"
tag = Pleroma.Emoji.build_emoji_tag({name, url})
assert tag["id"] == url
end
test "it encodes disallowed path characters" do
name = "hanapog"
url = "https://example.com/emojis/hana[pog].png"
tag = Pleroma.Emoji.build_emoji_tag({name, url})
assert tag["id"] == "https://example.com/emojis/hana%5Bpog%5D.png"
end
test "local_url does not decode percent in filenames" do
url = Pleroma.Emoji.local_url("/emoji/hana%20pog.png")
assert url == Pleroma.Web.Endpoint.url() <> "/emoji/hana%2520pog.png"
tag = Pleroma.Emoji.build_emoji_tag({"hanapog", url})
assert tag["id"] == url
end
test "local_url encodes question marks in filenames" do
url = Pleroma.Emoji.local_url("/emoji/file?name.png")
assert url == Pleroma.Web.Endpoint.url() <> "/emoji/file%3Fname.png"
end
end

View file

@ -696,12 +696,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
describe "set_replies/1" do
setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
test "returns unmodified object if activity doesn't have self-replies" do
test "still provides reply collection id even if activity doesn't have replies yet" do
data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
assert Transmogrifier.set_replies(data) == data
object = data["object"] |> Map.delete("replies")
modified = Transmogrifier.set_replies(object)
refute object["replies"]
assert modified["replies"]
assert match?(%{"id" => "http" <> _, "totalItems" => 0}, modified["replies"])
# first page should be omitted if there are no entries anyway
refute modified["replies"]["first"]
end
test "sets `replies` collection with a limited number of self-replies" do
test "sets `replies` collection with a limited number of replies, preferring oldest" do
[user, another_user] = insert_list(2, :user)
{:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
@ -730,7 +737,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
object = Object.normalize(activity, fetch: false)
replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
assert %{"type" => "Collection", "items" => ^replies_uris} =
assert %{"type" => "OrderedCollection", "first" => %{"orderedItems" => ^replies_uris}} =
Transmogrifier.set_replies(object.data)["replies"]
end
end

View file

@ -9,7 +9,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
@ -123,6 +126,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert activity.data["context"] == object.data["context"]
end
test "it fixes the public scope addressing" do
insert(:user,
ap_id: "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0"
)
object =
"test/fixtures/bovine-bogus-public-note.json"
|> File.read!()
|> Jason.decode!()
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"actor" => "https://mymath.rocks/endpoints/SYn3cl_N4HAPfPHgo2x37XunLEmhV9LnxCggcYwyec0",
"object" => object
}
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
object = Object.normalize(activity, fetch: false)
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
assert "https://www.w3.org/ns/activitystreams#Public" in object.data["to"]
end
test "it keeps link tags" do
insert(:user, ap_id: "https://example.org/users/alice")
@ -506,6 +533,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert is_nil(modified["object"]["announcements"])
assert is_nil(modified["object"]["announcement_count"])
assert is_nil(modified["object"]["generator"])
assert is_nil(modified["object"]["rules"])
assert is_nil(modified["object"]["language"])
assert is_nil(modified["object"]["voters"])
end
test "it strips internal fields of article" do
@ -563,6 +593,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
test "it can handle Listen activities" do
listen_activity = insert(:listen)
# This has an inlined object as in ObjectView
{:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
assert modified["type"] == "Listen"
@ -571,7 +602,36 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
{:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
user_ap_id = user.ap_id
activity_ap_id = activity.data["id"]
activity_to = activity.data["to"]
activity_cc = activity.data["cc"]
object_ap_id = activity.data["object"]
object_type = activity.object.data["type"]
# This does not have an inlined object
{:ok, modified2} = Transmogrifier.prepare_outgoing(activity.data)
assert match?(
%{
"@context" => [_ | _],
"type" => "Listen",
"actor" => ^user_ap_id,
"to" => ^activity_to,
"cc" => ^activity_cc,
"context" => "http://localhost" <> _,
"id" => ^activity_ap_id,
"object" => %{
"actor" => ^user_ap_id,
"attributedTo" => ^user_ap_id,
"id" => ^object_ap_id,
"type" => ^object_type,
"to" => ^activity_to,
"cc" => ^activity_cc
}
},
modified2
)
end
test "custom emoji urls are URI encoded" do
@ -611,11 +671,115 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} = prepared["object"]
end
test "Updates of Actors are handled" do
user = insert(:user, local: true)
changeset = User.update_changeset(user, %{name: "new name"})
{:ok, unpersisted_user} = Ecto.Changeset.apply_action(changeset, :update)
updated_object =
UserView.render("user.json", user: unpersisted_user)
|> Map.delete("@context")
{:ok, update_data, []} = Builder.update(user, updated_object)
{:ok, activity, _} =
Pipeline.common_pipeline(update_data,
local: true,
user_update_changeset: changeset
)
assert {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data)
assert prepared["type"] == "Update"
assert prepared["@context"]
assert prepared["object"]["type"] == user.actor_type
end
test "Correctly handles Undo activities" do
blocked = insert(:user)
blocker = insert(:user, local: true)
blocked_ap_id = blocked.ap_id
blocker_ap_id = blocker.ap_id
{:ok, %Activity{} = block_activity} = CommonAPI.block(blocked, blocker)
{:ok, %Activity{} = undo_activity} = CommonAPI.unblock(blocked, blocker)
{:ok, data} = Transmogrifier.prepare_outgoing(undo_activity.data)
block_ap_id = block_activity.data["id"]
assert is_binary(block_ap_id)
assert match?(
%{
"@context" => [_ | _],
"type" => "Undo",
"id" => "http://localhost" <> _,
"actor" => ^blocker_ap_id,
"object" => ^block_ap_id,
"to" => [^blocked_ap_id],
"cc" => [],
"bto" => [],
"bcc" => []
},
data
)
end
test "Correctly handles EmojiReact activities" do
user = insert(:user, local: true)
note_activity = insert(:note_activity)
user_ap_id = user.ap_id
user_followers = user.follower_address
note_author = note_activity.data["actor"]
note_ap_id = note_activity.data["object"]
assert is_binary(note_author)
assert is_binary(note_ap_id)
{:ok, react_activity} = CommonAPI.react_with_emoji(note_activity.id, user, "🐈")
{:ok, data} = Transmogrifier.prepare_outgoing(react_activity.data)
assert match?(
%{
"@context" => [_ | _],
"type" => "EmojiReact",
"actor" => ^user_ap_id,
"to" => [^user_followers, ^note_author],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"],
"bto" => [],
"bcc" => [],
"content" => "🐈",
"context" => "2hu",
"id" => "http://localhost" <> _,
"object" => ^note_ap_id,
"tag" => []
},
data
)
end
test "EmojiReact custom emoji urls are URI encoded" do
user = insert(:user, local: true)
note_activity = insert(:note_activity)
{:ok, react_activity} = CommonAPI.react_with_emoji(note_activity.id, user, ":dinosaur:")
{:ok, data} = Transmogrifier.prepare_outgoing(react_activity.data)
assert length(data["tag"]) == 1
tag = List.first(data["tag"])
url = tag["icon"]["url"]
assert url == "http://localhost:4001/emoji/dino%20walking.gif"
assert tag["id"] == "http://localhost:4001/emoji/dino%20walking.gif"
end
test "it prepares a quote post" do
user = insert(:user)
{:ok, quoted_post} = CommonAPI.post(user, %{status: "hey"})
{:ok, quote_post} = CommonAPI.post(user, %{status: "hey", quote_id: quoted_post.id})
{:ok, quote_post} = CommonAPI.post(user, %{status: "hey", quoted_status_id: quoted_post.id})
{:ok, modified} = Transmogrifier.prepare_outgoing(quote_post.data)

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Repo

View file

@ -49,9 +49,39 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
replies_uris = [self_reply1.object.data["id"]]
result = ObjectView.render("object.json", %{object: refresh_record(activity)})
assert %{"type" => "Collection", "items" => ^replies_uris} =
assert %{
"type" => "OrderedCollection",
"id" => _,
"first" => %{"orderedItems" => ^replies_uris}
} =
get_in(result, ["object", "replies"])
end
test "renders a replies collection on its own" do
user = insert(:user)
activity = insert(:note_activity, user: user)
activity = Pleroma.Activity.get_by_id_with_object(activity.id)
{:ok, r1} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id})
{:ok, r2} =
CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id})
replies_uris = [r1.object.data["id"], r2.object.data["id"]]
result =
ObjectView.render("object_replies.json", %{
render_params: %{object_ap_id: activity.object.data["id"]}
})
%{
"type" => "OrderedCollection",
"id" => _,
"totalItems" => 2,
"first" => %{"orderedItems" => ^replies_uris}
} = result
end
end
test "renders a like activity" do
@ -95,4 +125,23 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
assert result["object"] == announce.data["id"]
assert result["type"] == "Undo"
end
test "renders a listen activity" do
audio = insert(:audio)
user = insert(:user)
{:ok, listen_activity} = CommonAPI.listen(user, audio.data)
result = ObjectView.render("object.json", %{object: listen_activity})
assert result["id"] == listen_activity.data["id"]
assert result["to"] == listen_activity.data["to"]
assert result["type"] == "Listen"
assert result["object"]["album"] == listen_activity.data["album"]
assert result["object"]["artist"] == listen_activity.data["artist"]
assert result["object"]["length"] == listen_activity.data["length"]
assert result["object"]["title"] == listen_activity.data["title"]
assert result["object"]["type"] == "Audio"
assert result["@context"]
end
end

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.UserViewTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
import Pleroma.Factory
alias Pleroma.User
@ -169,6 +169,18 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
user = Map.merge(user, %{hide_followers_count: false, hide_followers: true})
assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
end
test "does not hide follower items based on `hide_follows`" do
user = insert(:user)
follower = insert(:user)
{:ok, user, _follower, _activity} = CommonAPI.follow(user, follower)
user = Map.merge(user, %{hide_followers: false, hide_follows: true})
follower_ap_id = follower.ap_id
assert %{"first" => %{"orderedItems" => [^follower_ap_id]}} =
UserView.render("followers.json", %{user: user})
end
end
describe "following" do

View file

@ -57,6 +57,28 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
} = response
end
test "success with redirect_uris array", %{conn: conn} do
base_url = Endpoint.url()
app_name = "Trusted app"
response =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/oauth_app", %{
name: app_name,
redirect_uris: [base_url]
})
|> json_response_and_validate_schema(200)
assert %{
"client_id" => _,
"client_secret" => _,
"name" => ^app_name,
"redirect_uri" => ^base_url,
"trusted" => false
} = response
end
test "with trusted", %{conn: conn} do
base_url = Endpoint.url()
app_name = "Trusted app"

View file

@ -20,14 +20,20 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraftTest do
{:ok, local} = CommonAPI.post(user, %{status: ".", visibility: "local"})
{:ok, public} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:error, _} = ActivityDraft.create(user, %{status: "nice", quote_id: direct.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quote_id: private.id})
{:error, _} = ActivityDraft.create(another_user, %{status: "nice", quote_id: private.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quote_id: unlisted.id})
{:ok, _} = ActivityDraft.create(another_user, %{status: "nice", quote_id: unlisted.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quote_id: local.id})
{:ok, _} = ActivityDraft.create(another_user, %{status: "nice", quote_id: local.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quote_id: public.id})
{:ok, _} = ActivityDraft.create(another_user, %{status: "nice", quote_id: public.id})
{:error, _} = ActivityDraft.create(user, %{status: "nice", quoted_status_id: direct.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quoted_status_id: private.id})
{:error, _} =
ActivityDraft.create(another_user, %{status: "nice", quoted_status_id: private.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quoted_status_id: unlisted.id})
{:ok, _} =
ActivityDraft.create(another_user, %{status: "nice", quoted_status_id: unlisted.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quoted_status_id: local.id})
{:ok, _} = ActivityDraft.create(another_user, %{status: "nice", quoted_status_id: local.id})
{:ok, _} = ActivityDraft.create(user, %{status: "nice", quoted_status_id: public.id})
{:ok, _} = ActivityDraft.create(another_user, %{status: "nice", quoted_status_id: public.id})
end
end

View file

@ -830,7 +830,9 @@ defmodule Pleroma.Web.CommonAPITest do
user = insert(:user)
{:ok, quoted} = CommonAPI.post(user, %{status: "Hello world"})
{:ok, quote_post} = CommonAPI.post(user, %{status: "nice post", quote_id: quoted.id})
{:ok, quote_post} =
CommonAPI.post(user, %{status: "nice post", quoted_status_id: quoted.id})
quoted = Object.normalize(quoted)
quote_post = Object.normalize(quote_post)
@ -841,13 +843,25 @@ defmodule Pleroma.Web.CommonAPITest do
refute quoted.data["actor"] in quote_post.data["to"]
end
test "it supports fallback from `quote_id`" do
user = insert(:user)
{:ok, quoted} = CommonAPI.post(user, %{status: "Hello world"})
{:ok, quote_post} = CommonAPI.post(user, %{status: "nice post", quote_id: quoted.id})
quoted = Object.normalize(quoted)
quote_post = Object.normalize(quote_post)
assert quote_post.data["quoteUrl"] == quoted.data["id"]
end
test "quote posting with explicit addressing doesn't mention the OP" do
user = insert(:user)
{:ok, quoted} = CommonAPI.post(user, %{status: "Hello world"})
{:ok, quote_post} =
CommonAPI.post(user, %{status: "nice post", quote_id: quoted.id, to: []})
CommonAPI.post(user, %{status: "nice post", quoted_status_id: quoted.id, to: []})
assert Object.normalize(quote_post).data["to"] == [Pleroma.Constants.as_public()]
end
@ -862,15 +876,15 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, local} = CommonAPI.post(user, %{status: ".", visibility: "local"})
{:ok, public} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:error, _} = CommonAPI.post(user, %{status: "nice", quote_id: direct.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quote_id: private.id})
{:error, _} = CommonAPI.post(another_user, %{status: "nice", quote_id: private.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quote_id: unlisted.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quote_id: unlisted.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quote_id: local.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quote_id: local.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quote_id: public.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quote_id: public.id})
{:error, _} = CommonAPI.post(user, %{status: "nice", quoted_status_id: direct.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quoted_status_id: private.id})
{:error, _} = CommonAPI.post(another_user, %{status: "nice", quoted_status_id: private.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quoted_status_id: unlisted.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quoted_status_id: unlisted.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quoted_status_id: local.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quoted_status_id: local.id})
{:ok, _} = CommonAPI.post(user, %{status: "nice", quoted_status_id: public.id})
{:ok, _} = CommonAPI.post(another_user, %{status: "nice", quoted_status_id: public.id})
end
test "it properly mentions punycode domain" do
@ -1072,7 +1086,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "only public can be pinned", %{user: user} do
{:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
{:error, :visibility_error} = CommonAPI.pin(activity.id, user)
{:error, :non_public_error} = CommonAPI.pin(activity.id, user)
end
test "unpin status", %{user: user, activity: activity} do
@ -1286,6 +1300,47 @@ defmodule Pleroma.Web.CommonAPITest do
} = flag_activity
end
test "doesn't create a report when post is not visible to user" do
reporter = insert(:user)
target_user = insert(:user)
{:ok, post} = CommonAPI.post(target_user, %{status: "Eric", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(post)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(post, reporter)
# Fails when all status are invisible
report_data = %{
account_id: target_user.id,
comment: "foobar",
status_ids: [post.id]
}
assert {:error, :visibility_error} = CommonAPI.report(reporter, report_data)
end
test "doesn't create a report when some posts are not visible to user" do
reporter = insert(:user)
target_user = insert(:user)
{:ok, visible_activity} = CommonAPI.post(target_user, %{status: "cofe"})
{:ok, invisibile_activity} =
CommonAPI.post(target_user, %{status: "cawfee", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(invisibile_activity)
assert Pleroma.Web.ActivityPub.Visibility.public?(visible_activity)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(invisibile_activity, reporter)
# Fails when some statuses are invisible
report_data_partial = %{
account_id: target_user.id,
comment: "foobar",
status_ids: [visible_activity.id, invisibile_activity.id]
}
assert {:error, :visibility_error} = CommonAPI.report(reporter, report_data_partial)
end
test "updates report state" do
[reporter, target_user] = insert_pair(:user)
activity = insert(:note_activity, user: target_user)

View file

@ -77,6 +77,10 @@ defmodule Pleroma.Web.FallbackTest do
assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/"
end
test "GET /phoenix/live_dashboard -> /pleroma/live_dashboard", %{conn: conn} do
assert redirected_to(get(conn, "/phoenix/live_dashboard")) =~ "/pleroma/live_dashboard"
end
test "OPTIONS /*path", %{conn: conn} do
assert conn
|> options("/foo")

View file

@ -2104,6 +2104,50 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|> json_response_and_validate_schema(404)
end
test "account lookup with restrict unauthenticated profiles for local" do
clear_config([:restrict_unauthenticated, :profiles, :local], true)
user = insert(:user, local: true)
reading_user = insert(:user)
conn =
build_conn()
|> get("/api/v1/accounts/lookup?acct=#{user.nickname}")
assert json_response_and_validate_schema(conn, 401)
conn =
build_conn()
|> assign(:user, reading_user)
|> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
|> get("/api/v1/accounts/lookup?acct=#{user.nickname}")
assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
assert id == user.id
end
test "account lookup with restrict unauthenticated profiles for remote" do
clear_config([:restrict_unauthenticated, :profiles, :remote], true)
user = insert(:user, nickname: "user@example.com", local: false)
reading_user = insert(:user)
conn =
build_conn()
|> get("/api/v1/accounts/lookup?acct=#{user.nickname}")
assert json_response_and_validate_schema(conn, 401)
conn =
build_conn()
|> assign(:user, reading_user)
|> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
|> get("/api/v1/accounts/lookup?acct=#{user.nickname}")
assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
assert id == user.id
end
test "create a note on a user" do
%{conn: conn} = oauth_access(["write:accounts", "read:follows"])
other_user = insert(:user)

View file

@ -61,6 +61,33 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
assert app.user_id == nil
end
test "creates an oauth app with redirect_uris array", %{conn: conn} do
app_attrs = build(:oauth_app)
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/apps", %{
client_name: app_attrs.client_name,
redirect_uris: [app_attrs.redirect_uris]
})
[app] = Repo.all(App)
expected = %{
"name" => app.client_name,
"website" => app.website,
"client_id" => app.client_id,
"client_secret" => app.client_secret,
"id" => app.id |> to_string(),
"redirect_uri" => app.redirect_uris,
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
}
assert expected == json_response_and_validate_schema(conn, 200)
assert app.user_id == nil
end
test "creates an oauth app with a user", %{conn: conn} do
user = insert(:user)
app_attrs = build(:oauth_app)

View file

@ -10,6 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
import Pleroma.Factory
defp extract_next_link_header(header) do
[_, next_link] = Regex.run(~r{<(?<next_link>.*)>; rel="next"}, header)
next_link
end
describe "locked accounts" do
setup do
user = insert(:user, is_locked: true)
@ -31,6 +36,23 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
assert to_string(other_user.id) == relationship["id"]
end
test "/api/v1/follow_requests paginates", %{user: user, conn: conn} do
for _ <- 1..21 do
other_user = insert(:user)
{:ok, _, _, _activity} = CommonAPI.follow(other_user, user)
{:ok, _, _} = User.follow(other_user, user, :follow_pending)
end
conn = get(conn, "/api/v1/follow_requests")
assert length(json_response_and_validate_schema(conn, 200)) == 20
assert [link_header] = get_resp_header(conn, "link")
assert link_header =~ "rel=\"next\""
next_link = extract_next_link_header(link_header)
assert next_link =~ "/api/v1/follow_requests"
conn = get(conn, next_link)
assert length(json_response_and_validate_schema(conn, 200)) == 1
end
test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do
other_user = insert(:user)

View file

@ -316,6 +316,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:notifications"])
{:ok, _, _, %{data: %{"state" => "accept"}}} = CommonAPI.follow(other_user, user)
{:ok, _, _, %{data: %{"state" => "accept"}}} = CommonAPI.follow(user, other_user)
{:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"})
{:ok, direct_activity} =

View file

@ -147,7 +147,7 @@ defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do
|> json_response_and_validate_schema(400)
end
test "returns error when account is not exist", %{
test "returns error when account does not exist", %{
conn: conn,
activity: activity
} do
@ -159,6 +159,51 @@ defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do
assert json_response_and_validate_schema(conn, 400) == %{"error" => "Account not found"}
end
test "returns not found when post isn't visible to reporter", %{user: target_user} do
%{conn: conn, user: reporter} = oauth_access(["write:reports"])
{:ok, invisible_activity} =
CommonAPI.post(target_user, %{status: "Invisible!", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(invisible_activity)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(invisible_activity, reporter)
assert %{"error" => "Record not found"} =
conn
|> put_req_header("content-type", "application/json")
|> post(
"/api/v1/reports",
%{"account_id" => target_user.id, "status_ids" => [invisible_activity.id]}
)
|> json_response_and_validate_schema(404)
end
test "returns not found when some post aren't visible to reporter", %{
activity: activity,
user: target_user
} do
%{conn: conn, user: reporter} = oauth_access(["write:reports"])
{:ok, invisible_activity} =
CommonAPI.post(target_user, %{status: "Invisible!", visibility: "private"})
assert Pleroma.Web.ActivityPub.Visibility.private?(invisible_activity)
assert Pleroma.Web.ActivityPub.Visibility.visible_for_user?(activity, reporter)
refute Pleroma.Web.ActivityPub.Visibility.visible_for_user?(invisible_activity, reporter)
assert %{"error" => "Record not found"} =
conn
|> put_req_header("content-type", "application/json")
|> post(
"/api/v1/reports",
%{
"account_id" => target_user.id,
"status_ids" => [activity.id, invisible_activity.id]
}
)
|> json_response_and_validate_schema(404)
end
test "doesn't fail if an admin has no email", %{conn: conn, target_user: target_user} do
insert(:user, %{is_admin: true, email: nil})

View file

@ -105,6 +105,25 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
test "encodes emoji urls in the emojis field" do
user =
insert(:user,
name: ":brackets: :percent:",
emoji: %{
"brackets" => "/emoji/hana[pog].png",
"percent" => "/emoji/hana%20pog.png"
}
)
%{emojis: emojis} =
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
emoji_urls = Map.new(emojis, &{&1.shortcode, &1.url})
assert emoji_urls["brackets"] == "/emoji/hana%5Bpog%5D.png"
assert emoji_urls["percent"] == "/emoji/hana%2520pog.png"
end
describe "roles and privileges" do
setup do
clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])

View file

@ -219,7 +219,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
data: %{
"reactions" => [
["👍", [user.ap_id], nil],
["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino walking.gif"]
["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino%20walking.gif"]
]
}
)
@ -243,7 +243,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
account: AccountView.render("show.json", %{user: other_user, for: user}),
status: StatusView.render("show.json", %{activity: activity, for: user}),
created_at: Utils.to_masto_date(notification.inserted_at),
emoji_url: "http://localhost:4001/emoji/dino walking.gif"
emoji_url: "http://localhost:4001/emoji/dino%20walking.gif"
}
test_notifications_rendering([notification], user, [expected])

View file

@ -54,7 +54,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
count: 2,
me: false,
name: "dinosaur",
url: "http://localhost:4001/emoji/dino walking.gif",
url: "http://localhost:4001/emoji/dino%20walking.gif",
account_ids: [other_user.id, user.id]
},
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
@ -70,7 +70,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
count: 2,
me: true,
name: "dinosaur",
url: "http://localhost:4001/emoji/dino walking.gif",
url: "http://localhost:4001/emoji/dino%20walking.gif",
account_ids: [other_user.id, user.id]
},
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
@ -344,7 +344,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
quotes_count: 0,
bookmark_folder: nil,
list_id: nil
}
},
quotes_count: 0
}
assert status == expected
@ -436,8 +437,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
post = insert(:note_activity)
user = insert(:user)
{:ok, quote_post} = CommonAPI.post(user, %{status: "he", quote_id: post.id})
{:ok, quoted_quote_post} = CommonAPI.post(user, %{status: "yo", quote_id: quote_post.id})
{:ok, quote_post} = CommonAPI.post(user, %{status: "he", quoted_status_id: post.id})
{:ok, quoted_quote_post} =
CommonAPI.post(user, %{status: "yo", quoted_status_id: quote_post.id})
status = StatusView.render("show.json", %{activity: quoted_quote_post})
@ -508,7 +511,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
post = insert(:note_activity)
user = insert(:user)
{:ok, quote_post} = CommonAPI.post(user, %{status: "he", quote_id: post.id})
{:ok, quote_post} = CommonAPI.post(user, %{status: "he", quoted_status_id: post.id})
{:ok, repost} = CommonAPI.repeat(quote_post.id, user)
[status] = StatusView.render("index.json", %{activities: [repost], as: :activity})

View file

@ -73,7 +73,7 @@ defmodule Pleroma.Web.MediaProxyTest do
end
test "encodes and decodes URL and ignores query params for the path" do
url = "https://pleroma.soykaf.com/static/logo.png?93939393939&bunny=true"
url = "https://pleroma.soykaf.com/static/logo.png?93939393939=&bunny=true"
encoded = MediaProxy.url(url)
assert String.ends_with?(encoded, "/logo.png")
assert decode_result(encoded) == url
@ -159,18 +159,6 @@ defmodule Pleroma.Web.MediaProxyTest do
assert String.starts_with?(encoded, base_url)
end
# Some sites expect ASCII encoded characters in the URL to be preserved even if
# unnecessary.
# Issues: https://git.pleroma.social/pleroma/pleroma/issues/580
# https://git.pleroma.social/pleroma/pleroma/issues/1055
test "preserve ASCII encoding" do
url =
"https://pleroma.com/%20/%21/%22/%23/%24/%25/%26/%27/%28/%29/%2A/%2B/%2C/%2D/%2E/%2F/%30/%31/%32/%33/%34/%35/%36/%37/%38/%39/%3A/%3B/%3C/%3D/%3E/%3F/%40/%41/%42/%43/%44/%45/%46/%47/%48/%49/%4A/%4B/%4C/%4D/%4E/%4F/%50/%51/%52/%53/%54/%55/%56/%57/%58/%59/%5A/%5B/%5C/%5D/%5E/%5F/%60/%61/%62/%63/%64/%65/%66/%67/%68/%69/%6A/%6B/%6C/%6D/%6E/%6F/%70/%71/%72/%73/%74/%75/%76/%77/%78/%79/%7A/%7B/%7C/%7D/%7E/%7F/%80/%81/%82/%83/%84/%85/%86/%87/%88/%89/%8A/%8B/%8C/%8D/%8E/%8F/%90/%91/%92/%93/%94/%95/%96/%97/%98/%99/%9A/%9B/%9C/%9D/%9E/%9F/%C2%A0/%A1/%A2/%A3/%A4/%A5/%A6/%A7/%A8/%A9/%AA/%AB/%AC/%C2%AD/%AE/%AF/%B0/%B1/%B2/%B3/%B4/%B5/%B6/%B7/%B8/%B9/%BA/%BB/%BC/%BD/%BE/%BF/%C0/%C1/%C2/%C3/%C4/%C5/%C6/%C7/%C8/%C9/%CA/%CB/%CC/%CD/%CE/%CF/%D0/%D1/%D2/%D3/%D4/%D5/%D6/%D7/%D8/%D9/%DA/%DB/%DC/%DD/%DE/%DF/%E0/%E1/%E2/%E3/%E4/%E5/%E6/%E7/%E8/%E9/%EA/%EB/%EC/%ED/%EE/%EF/%F0/%F1/%F2/%F3/%F4/%F5/%F6/%F7/%F8/%F9/%FA/%FB/%FC/%FD/%FE/%FF"
encoded = MediaProxy.url(url)
assert decode_result(encoded) == url
end
# This includes unsafe/reserved characters which are not interpreted as part of the URL
# and would otherwise have to be ASCII encoded. It is our role to ensure the proxied URL
# is unmodified, so we are testing these characters anyway.
@ -182,11 +170,30 @@ defmodule Pleroma.Web.MediaProxyTest do
assert decode_result(encoded) == url
end
test "preserve unicode characters" do
# Improperly encoded URLs should not happen even when input was wrong.
test "does not preserve unicode characters" do
url = "https://ko.wikipedia.org/wiki/위키백과:대문"
encoded_url =
"https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EB%8C%80%EB%AC%B8"
encoded = MediaProxy.url(url)
assert decode_result(encoded) == url
assert decode_result(encoded) == encoded_url
end
# If we preserve wrongly encoded URLs in MediaProxy, it will get fixed
# when we GET these URLs and will result in 424 when MediaProxy previews are enabled.
test "does not preserve incorrect URLs when making MediaProxy link" do
incorrect_original_url = "https://example.com/media/cofe%20%28with%20milk%29.png"
corrected_original_url = "https://example.com/media/cofe%20(with%20milk).png"
unpreserved_encoded_original_url =
"http://localhost:4001/proxy/Sv6tt6xjA72_i4d8gXbuMAOXQSs/aHR0cHM6Ly9leGFtcGxlLmNvbS9tZWRpYS9jb2ZlJTIwKHdpdGglMjBtaWxrKS5wbmc/cofe%20(with%20milk).png"
encoded = MediaProxy.url(incorrect_original_url)
assert encoded == unpreserved_encoded_original_url
assert decode_result(encoded) == corrected_original_url
end
end

View file

@ -337,6 +337,41 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
end
end
describe "POST /api/v1/pleroma/chats/:id/pin" do
setup do: oauth_access(["write:chats"])
test "it pins a chat", %{conn: conn, user: user} do
other_user = insert(:user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
result =
conn
|> post("/api/v1/pleroma/chats/#{chat.id}/pin")
|> json_response_and_validate_schema(200)
assert %{"pinned" => true} = result
end
end
describe "POST /api/v1/pleroma/chats/:id/unpin" do
setup do: oauth_access(["write:chats"])
test "it unpins a chat", %{conn: conn, user: user} do
other_user = insert(:user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
{:ok, chat} = Chat.pin(chat)
result =
conn
|> post("/api/v1/pleroma/chats/#{chat.id}/unpin")
|> json_response_and_validate_schema(200)
assert %{"pinned" => false} = result
end
end
for tested_endpoint <- ["/api/v1/pleroma/chats", "/api/v2/pleroma/chats"] do
describe "GET #{tested_endpoint}" do
setup do: oauth_access(["read:chats"])
@ -407,6 +442,21 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
assert length(result) == 1
end
test "it only returns pinned chats", %{conn: conn, user: user} do
recipient1 = insert(:user)
recipient2 = insert(:user)
{:ok, %{id: id} = chat} = Chat.get_or_create(user.id, recipient1.ap_id)
{:ok, _} = Chat.get_or_create(user.id, recipient2.ap_id)
Chat.pin(chat)
[%{"id" => ^id, "pinned" => true}] =
conn
|> get("#{unquote(tested_endpoint)}?pinned=true")
|> json_response_and_validate_schema(200)
end
if tested_endpoint == "/api/v1/pleroma/chats" do
test "it returns all chats", %{conn: conn, user: user} do
Enum.each(1..30, fn _ ->

View file

@ -9,10 +9,38 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
defp prepare_reacted_post(visibility \\ "private") do
unrelated_user = insert(:user, local: true)
poster = insert(:user, local: true)
follower = insert(:user, local: true)
{:ok, _, _, %{data: %{"state" => "accept"}}} = CommonAPI.follow(poster, follower)
{:ok, post_activity} = CommonAPI.post(poster, %{status: "miaow!", visibility: visibility})
if visibility != "direct" do
assert Visibility.visible_for_user?(post_activity, follower)
end
if visibility in ["direct", "private"] do
refute Visibility.visible_for_user?(post_activity, unrelated_user)
end
{:ok, _react_activity} = CommonAPI.react_with_emoji(post_activity.id, follower, "🐾")
{post_activity, poster, follower, unrelated_user}
end
defp prepare_conn_of_user(conn, user) do
conn
|> assign(:user, user)
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write", "read"]))
end
setup do
Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Test.StaticConfig)
:ok
@ -72,7 +100,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
"name" => "dinosaur",
"count" => 1,
"me" => true,
"url" => "http://localhost:4001/emoji/dino walking.gif",
"url" => "http://localhost:4001/emoji/dino%20walking.gif",
"account_ids" => [other_user.id]
}
]
@ -137,6 +165,28 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
|> json_response_and_validate_schema(400)
end
test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji not allowed for non-visible posts", %{
conn: conn
} do
{%{id: activity_id} = _activity, _author, follower, stranger} = prepare_reacted_post()
# Works for follower
resp =
prepare_conn_of_user(conn, follower)
|> put("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐈")
|> json_response_and_validate_schema(200)
assert match?(%{"id" => ^activity_id}, resp)
# Fails for stranger
resp =
prepare_conn_of_user(conn, stranger)
|> put("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐈")
|> json_response_and_validate_schema(404)
assert match?(%{"error" => "Record not found"}, resp)
end
test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
@ -211,6 +261,26 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
|> json_response(400)
end
test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji only allows original reacter to revoke",
%{conn: conn} do
{%{id: activity_id} = _activity, author, follower, unrelated} = prepare_reacted_post("public")
# Works for original reacter
prepare_conn_of_user(conn, follower)
|> delete("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐾")
|> json_response_and_validate_schema(200)
# Fails for anyone else
for u <- [author, unrelated] do
resp =
prepare_conn_of_user(conn, u)
|> delete("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐾")
|> json_response(400)
assert match?(%{"error" => _}, resp)
end
end
test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
@ -324,6 +394,25 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
assert [%{"name" => "🎅", "count" => 2}] = result
end
test "GET /api/v1/pleroma/statuses/:id/reactions not allowed for non-visible posts", %{
conn: conn
} do
{%{id: activity_id} = _activity, _author, follower, stranger} = prepare_reacted_post()
# Works for follower
resp =
prepare_conn_of_user(conn, follower)
|> get("/api/v1/pleroma/statuses/#{activity_id}/reactions")
|> json_response_and_validate_schema(200)
assert match?([%{"name" => _, "count" => _} | _], resp)
# Fails for stranger
assert prepare_conn_of_user(conn, stranger)
|> get("/api/v1/pleroma/statuses/#{activity_id}/reactions")
|> json_response_and_validate_schema(404) == %{"error" => "Record not found"}
end
test "GET /api/v1/pleroma/statuses/:id/reactions with :show_reactions disabled", %{conn: conn} do
clear_config([:instance, :show_reactions], false)
@ -372,4 +461,20 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
assert represented_user["id"] == other_user.id
end
test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji not allowed for non-visible posts", %{
conn: conn
} do
{%{id: activity_id} = _activity, _author, follower, stranger} = prepare_reacted_post()
# Works for follower
assert prepare_conn_of_user(conn, follower)
|> get("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐈")
|> json_response_and_validate_schema(200)
# Fails for stranger
assert prepare_conn_of_user(conn, stranger)
|> get("/api/v1/pleroma/statuses/#{activity_id}/reactions/🐈")
|> json_response_and_validate_schema(404) == %{"error" => "Record not found"}
end
end

View file

@ -0,0 +1,17 @@
defmodule Pleroma.Web.PleromaAPI.FrontendSettingsControllerTest do
use Pleroma.Web.ConnCase, async: false
describe "PUT /api/v1/pleroma/preferred_frontend" do
test "sets a cookie with selected frontend" do
%{conn: conn} = oauth_access(["read"])
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/pleroma/preferred_frontend", %{"frontend_name" => "pleroma-fe/stable"})
json_response_and_validate_schema(response, 200)
assert %{"preferred_frontend" => %{value: "pleroma-fe/stable"}} = response.resp_cookies
end
end
end

View file

@ -9,7 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do
describe "POST /api/v1/pleroma/scrobble" do
test "works correctly" do
%{conn: conn} = oauth_access(["write"])
%{conn: conn} = oauth_access(["write:scrobbles"])
conn =
conn
@ -51,7 +51,7 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do
describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do
test "works correctly" do
%{user: user, conn: conn} = oauth_access(["read"])
%{user: user, conn: conn} = oauth_access(["read:scrobbles"])
{:ok, _activity} =
CommonAPI.listen(user, %{

View file

@ -9,46 +9,22 @@ defmodule Pleroma.Web.PleromaAPI.StatusControllerTest do
import Pleroma.Factory
describe "getting quotes of a specified post" do
setup do
[current_user, user] = insert_pair(:user)
%{user: current_user, conn: conn} = oauth_access(["read:statuses"], user: current_user)
[current_user: current_user, user: user, conn: conn]
end
test "/quotes fallback works" do
[current_user, user] = insert_pair(:user)
%{conn: conn} = oauth_access(["read:statuses"], user: current_user)
test "shows quotes of a post", %{conn: conn} do
user = insert(:user)
activity = insert(:note_activity)
activity = insert(:note_activity)
{:ok, quote_post} = CommonAPI.post(user, %{status: "quoat", quote_id: activity.id})
{:ok, quote_post} = CommonAPI.post(user, %{status: "quoat", quoted_status_id: activity.id})
response =
conn
|> get("/api/v1/pleroma/statuses/#{activity.id}/quotes")
|> json_response_and_validate_schema(:ok)
response =
conn
|> get("/api/v1/pleroma/statuses/#{activity.id}/quotes")
|> json_response_and_validate_schema(:ok)
[status] = response
[status] = response
assert length(response) == 1
assert status["id"] == quote_post.id
end
test "returns 404 error when a post can't be seen", %{conn: conn} do
activity = insert(:direct_note_activity)
response =
conn
|> get("/api/v1/pleroma/statuses/#{activity.id}/quotes")
assert json_response_and_validate_schema(response, 404) == %{"error" => "Record not found"}
end
test "returns 404 error when a post does not exist", %{conn: conn} do
response =
conn
|> get("/api/v1/pleroma/statuses/idontexist/quotes")
assert json_response_and_validate_schema(response, 404) == %{"error" => "Record not found"}
end
assert length(response) == 1
assert status["id"] == quote_post.id
end
end

View file

@ -4,7 +4,7 @@
defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
alias Pleroma.NullCache
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
@ -18,6 +18,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
import Mox
import Pleroma.Factory
setup do
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
:ok
end
setup do: clear_config([:rich_media, :enabled], true)
test "it displays a chat message" do

View file

@ -30,7 +30,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatViewTest do
AccountView.render("show.json", user: recipient, skip_visibility_check: true),
unread: 0,
last_message: nil,
updated_at: Utils.to_masto_date(chat.updated_at)
updated_at: Utils.to_masto_date(chat.updated_at),
pinned: false
}
{:ok, chat_message_creation} = CommonAPI.post_chat_message(user, recipient, "hello")

View file

@ -97,6 +97,7 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do
"users",
"tags",
"mailer",
"frontend_switcher",
"inbox",
"relay",
"internal",
@ -105,7 +106,6 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do
"manifest.json",
"auth",
"proxy",
"phoenix",
"test",
"user_exists",
"check_password"
@ -113,4 +113,36 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do
assert expected_routes == Pleroma.Web.Router.get_api_routes()
end
describe "preferred frontend cookie handling" do
test "returns preferred frontend file", %{conn: conn} do
name = "test-fe"
ref = "develop"
clear_config([:frontends, :pickable], ["#{name}/#{ref}"])
path = "#{@dir}/frontends/#{name}/#{ref}"
Pleroma.Backports.mkdir_p!(path)
File.write!("#{path}/index.html", "from frontend plug")
index =
conn
|> put_req_cookie("preferred_frontend", "#{name}/#{ref}")
|> get("/")
assert html_response(index, 200) == "from frontend plug"
end
test "only returns content from pickable frontends", %{conn: conn} do
clear_config([:instance, :static_dir], "instance/static")
clear_config([:frontends, :pickable], ["pleroma-fe/develop", "pl-fe/develop"])
config_file =
conn
|> put_req_cookie("preferred_frontend", "../../../config")
|> get("/config.exs")
refute response(config_file, 200) =~ "import Config"
end
end
end

View file

@ -4,7 +4,7 @@
defmodule Pleroma.Web.RichMedia.CardTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
@ -19,6 +19,8 @@ defmodule Pleroma.Web.RichMedia.CardTest do
setup do
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
ConfigMock
|> stub_with(Pleroma.Test.StaticConfig)

View file

@ -19,7 +19,12 @@ defmodule Pleroma.Web.StreamerTest do
@moduletag needs_streamer: true, capture_log: true
setup do: clear_config([:instance, :skip_thread_containment])
setup do
clear_config([:instance, :skip_thread_containment])
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
:ok
end
describe "get_topic/_ (unauthenticated)" do
test "allows no stream" do

View file

@ -3,12 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebFingerTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
alias Pleroma.Web.WebFinger
import Pleroma.Factory
import Tesla.Mock
setup do
Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
@ -93,7 +94,7 @@ defmodule Pleroma.Web.WebFingerTest do
{:ok, _data} = WebFinger.finger(user)
end
test "it work for AP-only user" do
test "it works for AP-only user" do
user = "kpherox@mstdn.jp"
{:ok, data} = WebFinger.finger(user)
@ -224,24 +225,84 @@ defmodule Pleroma.Web.WebFingerTest do
status: 200,
body: File.read!("test/fixtures/tesla_mock/gleasonator.com_host_meta")
}}
%{url: "https://whitehouse.gov/.well-known/webfinger?resource=acct:trump@whitehouse.gov"} ->
{:ok, %Tesla.Env{status: 404}}
end)
{:error, _data} = WebFinger.finger("alex@gleasonator.com")
end
end
test "prevents forgeries" do
Tesla.Mock.mock(fn
%{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} ->
fake_webfinger =
File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!()
test "prevents forgeries" do
Tesla.Mock.mock(fn
%{
url:
"https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"
} ->
fake_webfinger =
File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!()
Tesla.Mock.json(fake_webfinger)
Tesla.Mock.json(fake_webfinger)
%{url: "https://fba.ryona.agency/.well-known/host-meta"} ->
{:ok, %Tesla.Env{status: 404}}
end)
%{url: url}
when url in [
"https://poa.st/.well-known/webfinger?resource=acct:graf@poa.st",
"https://fba.ryona.agency/.well-known/host-meta"
] ->
{:ok, %Tesla.Env{status: 404}}
end)
assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency")
assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency")
end
test "prevents forgeries even when the spoofed subject exists on the target domain" do
Tesla.Mock.mock(fn
%{url: url}
when url in [
"https://attacker.example/.well-known/host-meta",
"https://victim.example/.well-known/host-meta"
] ->
{:ok, %Tesla.Env{status: 404}}
%{
url:
"https://attacker.example/.well-known/webfinger?resource=acct:alice@attacker.example"
} ->
Tesla.Mock.json(%{
"subject" => "acct:alice@victim.example",
"links" => [
%{
"rel" => "self",
"type" => "application/activity+json",
"href" => "https://attacker.example/users/alice"
}
]
})
%{url: "https://victim.example/.well-known/webfinger?resource=acct:alice@victim.example"} ->
Tesla.Mock.json(%{
"subject" => "acct:alice@victim.example",
"links" => [
%{
"rel" => "self",
"type" => "application/activity+json",
"href" => "https://victim.example/users/alice"
}
]
})
end)
assert {:error, _} = WebFinger.finger("alice@attacker.example")
end
test "works for correctly set up split-domain instances implementing host-meta redirect" do
{:ok, _data} = WebFinger.finger("a@pleroma.example")
{:ok, _data} = WebFinger.finger("a@sub.pleroma.example")
end
test "works for correctly set up split-domain instances without host-meta redirect" do
{:ok, _data} = WebFinger.finger("a@mastodon.example")
{:ok, _data} = WebFinger.finger("a@sub.mastodon.example")
end
end
end

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.PublisherWorkerTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.ReachabilityWorkerTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
use Oban.Testing, repo: Pleroma.Repo
import Mock

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.ReceiverWorkerTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
use Oban.Testing, repo: Pleroma.Repo
import Mock

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.RemoteFetcherWorkerTest do
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Workers.RemoteFetcherWorker

View file

@ -102,11 +102,19 @@ defmodule Pleroma.Factory do
user = attrs[:user] || insert(:user)
object_id =
if attrs[:object_local] == false do
# Must not match our Endpoint URL in the test env
"https://example.com/objects/#{Ecto.UUID.generate()}"
else
Pleroma.Web.ActivityPub.Utils.generate_object_id()
end
data = %{
"type" => "Note",
"content" => text,
"source" => text,
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"id" => object_id,
"actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
@ -297,27 +305,27 @@ defmodule Pleroma.Factory do
featured_collection_activity(attrs, "Add")
end
def remove_activity_factor(attrs \\ %{}) do
def remove_activity_factory(attrs \\ %{}) do
featured_collection_activity(attrs, "Remove")
end
defp featured_collection_activity(attrs, type) do
user = attrs[:user] || insert(:user)
note = attrs[:note] || insert(:note, user: user)
note_activity = attrs[:note_activity] || insert(:note_activity, user: user)
data_attrs =
attrs
|> Map.get(:data_attrs, %{})
|> Map.put(:type, type)
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
attrs = Map.drop(attrs, [:user, :note_activity, :data_attrs])
data =
%{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"target" => user.featured_address,
"object" => note.data["object"],
"actor" => note.data["actor"],
"object" => note_activity.data["object"],
"actor" => note_activity.data["actor"],
"type" => "Add",
"to" => [Pleroma.Constants.as_public()],
"cc" => [user.follower_address]
@ -361,14 +369,25 @@ defmodule Pleroma.Factory do
def note_activity_factory(attrs \\ %{}) do
user = attrs[:user] || insert(:user)
note = attrs[:note] || insert(:note, user: user)
object_local = if attrs[:object_local] == false, do: false, else: true
note = attrs[:note] || insert(:note, user: user, object_local: object_local)
activity_id =
if attrs[:local] == false do
# Same domain as in note Object factory, it doesn't make sense
# to create mismatched Create Activities with an ID coming from
# a different domain than the Object
"https://example.com/activities/#{Ecto.UUID.generate()}"
else
Pleroma.Web.ActivityPub.Utils.generate_activity_id()
end
data_attrs = attrs[:data_attrs] || %{}
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
attrs = Map.drop(attrs, [:user, :note, :data_attrs, :object_local])
data =
%{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"id" => activity_id,
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"],
@ -408,15 +427,17 @@ defmodule Pleroma.Factory do
def announce_activity_factory(attrs \\ %{}) do
note_activity = attrs[:note_activity] || insert(:note_activity)
object = Object.normalize(note_activity, fetch: false)
user = attrs[:user] || insert(:user)
data = %{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"type" => "Announce",
"actor" => note_activity.actor,
"object" => note_activity.data["id"],
"to" => [user.follower_address, note_activity.data["actor"]],
"actor" => user.ap_id,
"object" => object.data["id"],
"to" => [user.follower_address, object.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"],
"context" => note_activity.data["context"]
"context" => object.data["context"]
}
%Pleroma.Activity{
@ -426,6 +447,28 @@ defmodule Pleroma.Factory do
}
end
def emoji_react_activity_factory(attrs \\ %{}) do
note_activity = attrs[:note_activity] || insert(:note_activity)
object = Object.normalize(note_activity, fetch: false)
user = attrs[:user] || insert(:user)
data = %{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"actor" => user.ap_id,
"type" => "EmojiReact",
"object" => object.data["id"],
"to" => [user.follower_address, object.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"],
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => object.data["context"],
"content" => "😀"
}
%Pleroma.Activity{
data: data
}
end
def like_activity_factory(attrs \\ %{}) do
note_activity = attrs[:note_activity] || insert(:note_activity)
object = Object.normalize(note_activity, fetch: false)

View file

@ -1229,7 +1229,8 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 404, body: ""}}
end
def get("https://mstdn.jp/.well-known/webfinger?resource=acct:kpherox@mstdn.jp", _, _, _) do
def get("https://mstdn.jp/.well-known/webfinger?resource=acct:" <> acct, _, _, _)
when acct in ["kpherox@mstdn.jp", "kPherox@mstdn.jp"] do
{:ok,
%Tesla.Env{
status: 200,
@ -1526,14 +1527,6 @@ defmodule HttpRequestMock do
}}
end
def get("https://mastodon.example/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
status: 302,
headers: [{"location", "https://sub.mastodon.example/.well-known/host-meta"}]
}}
end
def get("https://sub.mastodon.example/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
@ -1546,11 +1539,15 @@ defmodule HttpRequestMock do
end
def get(
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example",
url,
_,
_,
_
) do
)
when url in [
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example",
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@sub.mastodon.example"
] do
{:ok,
%Tesla.Env{
status: 200,
@ -1564,6 +1561,22 @@ defmodule HttpRequestMock do
}}
end
def get(
"https://mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example",
_,
_,
_
) do
{:ok,
%Tesla.Env{
status: 302,
headers: [
{"location",
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example"}
]
}}
end
def get("https://sub.mastodon.example/users/a", _, _, _) do
{:ok,
%Tesla.Env{
@ -1609,11 +1622,15 @@ defmodule HttpRequestMock do
end
def get(
"https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@pleroma.example",
url,
_,
_,
_
) do
)
when url in [
"https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@pleroma.example",
"https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@sub.pleroma.example"
] do
{:ok,
%Tesla.Env{
status: 200,