Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into pleroma-instance-domain-blocks
This commit is contained in:
commit
656c4368d3
288 changed files with 6024 additions and 1531 deletions
34
test/fixtures/bovine-bogus-public-note.json
vendored
Normal file
34
test/fixtures/bovine-bogus-public-note.json
vendored
Normal 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'm a big believer in "Do as I say, not as I <strong>did</strong>".</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'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"
|
||||
}
|
||||
93
test/fixtures/quote_post/mastodon_quote_post.json
vendored
Normal file
93
test/fixtures/quote_post/mastodon_quote_post.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
41
test/fixtures/users_mock/href_as_array.json
vendored
Normal file
41
test/fixtures/users_mock/href_as_array.json
vendored
Normal 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"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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} =
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 _ ->
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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, %{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue