summaryrefslogtreecommitdiff
path: root/test/web
diff options
context:
space:
mode:
Diffstat (limited to 'test/web')
-rw-r--r--test/web/activity_pub/activity_pub_controller_test.exs169
-rw-r--r--test/web/activity_pub/activity_pub_test.exs95
-rw-r--r--test/web/activity_pub/mrf/anti_link_spam_policy_test.exs145
-rw-r--r--test/web/activity_pub/mrf/ensure_re_prepended_test.exs82
-rw-r--r--test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs45
-rw-r--r--test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs37
-rw-r--r--test/web/activity_pub/mrf/normalize_markup_test.exs42
-rw-r--r--test/web/activity_pub/mrf/reject_non_public_test.exs105
-rw-r--r--test/web/activity_pub/mrf/subchain_policy_test.exs32
-rw-r--r--test/web/activity_pub/mrf/tag_policy_test.exs123
-rw-r--r--test/web/activity_pub/mrf/user_allowlist_policy_test.exs36
-rw-r--r--test/web/activity_pub/transmogrifier/follow_handling_test.exs143
-rw-r--r--test/web/activity_pub/transmogrifier_test.exs342
-rw-r--r--test/web/activity_pub/utils_test.exs95
-rw-r--r--test/web/activity_pub/views/object_view_test.exs14
-rw-r--r--test/web/activity_pub/views/user_view_test.exs29
-rw-r--r--test/web/activity_pub/visibilty_test.exs121
-rw-r--r--test/web/admin_api/admin_api_controller_test.exs661
-rw-r--r--test/web/admin_api/config_test.exs465
-rw-r--r--test/web/admin_api/views/report_view_test.exs130
-rw-r--r--test/web/common_api/common_api_test.exs139
-rw-r--r--test/web/common_api/common_api_utils_test.exs152
-rw-r--r--test/web/federator_test.exs7
-rw-r--r--test/web/mastodon_api/account_view_test.exs50
-rw-r--r--test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs304
-rw-r--r--test/web/mastodon_api/mastodon_api_controller_test.exs1536
-rw-r--r--test/web/mastodon_api/search_controller_test.exs267
-rw-r--r--test/web/mastodon_api/status_view_test.exs239
-rw-r--r--test/web/media_proxy/media_proxy_controller_test.exs73
-rw-r--r--test/web/media_proxy/media_proxy_test.exs215
-rw-r--r--test/web/metadata/player_view_test.exs33
-rw-r--r--test/web/metadata/rel_me_test.exs4
-rw-r--r--test/web/metadata/twitter_card_test.exs123
-rw-r--r--test/web/node_info_test.exs43
-rw-r--r--test/web/oauth/oauth_controller_test.exs183
-rw-r--r--test/web/ostatus/activity_representer_test.exs19
-rw-r--r--test/web/ostatus/incoming_documents/delete_handling_test.exs13
-rw-r--r--test/web/ostatus/ostatus_controller_test.exs20
-rw-r--r--test/web/ostatus/ostatus_test.exs72
-rw-r--r--test/web/plugs/federating_plug_test.exs23
-rw-r--r--test/web/rel_me_test.exs4
-rw-r--r--test/web/rich_media/helpers_test.exs51
-rw-r--r--test/web/rich_media/parser_test.exs39
-rw-r--r--test/web/streamer_test.exs230
-rw-r--r--test/web/twitter_api/password_controller_test.exs60
-rw-r--r--test/web/twitter_api/twitter_api_controller_test.exs144
-rw-r--r--test/web/twitter_api/twitter_api_test.exs18
-rw-r--r--test/web/twitter_api/util_controller_test.exs13
-rw-r--r--test/web/twitter_api/views/activity_view_test.exs6
-rw-r--r--test/web/twitter_api/views/user_view_test.exs14
-rw-r--r--test/web/web_finger/web_finger_controller_test.exs6
-rw-r--r--test/web/web_finger/web_finger_test.exs11
-rw-r--r--test/web/websub/websub_controller_test.exs10
53 files changed, 6109 insertions, 923 deletions
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index 30adfda36..452172bb4 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -11,9 +11,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.UserView
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.CommonAPI
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ Pleroma.Config.put(config_path, true)
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
:ok
end
@@ -162,7 +171,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
describe "/object/:uuid/likes" do
test "it returns the like activities in a collection", %{conn: conn} do
like = insert(:like_activity)
- uuid = String.split(like.data["object"], "/") |> List.last()
+ like_object_ap_id = Object.normalize(like).data["id"]
+ uuid = String.split(like_object_ap_id, "/") |> List.last()
result =
conn
@@ -234,13 +244,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
describe "/users/:nickname/inbox" do
- test "it inserts an incoming activity into the database", %{conn: conn} do
- user = insert(:user)
-
+ setup do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
- |> Map.put("bcc", [user.ap_id])
+
+ [data: data]
+ end
+
+ test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
+ user = insert(:user)
+ data = Map.put(data, "bcc", [user.ap_id])
conn =
conn
@@ -253,16 +267,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Activity.get_by_ap_id(data["id"])
end
- test "it accepts messages from actors that are followed by the user", %{conn: conn} do
+ test "it accepts messages from actors that are followed by the user", %{
+ conn: conn,
+ data: data
+ } do
recipient = insert(:user)
actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
{:ok, recipient} = User.follow(recipient, actor)
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
-
object =
data["object"]
|> Map.put("attributedTo", actor.ap_id)
@@ -298,6 +311,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it returns a note activity in a collection", %{conn: conn} do
note_activity = insert(:direct_note_activity)
+ note_object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
conn =
@@ -306,16 +320,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/inbox")
- assert response(conn, 200) =~ note_activity.data["object"]["content"]
+ assert response(conn, 200) =~ note_object.data["content"]
end
- test "it clears `unreachable` federation status of the sender", %{conn: conn} do
+ test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
user = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
- |> Map.put("bcc", [user.ap_id])
+ data = Map.put(data, "bcc", [user.ap_id])
sender_host = URI.parse(data["actor"]).host
Instances.set_consistently_unreachable(sender_host)
@@ -330,6 +340,47 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert "ok" == json_response(conn, 200)
assert Instances.reachable?(sender_host)
end
+
+ test "it removes all follower collections but actor's", %{conn: conn} do
+ [actor, recipient] = insert_pair(:user)
+
+ data =
+ File.read!("test/fixtures/activitypub-client-post-activity.json")
+ |> Poison.decode!()
+
+ object = Map.put(data["object"], "attributedTo", actor.ap_id)
+
+ data =
+ data
+ |> Map.put("id", Utils.generate_object_id())
+ |> Map.put("actor", actor.ap_id)
+ |> Map.put("object", object)
+ |> Map.put("cc", [
+ recipient.follower_address,
+ actor.follower_address
+ ])
+ |> Map.put("to", [
+ recipient.ap_id,
+ recipient.follower_address,
+ "https://www.w3.org/ns/activitystreams#Public"
+ ])
+
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{recipient.nickname}/inbox", data)
+ |> json_response(200)
+
+ activity = Activity.get_by_ap_id(data["id"])
+
+ assert activity.id
+ assert actor.follower_address in activity.recipients
+ assert actor.follower_address in activity.data["cc"]
+
+ refute recipient.follower_address in activity.recipients
+ refute recipient.follower_address in activity.data["cc"]
+ refute recipient.follower_address in activity.data["to"]
+ end
end
describe "/users/:nickname/outbox" do
@@ -347,6 +398,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it returns a note activity in a collection", %{conn: conn} do
note_activity = insert(:note_activity)
+ note_object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
conn =
@@ -354,7 +406,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}/outbox")
- assert response(conn, 200) =~ note_activity.data["object"]["content"]
+ assert response(conn, 200) =~ note_object.data["content"]
end
test "it returns an announce activity in a collection", %{conn: conn} do
@@ -416,12 +468,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
note_activity = insert(:note_activity)
+ note_object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
data = %{
type: "Delete",
object: %{
- id: note_activity.data["object"]["id"]
+ id: note_object.data["id"]
}
}
@@ -434,19 +487,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
result = json_response(conn, 201)
assert Activity.get_by_ap_id(result["id"])
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
- assert object
+ assert object = Object.get_by_ap_id(note_object.data["id"])
assert object.data["type"] == "Tombstone"
end
test "it rejects delete activity of object from other actor", %{conn: conn} do
note_activity = insert(:note_activity)
+ note_object = Object.normalize(note_activity)
user = insert(:user)
data = %{
type: "Delete",
object: %{
- id: note_activity.data["object"]["id"]
+ id: note_object.data["id"]
}
}
@@ -461,12 +514,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it increases like count when receiving a like action", %{conn: conn} do
note_activity = insert(:note_activity)
+ note_object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
data = %{
type: "Like",
object: %{
- id: note_activity.data["object"]["id"]
+ id: note_object.data["id"]
}
}
@@ -479,8 +533,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
result = json_response(conn, 201)
assert Activity.get_by_ap_id(result["id"])
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
- assert object
+ assert object = Object.get_by_ap_id(note_object.data["id"])
assert object.data["like_count"] == 1
end
end
@@ -499,7 +552,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert result["first"]["orderedItems"] == [user.ap_id]
end
- test "it returns returns empty if the user has 'hide_followers' set", %{conn: conn} do
+ test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{info: %{hide_followers: true}})
User.follow(user, user_two)
@@ -509,8 +562,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> get("/users/#{user_two.nickname}/followers")
|> json_response(200)
- assert result["first"]["orderedItems"] == []
- assert result["totalItems"] == 0
+ assert is_binary(result["first"])
+ end
+
+ test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
+ %{conn: conn} do
+ user = insert(:user, %{info: %{hide_followers: true}})
+
+ result =
+ conn
+ |> get("/users/#{user.nickname}/followers?page=1")
+
+ assert result.status == 403
+ assert result.resp_body == ""
+ end
+
+ test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user",
+ %{conn: conn} do
+ user = insert(:user, %{info: %{hide_followers: true}})
+ other_user = insert(:user)
+ {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/users/#{user.nickname}/followers?page=1")
+ |> json_response(200)
+
+ assert result["totalItems"] == 1
+ assert result["orderedItems"] == [other_user.ap_id]
end
test "it works for more than 10 users", %{conn: conn} do
@@ -554,7 +634,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert result["first"]["orderedItems"] == [user_two.ap_id]
end
- test "it returns returns empty if the user has 'hide_follows' set", %{conn: conn} do
+ test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
user = insert(:user, %{info: %{hide_follows: true}})
user_two = insert(:user)
User.follow(user, user_two)
@@ -564,8 +644,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> get("/users/#{user.nickname}/following")
|> json_response(200)
- assert result["first"]["orderedItems"] == []
- assert result["totalItems"] == 0
+ assert is_binary(result["first"])
+ end
+
+ test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
+ %{conn: conn} do
+ user = insert(:user, %{info: %{hide_follows: true}})
+
+ result =
+ conn
+ |> get("/users/#{user.nickname}/following?page=1")
+
+ assert result.status == 403
+ assert result.resp_body == ""
+ end
+
+ test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user",
+ %{conn: conn} do
+ user = insert(:user, %{info: %{hide_follows: true}})
+ other_user = insert(:user)
+ {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/users/#{user.nickname}/following?page=1")
+ |> json_response(200)
+
+ assert result["totalItems"] == 1
+ assert result["orderedItems"] == [other_user.ap_id]
end
test "it works for more than 10 users", %{conn: conn} do
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index f743f380b..00adbc0f9 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -254,10 +254,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
}
{:ok, %Activity{} = activity} = ActivityPub.insert(data)
- object = Object.normalize(activity.data["object"])
-
+ assert object = Object.normalize(activity)
assert is_binary(object.data["id"])
- assert %Object{} = Object.get_by_ap_id(activity.data["object"])
end
end
@@ -659,7 +657,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "like an object" do
test "adds a like activity to the db" do
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ assert object = Object.normalize(note_activity)
+
user = insert(:user)
user_two = insert(:user)
@@ -678,19 +677,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert like_activity == same_like_activity
assert object.data["likes"] == [user.ap_id]
+ assert object.data["like_count"] == 1
[note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
assert note_activity.data["object"]["like_count"] == 1
{:ok, _like_activity, object} = ActivityPub.like(user_two, object)
assert object.data["like_count"] == 2
+
+ [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
+ assert note_activity.data["object"]["like_count"] == 2
end
end
describe "unliking" do
test "unliking a previously liked object" do
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
user = insert(:user)
# Unliking something that hasn't been liked does nothing
@@ -710,7 +713,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "announcing an object" do
test "adds an announce activity to the db" do
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
user = insert(:user)
{:ok, announce_activity, object} = ActivityPub.announce(user, object)
@@ -731,7 +734,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "unannouncing an object" do
test "unannouncing a previously announced object" do
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
user = insert(:user)
# Unannouncing an object that is not announced does nothing
@@ -810,10 +813,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity.data["type"] == "Undo"
assert activity.data["actor"] == follower.ap_id
- assert is_map(activity.data["object"])
- assert activity.data["object"]["type"] == "Follow"
- assert activity.data["object"]["object"] == followed.ap_id
- assert activity.data["object"]["id"] == follow_activity.data["id"]
+ embedded_object = activity.data["object"]
+ assert is_map(embedded_object)
+ assert embedded_object["type"] == "Follow"
+ assert embedded_object["object"] == followed.ap_id
+ assert embedded_object["id"] == follow_activity.data["id"]
end
end
@@ -839,22 +843,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity.data["type"] == "Undo"
assert activity.data["actor"] == blocker.ap_id
- assert is_map(activity.data["object"])
- assert activity.data["object"]["type"] == "Block"
- assert activity.data["object"]["object"] == blocked.ap_id
- assert activity.data["object"]["id"] == block_activity.data["id"]
+ embedded_object = activity.data["object"]
+ assert is_map(embedded_object)
+ assert embedded_object["type"] == "Block"
+ assert embedded_object["object"] == blocked.ap_id
+ assert embedded_object["id"] == block_activity.data["id"]
end
end
describe "deletion" do
test "it creates a delete activity and deletes the original object" do
note = insert(:note_activity)
- object = Object.get_by_ap_id(note.data["object"]["id"])
+ object = Object.normalize(note)
{:ok, delete} = ActivityPub.delete(object)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == note.data["actor"]
- assert delete.data["object"] == note.data["object"]["id"]
+ assert delete.data["object"] == object.data["id"]
assert Activity.get_by_id(delete.id) != nil
@@ -900,13 +905,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
user = insert(:user)
note = insert(:note_activity)
+ object = Object.normalize(note)
{:ok, object} =
- Object.get_by_ap_id(note.data["object"]["id"])
+ object
|> Object.change(%{
data: %{
- "actor" => note.data["object"]["actor"],
- "id" => note.data["object"]["id"],
+ "actor" => object.data["actor"],
+ "id" => object.data["id"],
"to" => [user.ap_id],
"type" => "Note"
}
@@ -1018,8 +1024,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert update.data["actor"] == user.ap_id
assert update.data["to"] == [user.follower_address]
- assert update.data["object"]["id"] == user_data["id"]
- assert update.data["object"]["type"] == user_data["type"]
+ assert embedded_object = update.data["object"]
+ assert embedded_object["id"] == user_data["id"]
+ assert embedded_object["type"] == user_data["type"]
end
end
@@ -1183,7 +1190,51 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
+ test "fetch_activities/2 returns activities addressed to a list " do
+ user = insert(:user)
+ member = insert(:user)
+ {:ok, list} = Pleroma.List.create("foo", user)
+ {:ok, list} = Pleroma.List.follow(list, member)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+
+ activity = Repo.preload(activity, :bookmark)
+ activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
+
+ assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity]
+ end
+
def data_uri do
File.read!("test/fixtures/avatar_data_uri")
end
+
+ describe "fetch_activities_bounded" do
+ test "fetches private posts for followed users" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "thought I looked cute might delete later :3",
+ "visibility" => "private"
+ })
+
+ [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
+ assert result.id == activity.id
+ end
+
+ test "fetches only public posts for other users" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
+
+ {:ok, _private_activity} =
+ CommonAPI.post(user, %{
+ "status" => "why is tenshi eating a corndog so cute?",
+ "visibility" => "private"
+ })
+
+ [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
+ assert result.id == activity.id
+ end
+ end
end
diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
new file mode 100644
index 000000000..03dc299ec
--- /dev/null
+++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
@@ -0,0 +1,145 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import ExUnit.CaptureLog
+
+ alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy
+
+ @linkless_message %{
+ "type" => "Create",
+ "object" => %{
+ "content" => "hi world!"
+ }
+ }
+
+ @linkful_message %{
+ "type" => "Create",
+ "object" => %{
+ "content" => "<a href='https://example.com'>hi world!</a>"
+ }
+ }
+
+ @response_message %{
+ "type" => "Create",
+ "object" => %{
+ "name" => "yes",
+ "type" => "Answer"
+ }
+ }
+
+ describe "with new user" do
+ test "it allows posts without links" do
+ user = insert(:user)
+
+ assert user.info.note_count == 0
+
+ message =
+ @linkless_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+
+ test "it disallows posts with links" do
+ user = insert(:user)
+
+ assert user.info.note_count == 0
+
+ message =
+ @linkful_message
+ |> Map.put("actor", user.ap_id)
+
+ {:reject, _} = AntiLinkSpamPolicy.filter(message)
+ end
+ end
+
+ describe "with old user" do
+ test "it allows posts without links" do
+ user = insert(:user, info: %{note_count: 1})
+
+ assert user.info.note_count == 1
+
+ message =
+ @linkless_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+
+ test "it allows posts with links" do
+ user = insert(:user, info: %{note_count: 1})
+
+ assert user.info.note_count == 1
+
+ message =
+ @linkful_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+ end
+
+ describe "with followed new user" do
+ test "it allows posts without links" do
+ user = insert(:user, info: %{follower_count: 1})
+
+ assert user.info.follower_count == 1
+
+ message =
+ @linkless_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+
+ test "it allows posts with links" do
+ user = insert(:user, info: %{follower_count: 1})
+
+ assert user.info.follower_count == 1
+
+ message =
+ @linkful_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+ end
+
+ describe "with unknown actors" do
+ test "it rejects posts without links" do
+ message =
+ @linkless_message
+ |> Map.put("actor", "http://invalid.actor")
+
+ assert capture_log(fn ->
+ {:reject, _} = AntiLinkSpamPolicy.filter(message)
+ end) =~ "[error] Could not decode user at fetch http://invalid.actor"
+ end
+
+ test "it rejects posts with links" do
+ message =
+ @linkful_message
+ |> Map.put("actor", "http://invalid.actor")
+
+ assert capture_log(fn ->
+ {:reject, _} = AntiLinkSpamPolicy.filter(message)
+ end) =~ "[error] Could not decode user at fetch http://invalid.actor"
+ end
+ end
+
+ describe "with contentless-objects" do
+ test "it does not reject them or error out" do
+ user = insert(:user, info: %{note_count: 1})
+
+ message =
+ @response_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
new file mode 100644
index 000000000..dbc8b9e80
--- /dev/null
+++ b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrependedTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.MRF.EnsureRePrepended
+
+ describe "rewrites summary" do
+ test "it adds `re:` to summary object when child summary and parent summary equal" do
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "summary" => "object-summary",
+ "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "object-summary"}}}
+ }
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res["object"]["summary"] == "re: object-summary"
+ end
+
+ test "it adds `re:` to summary object when child summary containts re-subject of parent summary " do
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "summary" => "object-summary",
+ "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "re: object-summary"}}}
+ }
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res["object"]["summary"] == "re: object-summary"
+ end
+ end
+
+ describe "skip filter" do
+ test "it skip if type isn't 'Create'" do
+ message = %{
+ "type" => "Annotation",
+ "object" => %{"summary" => "object-summary"}
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res == message
+ end
+
+ test "it skip if summary is empty" do
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}}
+ }
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res == message
+ end
+
+ test "it skip if inReplyTo is empty" do
+ message = %{"type" => "Create", "object" => %{"summary" => "summary"}}
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res == message
+ end
+
+ test "it skip if parent and child summary isn't equal" do
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "summary" => "object-summary",
+ "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}}
+ }
+ }
+
+ assert {:ok, res} = EnsureRePrepended.filter(message)
+ assert res == message
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs
new file mode 100644
index 000000000..372e789be
--- /dev/null
+++ b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs
@@ -0,0 +1,45 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.HTTP
+ alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy
+
+ import Mock
+
+ @message %{
+ "type" => "Create",
+ "object" => %{
+ "type" => "Note",
+ "content" => "content",
+ "attachment" => [
+ %{"url" => [%{"href" => "http://example.com/image.jpg"}]}
+ ]
+ }
+ }
+
+ test "it prefetches media proxy URIs" do
+ with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
+ MediaProxyWarmingPolicy.filter(@message)
+ assert called(HTTP.get(:_, :_, :_))
+ end
+ end
+
+ test "it does nothing when no attachments are present" do
+ object =
+ @message["object"]
+ |> Map.delete("attachment")
+
+ message =
+ @message
+ |> Map.put("object", object)
+
+ with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
+ MediaProxyWarmingPolicy.filter(message)
+ refute called(HTTP.get(:_, :_, :_))
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs b/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs
new file mode 100644
index 000000000..63ed71129
--- /dev/null
+++ b/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicyTest do
+ use Pleroma.DataCase
+ alias Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy
+
+ test "it clears content object" do
+ message = %{
+ "type" => "Create",
+ "object" => %{"content" => ".", "attachment" => "image"}
+ }
+
+ assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
+ assert res["object"]["content"] == ""
+
+ message = put_in(message, ["object", "content"], "<p>.</p>")
+ assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
+ assert res["object"]["content"] == ""
+ end
+
+ @messages [
+ %{
+ "type" => "Create",
+ "object" => %{"content" => "test", "attachment" => "image"}
+ },
+ %{"type" => "Create", "object" => %{"content" => "."}},
+ %{"type" => "Create", "object" => %{"content" => "<p>.</p>"}}
+ ]
+ test "it skips filter" do
+ Enum.each(@messages, fn message ->
+ assert {:ok, res} = NoPlaceholderTextPolicy.filter(message)
+ assert res == message
+ end)
+ end
+end
diff --git a/test/web/activity_pub/mrf/normalize_markup_test.exs b/test/web/activity_pub/mrf/normalize_markup_test.exs
new file mode 100644
index 000000000..3916a1f35
--- /dev/null
+++ b/test/web/activity_pub/mrf/normalize_markup_test.exs
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do
+ use Pleroma.DataCase
+ alias Pleroma.Web.ActivityPub.MRF.NormalizeMarkup
+
+ @html_sample """
+ <b>this is in bold</b>
+ <p>this is a paragraph</p>
+ this is a linebreak<br />
+ this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
+ this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a>
+ this is an image: <img src="http://example.com/image.jpg"><br />
+ <script>alert('hacked')</script>
+ """
+
+ test "it filter html tags" do
+ expected = """
+ <b>this is in bold</b>
+ <p>this is a paragraph</p>
+ this is a linebreak<br />
+ this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
+ this is a link with not allowed "rel" attribute: <a href="http://example.com/">example.com</a>
+ this is an image: <img src="http://example.com/image.jpg" /><br />
+ alert('hacked')
+ """
+
+ message = %{"type" => "Create", "object" => %{"content" => @html_sample}}
+
+ assert {:ok, res} = NormalizeMarkup.filter(message)
+ assert res["object"]["content"] == expected
+ end
+
+ test "it skips filter if type isn't `Create`" do
+ message = %{"type" => "Note", "object" => %{}}
+
+ assert {:ok, res} = NormalizeMarkup.filter(message)
+ assert res == message
+ end
+end
diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/web/activity_pub/mrf/reject_non_public_test.exs
new file mode 100644
index 000000000..fdf6b245e
--- /dev/null
+++ b/test/web/activity_pub/mrf/reject_non_public_test.exs
@@ -0,0 +1,105 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.Web.ActivityPub.MRF.RejectNonPublic
+
+ setup do
+ policy = Pleroma.Config.get([:mrf_rejectnonpublic])
+ on_exit(fn -> Pleroma.Config.put([:mrf_rejectnonpublic], policy) end)
+
+ :ok
+ end
+
+ describe "public message" do
+ test "it's allowed when address is public" do
+ actor = insert(:user, follower_address: "test-address")
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ assert {:ok, message} = RejectNonPublic.filter(message)
+ end
+
+ test "it's allowed when cc address contain public address" do
+ actor = insert(:user, follower_address: "test-address")
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ assert {:ok, message} = RejectNonPublic.filter(message)
+ end
+ end
+
+ describe "followers message" do
+ test "it's allowed when addrer of message in the follower addresses of user and it enabled in config" do
+ actor = insert(:user, follower_address: "test-address")
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["test-address"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true)
+ assert {:ok, message} = RejectNonPublic.filter(message)
+ end
+
+ test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do
+ actor = insert(:user, follower_address: "test-address")
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["test-address"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false)
+ assert {:reject, nil} = RejectNonPublic.filter(message)
+ end
+ end
+
+ describe "direct message" do
+ test "it's allows when direct messages are allow" do
+ actor = insert(:user)
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true)
+ assert {:ok, message} = RejectNonPublic.filter(message)
+ end
+
+ test "it's reject when direct messages aren't allow" do
+ actor = insert(:user)
+
+ message = %{
+ "actor" => actor.ap_id,
+ "to" => ["https://www.w3.org/ns/activitystreams#Publid~~~"],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Publid"],
+ "type" => "Create"
+ }
+
+ Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false)
+ assert {:reject, nil} = RejectNonPublic.filter(message)
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/web/activity_pub/mrf/subchain_policy_test.exs
new file mode 100644
index 000000000..f7cbcad48
--- /dev/null
+++ b/test/web/activity_pub/mrf/subchain_policy_test.exs
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.ActivityPub.MRF.DropPolicy
+ alias Pleroma.Web.ActivityPub.MRF.SubchainPolicy
+
+ @message %{
+ "actor" => "https://banned.com",
+ "type" => "Create",
+ "object" => %{"content" => "hi"}
+ }
+
+ test "it matches and processes subchains when the actor matches a configured target" do
+ Pleroma.Config.put([:mrf_subchain, :match_actor], %{
+ ~r/^https:\/\/banned.com/s => [DropPolicy]
+ })
+
+ {:reject, _} = SubchainPolicy.filter(@message)
+ end
+
+ test "it doesn't match and process subchains when the actor doesn't match a configured target" do
+ Pleroma.Config.put([:mrf_subchain, :match_actor], %{
+ ~r/^https:\/\/borked.com/s => [DropPolicy]
+ })
+
+ {:ok, _message} = SubchainPolicy.filter(@message)
+ end
+end
diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/web/activity_pub/mrf/tag_policy_test.exs
new file mode 100644
index 000000000..4aa35311e
--- /dev/null
+++ b/test/web/activity_pub/mrf/tag_policy_test.exs
@@ -0,0 +1,123 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.Web.ActivityPub.MRF.TagPolicy
+ @public "https://www.w3.org/ns/activitystreams#Public"
+
+ describe "mrf_tag:disable-any-subscription" do
+ test "rejects message" do
+ actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"])
+ message = %{"object" => actor.ap_id, "type" => "Follow"}
+ assert {:reject, nil} = TagPolicy.filter(message)
+ end
+ end
+
+ describe "mrf_tag:disable-remote-subscription" do
+ test "rejects non-local follow requests" do
+ actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
+ follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false)
+ message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
+ assert {:reject, nil} = TagPolicy.filter(message)
+ end
+
+ test "allows non-local follow requests" do
+ actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
+ follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true)
+ message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
+ assert {:ok, message} = TagPolicy.filter(message)
+ end
+ end
+
+ describe "mrf_tag:sandbox" do
+ test "removes from public timelines" do
+ actor = insert(:user, tags: ["mrf_tag:sandbox"])
+
+ message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{},
+ "to" => [@public, "f"],
+ "cc" => [@public, "d"]
+ }
+
+ except_message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d"]},
+ "to" => ["f", actor.follower_address],
+ "cc" => ["d"]
+ }
+
+ assert TagPolicy.filter(message) == {:ok, except_message}
+ end
+ end
+
+ describe "mrf_tag:force-unlisted" do
+ test "removes from the federated timeline" do
+ actor = insert(:user, tags: ["mrf_tag:force-unlisted"])
+
+ message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{},
+ "to" => [@public, "f"],
+ "cc" => [actor.follower_address, "d"]
+ }
+
+ except_message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]},
+ "to" => ["f", actor.follower_address],
+ "cc" => ["d", @public]
+ }
+
+ assert TagPolicy.filter(message) == {:ok, except_message}
+ end
+ end
+
+ describe "mrf_tag:media-strip" do
+ test "removes attachments" do
+ actor = insert(:user, tags: ["mrf_tag:media-strip"])
+
+ message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"attachment" => ["file1"]}
+ }
+
+ except_message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{}
+ }
+
+ assert TagPolicy.filter(message) == {:ok, except_message}
+ end
+ end
+
+ describe "mrf_tag:media-force-nsfw" do
+ test "Mark as sensitive on presence of attachments" do
+ actor = insert(:user, tags: ["mrf_tag:media-force-nsfw"])
+
+ message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"tag" => ["test"], "attachment" => ["file1"]}
+ }
+
+ except_message = %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"tag" => ["test", "nsfw"], "attachment" => ["file1"], "sensitive" => true}
+ }
+
+ assert TagPolicy.filter(message) == {:ok, except_message}
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
new file mode 100644
index 000000000..6519e2398
--- /dev/null
+++ b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
@@ -0,0 +1,36 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy
+
+ setup do
+ policy = Pleroma.Config.get([:mrf_user_allowlist]) || []
+ on_exit(fn -> Pleroma.Config.put([:mrf_user_allowlist], policy) end)
+
+ :ok
+ end
+
+ test "pass filter if allow list is empty" do
+ actor = insert(:user)
+ message = %{"actor" => actor.ap_id}
+ assert UserAllowListPolicy.filter(message) == {:ok, message}
+ end
+
+ test "pass filter if allow list isn't empty and user in allow list" do
+ actor = insert(:user)
+ Pleroma.Config.put([:mrf_user_allowlist, :localhost], [actor.ap_id, "test-ap-id"])
+ message = %{"actor" => actor.ap_id}
+ assert UserAllowListPolicy.filter(message) == {:ok, message}
+ end
+
+ test "rejected if allow list isn't empty and user not in allow list" do
+ actor = insert(:user)
+ Pleroma.Config.put([:mrf_user_allowlist, :localhost], ["test-ap-id"])
+ message = %{"actor" => actor.ap_id}
+ assert UserAllowListPolicy.filter(message) == {:reject, nil}
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs
new file mode 100644
index 000000000..857d65564
--- /dev/null
+++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs
@@ -0,0 +1,143 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
+ use Pleroma.DataCase
+ alias Pleroma.Activity
+ alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
+
+ import Pleroma.Factory
+ import Ecto.Query
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ describe "handle_incoming" do
+ test "it works for incoming follow requests" do
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+ assert data["type"] == "Follow"
+ assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
+
+ activity = Repo.get(Activity, activity.id)
+ assert activity.data["state"] == "accept"
+ assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
+ end
+
+ test "with locked accounts, it does not create a follow or an accept" do
+ user = insert(:user, info: %{locked: true})
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["state"] == "pending"
+
+ refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
+
+ accepts =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = ?", a.data, "Accept")
+ )
+ |> Repo.all()
+
+ assert length(accepts) == 0
+ end
+
+ test "it works for follow requests when you are already followed, creating a new accept activity" do
+ # This is important because the remote might have the wrong idea about the
+ # current follow status. This can lead to instance A thinking that x@A is
+ # followed by y@B, but B thinks they are not. In this case, the follow can
+ # never go through again because it will never get an Accept.
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
+
+ accepts =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = ?", a.data, "Accept")
+ )
+ |> Repo.all()
+
+ assert length(accepts) == 1
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("id", String.replace(data["id"], "2", "3"))
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
+
+ accepts =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = ?", a.data, "Accept")
+ )
+ |> Repo.all()
+
+ assert length(accepts) == 2
+ end
+
+ test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
+ Pleroma.Config.put([:user, :deny_follow_blocked], true)
+
+ user = insert(:user)
+ {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
+
+ {:ok, user} = User.block(user, target)
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
+
+ %Activity{} = activity = Activity.get_by_ap_id(id)
+
+ assert activity.data["state"] == "reject"
+ end
+
+ test "it works for incoming follow requests from hubzilla" do
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/hubzilla-follow-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+ |> Utils.normalize_params()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
+ assert data["type"] == "Follow"
+ assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
+ assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
+ end
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index c24b50f8c..a1f5f6e36 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -11,12 +11,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
- alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OStatus
alias Pleroma.Web.Websub.WebsubClientSubscription
+ import Mock
import Pleroma.Factory
- alias Pleroma.Web.CommonAPI
+ import ExUnit.CaptureLog
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -30,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
- |> Map.put("object", activity.data["object"])
+ |> Map.put("object", Object.normalize(activity).data)
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
@@ -46,12 +47,9 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
data["object"]
|> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
- data =
- data
- |> Map.put("object", object)
-
+ data = Map.put(data, "object", object)
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
- returned_object = Object.normalize(returned_activity.data["object"])
+ returned_object = Object.normalize(returned_activity, false)
assert activity =
Activity.get_create_by_object_ap_id(
@@ -61,6 +59,50 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
end
+ test "it does not fetch replied-to activities beyond max_replies_depth" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
+
+ data = Map.put(data, "object", object)
+
+ with_mock Pleroma.Web.Federator,
+ allowed_incoming_reply_depth?: fn _ -> false end do
+ {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+
+ returned_object = Object.normalize(returned_activity, false)
+
+ refute Activity.get_create_by_object_ap_id(
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ )
+
+ assert returned_object.data["inReplyToAtomUri"] ==
+ "https://shitposter.club/notice/2827873"
+ end
+ end
+
+ test "it does not crash if the object in inReplyTo can't be fetched" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://404.site/whatever")
+
+ data =
+ data
+ |> Map.put("object", object)
+
+ assert capture_log(fn ->
+ {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
+ end) =~ "[error] Couldn't fetch \"\"https://404.site/whatever\"\", error: nil"
+ end
+
test "it works for incoming notices" do
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
@@ -81,25 +123,27 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert data["actor"] == "http://mastodon.example.org/users/admin"
- object = Object.normalize(data["object"]).data
- assert object["id"] == "http://mastodon.example.org/users/admin/statuses/99512778738411822"
+ object_data = Object.normalize(data["object"]).data
+
+ assert object_data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99512778738411822"
- assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+ assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
- assert object["cc"] == [
+ assert object_data["cc"] == [
"http://mastodon.example.org/users/admin/followers",
"http://localtesting.pleroma.lol/users/lain"
]
- assert object["actor"] == "http://mastodon.example.org/users/admin"
- assert object["attributedTo"] == "http://mastodon.example.org/users/admin"
+ assert object_data["actor"] == "http://mastodon.example.org/users/admin"
+ assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
- assert object["context"] ==
+ assert object_data["context"] ==
"tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
- assert object["sensitive"] == true
+ assert object_data["sensitive"] == true
- user = User.get_cached_by_ap_id(object["actor"])
+ user = User.get_cached_by_ap_id(object_data["actor"])
assert user.info.note_count == 1
end
@@ -113,6 +157,55 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert Enum.at(object.data["tag"], 2) == "moo"
end
+ test "it works for incoming questions" do
+ data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity)
+
+ assert Enum.all?(object.data["oneOf"], fn choice ->
+ choice["name"] in [
+ "Dunno",
+ "Everyone knows that!",
+ "25 char limit is dumb",
+ "I can't even fit a funny"
+ ]
+ end)
+ end
+
+ test "it rewrites Note votes to Answers and increments vote counters on question activities" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "suya...",
+ "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
+ })
+
+ object = Object.normalize(activity)
+
+ data =
+ File.read!("test/fixtures/mastodon-vote.json")
+ |> Poison.decode!()
+ |> Kernel.put_in(["to"], user.ap_id)
+ |> Kernel.put_in(["object", "inReplyTo"], object.data["id"])
+ |> Kernel.put_in(["object", "to"], user.ap_id)
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+ answer_object = Object.normalize(activity)
+ assert answer_object.data["type"] == "Answer"
+ object = Object.get_by_ap_id(object.data["id"])
+
+ assert Enum.any?(
+ object.data["oneOf"],
+ fn
+ %{"name" => "suya..", "replies" => %{"totalItems" => 1}} -> true
+ _ -> false
+ end
+ )
+ end
+
test "it works for incoming notices with contentMap" do
data =
File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
@@ -199,59 +292,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert object_data["cc"] == to
end
- test "it works for incoming follow requests" do
- user = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
- |> Map.put("object", user.ap_id)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["actor"] == "http://mastodon.example.org/users/admin"
- assert data["type"] == "Follow"
- assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
- assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
- end
-
- test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
- Pleroma.Config.put([:user, :deny_follow_blocked], true)
-
- user = insert(:user)
- {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
-
- {:ok, user} = User.block(user, target)
-
- data =
- File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
- |> Map.put("object", user.ap_id)
-
- {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
-
- %Activity{} = activity = Activity.get_by_ap_id(id)
-
- assert activity.data["state"] == "reject"
- end
-
- test "it works for incoming follow requests from hubzilla" do
- user = insert(:user)
-
- data =
- File.read!("test/fixtures/hubzilla-follow-activity.json")
- |> Poison.decode!()
- |> Map.put("object", user.ap_id)
- |> Utils.normalize_params()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
- assert data["type"] == "Follow"
- assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
- assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
- end
-
test "it works for incoming likes" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
@@ -376,6 +416,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
|> Map.put("attributedTo", user.ap_id)
|> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
|> Map.put("cc", [])
+ |> Map.put("id", user.ap_id <> "/activities/12345678")
data = Map.put(data, "object", object)
@@ -399,6 +440,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
|> Map.put("attributedTo", user.ap_id)
|> Map.put("to", nil)
|> Map.put("cc", nil)
+ |> Map.put("id", user.ap_id <> "/activities/12345678")
data = Map.put(data, "object", object)
@@ -505,11 +547,38 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
data
|> Map.put("object", object)
- :error = Transmogrifier.handle_incoming(data)
+ assert capture_log(fn ->
+ :error = Transmogrifier.handle_incoming(data)
+ end) =~
+ "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, {:error, :nxdomain}}"
assert Activity.get_by_id(activity.id)
end
+ test "it works for incoming user deletes" do
+ %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
+
+ data =
+ File.read!("test/fixtures/mastodon-delete-user.json")
+ |> Poison.decode!()
+
+ {:ok, _} = Transmogrifier.handle_incoming(data)
+
+ refute User.get_cached_by_ap_id(ap_id)
+ end
+
+ test "it fails for incoming user deletes with spoofed origin" do
+ %{ap_id: ap_id} = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-delete-user.json")
+ |> Poison.decode!()
+ |> Map.put("actor", ap_id)
+
+ assert :error == Transmogrifier.handle_incoming(data)
+ assert User.get_cached_by_ap_id(ap_id)
+ end
+
test "it works for incoming unannounces with an existing notice" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
@@ -531,10 +600,11 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Undo"
- assert data["object"]["type"] == "Announce"
- assert data["object"]["object"] == activity.data["object"]
+ assert object_data = data["object"]
+ assert object_data["type"] == "Announce"
+ assert object_data["object"] == activity.data["object"]
- assert data["object"]["id"] ==
+ assert object_data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
end
@@ -844,7 +914,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -1028,6 +1098,18 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert modified["directMessage"] == true
end
+
+ test "it strips BCC field" do
+ user = insert(:user)
+ {:ok, list} = Pleroma.List.create("foo", user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert is_nil(modified["bcc"])
+ end
end
describe "user upgrade" do
@@ -1053,6 +1135,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert user.info.ap_enabled
assert user.info.note_count == 1
assert user.follower_address == "https://niu.moe/users/rye/followers"
+ assert user.following_address == "https://niu.moe/users/rye/following"
user = User.get_cached_by_id(user.id)
assert user.info.note_count == 1
@@ -1209,4 +1292,113 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
end
end
+
+ test "Rewrites Answers to Notes" do
+ user = insert(:user)
+
+ {:ok, poll_activity} =
+ CommonAPI.post(user, %{
+ "status" => "suya...",
+ "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
+ })
+
+ poll_object = Object.normalize(poll_activity)
+ # TODO: Replace with CommonAPI vote creation when implemented
+ data =
+ File.read!("test/fixtures/mastodon-vote.json")
+ |> Poison.decode!()
+ |> Kernel.put_in(["to"], user.ap_id)
+ |> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
+ |> Kernel.put_in(["object", "to"], user.ap_id)
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+ {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert data["object"]["type"] == "Note"
+ end
+
+ describe "fix_explicit_addressing" do
+ setup do
+ user = insert(:user)
+ [user: user]
+ end
+
+ test "moves non-explicitly mentioned actors to cc", %{user: user} do
+ explicitly_mentioned_actors = [
+ "https://pleroma.gold/users/user1",
+ "https://pleroma.gold/user2"
+ ]
+
+ object = %{
+ "actor" => user.ap_id,
+ "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
+ "cc" => [],
+ "tag" =>
+ Enum.map(explicitly_mentioned_actors, fn href ->
+ %{"type" => "Mention", "href" => href}
+ end)
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object)
+ assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
+ refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
+ assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
+ end
+
+ test "does not move actor's follower collection to cc", %{user: user} do
+ object = %{
+ "actor" => user.ap_id,
+ "to" => [user.follower_address],
+ "cc" => []
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object)
+ assert user.follower_address in fixed_object["to"]
+ refute user.follower_address in fixed_object["cc"]
+ end
+
+ test "removes recipient's follower collection from cc", %{user: user} do
+ recipient = insert(:user)
+
+ object = %{
+ "actor" => user.ap_id,
+ "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [user.follower_address, recipient.follower_address]
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object)
+
+ assert user.follower_address in fixed_object["cc"]
+ refute recipient.follower_address in fixed_object["cc"]
+ refute recipient.follower_address in fixed_object["to"]
+ end
+ end
+
+ test "update_following_followers_counters/1" do
+ user1 =
+ insert(:user,
+ local: false,
+ follower_address: "http://localhost:4001/users/masto_closed/followers",
+ following_address: "http://localhost:4001/users/masto_closed/following"
+ )
+
+ user2 =
+ insert(:user,
+ local: false,
+ follower_address: "http://localhost:4001/users/fuser2/followers",
+ following_address: "http://localhost:4001/users/fuser2/following"
+ )
+
+ Transmogrifier.update_following_followers_counters(user1)
+ Transmogrifier.update_following_followers_counters(user2)
+
+ %{follower_count: followers, following_count: following} = User.get_cached_user_info(user1)
+ assert followers == 437
+ assert following == 152
+
+ %{follower_count: followers, following_count: following} = User.get_cached_user_info(user2)
+
+ assert followers == 527
+ assert following == 267
+ end
end
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index c57fae437..ca5f057a7 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -1,6 +1,12 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase
alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
@@ -204,4 +210,93 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
]
}
end
+
+ describe "get_existing_votes" do
+ test "fetches existing votes" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "How do I pronounce LaTeX?",
+ "poll" => %{
+ "options" => ["laytekh", "lahtekh", "latex"],
+ "expires_in" => 20,
+ "multiple" => true
+ }
+ })
+
+ object = Object.normalize(activity)
+ {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
+ assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
+ end
+
+ test "fetches only Create activities" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Are we living in a society?",
+ "poll" => %{
+ "options" => ["yes", "no"],
+ "expires_in" => 20
+ }
+ })
+
+ object = Object.normalize(activity)
+ {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
+ vote_object = Object.normalize(vote)
+ {:ok, _activity, _object} = ActivityPub.like(user, vote_object)
+ [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
+ assert fetched_vote.id == vote.id
+ end
+ end
+
+ describe "update_follow_state_for_all/2" do
+ test "updates the state of all Follow activities with the same actor and object" do
+ user = insert(:user, info: %{locked: true})
+ follower = insert(:user)
+
+ {:ok, follow_activity} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
+
+ data =
+ follow_activity_two.data
+ |> Map.put("state", "accept")
+
+ cng = Ecto.Changeset.change(follow_activity_two, data: data)
+
+ {:ok, follow_activity_two} = Repo.update(cng)
+
+ {:ok, follow_activity_two} =
+ Utils.update_follow_state_for_all(follow_activity_two, "accept")
+
+ assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
+ assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
+ end
+ end
+
+ describe "update_follow_state/2" do
+ test "updates the state of the given follow activity" do
+ user = insert(:user, info: %{locked: true})
+ follower = insert(:user)
+
+ {:ok, follow_activity} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
+
+ data =
+ follow_activity_two.data
+ |> Map.put("state", "accept")
+
+ cng = Ecto.Changeset.change(follow_activity_two, data: data)
+
+ {:ok, follow_activity_two} = Repo.update(cng)
+
+ {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
+
+ assert Repo.get(Activity, follow_activity.id).data["state"] == "pending"
+ assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
+ end
+ end
end
diff --git a/test/web/activity_pub/views/object_view_test.exs b/test/web/activity_pub/views/object_view_test.exs
index d939fc5a7..13447dc29 100644
--- a/test/web/activity_pub/views/object_view_test.exs
+++ b/test/web/activity_pub/views/object_view_test.exs
@@ -1,7 +1,12 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
use Pleroma.DataCase
import Pleroma.Factory
+ alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.CommonAPI
@@ -19,19 +24,21 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
test "renders a note activity" do
note = insert(:note_activity)
+ object = Object.normalize(note)
result = ObjectView.render("object.json", %{object: note})
assert result["id"] == note.data["id"]
assert result["to"] == note.data["to"]
assert result["object"]["type"] == "Note"
- assert result["object"]["content"] == note.data["object"]["content"]
+ assert result["object"]["content"] == object.data["content"]
assert result["type"] == "Create"
assert result["@context"]
end
test "renders a like activity" do
note = insert(:note_activity)
+ object = Object.normalize(note)
user = insert(:user)
{:ok, like_activity, _} = CommonAPI.favorite(note.id, user)
@@ -39,12 +46,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
result = ObjectView.render("object.json", %{object: like_activity})
assert result["id"] == like_activity.data["id"]
- assert result["object"] == note.data["object"]["id"]
+ assert result["object"] == object.data["id"]
assert result["type"] == "Like"
end
test "renders an announce activity" do
note = insert(:note_activity)
+ object = Object.normalize(note)
user = insert(:user)
{:ok, announce_activity, _} = CommonAPI.repeat(note.id, user)
@@ -52,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
result = ObjectView.render("object.json", %{object: announce_activity})
assert result["id"] == announce_activity.data["id"]
- assert result["object"] == note.data["object"]["id"]
+ assert result["object"] == object.data["id"]
assert result["type"] == "Announce"
end
end
diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs
index e6483db8b..86254117f 100644
--- a/test/web/activity_pub/views/user_view_test.exs
+++ b/test/web/activity_pub/views/user_view_test.exs
@@ -1,9 +1,14 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.UserViewTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.User
alias Pleroma.Web.ActivityPub.UserView
+ alias Pleroma.Web.CommonAPI
test "Renders a user, including the public key" do
user = insert(:user)
@@ -78,4 +83,28 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
refute result["endpoints"]["oauthTokenEndpoint"]
end
end
+
+ describe "followers" do
+ test "sets totalItems to zero when followers are hidden" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
+ assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
+ info = Map.put(user.info, :hide_followers, true)
+ user = Map.put(user, :info, info)
+ assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user})
+ end
+ end
+
+ describe "following" do
+ test "sets totalItems to zero when follows are hidden" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
+ assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})
+ info = Map.put(user.info, :hide_follows, true)
+ user = Map.put(user, :info, info)
+ assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user})
+ end
+ end
end
diff --git a/test/web/activity_pub/visibilty_test.exs b/test/web/activity_pub/visibilty_test.exs
index e2584f635..b62a89e68 100644
--- a/test/web/activity_pub/visibilty_test.exs
+++ b/test/web/activity_pub/visibilty_test.exs
@@ -1,6 +1,11 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.VisibilityTest do
use Pleroma.DataCase
+ alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
@@ -11,6 +16,9 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
following = insert(:user)
unrelated = insert(:user)
{:ok, following} = Pleroma.User.follow(following, user)
+ {:ok, list} = Pleroma.List.create("foo", user)
+
+ Pleroma.List.follow(list, unrelated)
{:ok, public} =
CommonAPI.post(user, %{"status" => "@#{mentioned.nickname}", "visibility" => "public"})
@@ -24,6 +32,12 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
{:ok, unlisted} =
CommonAPI.post(user, %{"status" => "@#{mentioned.nickname}", "visibility" => "unlisted"})
+ {:ok, list} =
+ CommonAPI.post(user, %{
+ "status" => "@#{mentioned.nickname}",
+ "visibility" => "list:#{list.id}"
+ })
+
%{
public: public,
private: private,
@@ -32,29 +46,65 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
user: user,
mentioned: mentioned,
following: following,
- unrelated: unrelated
+ unrelated: unrelated,
+ list: list
}
end
- test "is_direct?", %{public: public, private: private, direct: direct, unlisted: unlisted} do
+ test "is_direct?", %{
+ public: public,
+ private: private,
+ direct: direct,
+ unlisted: unlisted,
+ list: list
+ } do
assert Visibility.is_direct?(direct)
refute Visibility.is_direct?(public)
refute Visibility.is_direct?(private)
refute Visibility.is_direct?(unlisted)
+ assert Visibility.is_direct?(list)
end
- test "is_public?", %{public: public, private: private, direct: direct, unlisted: unlisted} do
+ test "is_public?", %{
+ public: public,
+ private: private,
+ direct: direct,
+ unlisted: unlisted,
+ list: list
+ } do
refute Visibility.is_public?(direct)
assert Visibility.is_public?(public)
refute Visibility.is_public?(private)
assert Visibility.is_public?(unlisted)
+ refute Visibility.is_public?(list)
end
- test "is_private?", %{public: public, private: private, direct: direct, unlisted: unlisted} do
+ test "is_private?", %{
+ public: public,
+ private: private,
+ direct: direct,
+ unlisted: unlisted,
+ list: list
+ } do
refute Visibility.is_private?(direct)
refute Visibility.is_private?(public)
assert Visibility.is_private?(private)
refute Visibility.is_private?(unlisted)
+ refute Visibility.is_private?(list)
+ end
+
+ test "is_list?", %{
+ public: public,
+ private: private,
+ direct: direct,
+ unlisted: unlisted,
+ list: list
+ } do
+ refute Visibility.is_list?(direct)
+ refute Visibility.is_list?(public)
+ refute Visibility.is_list?(private)
+ refute Visibility.is_list?(unlisted)
+ assert Visibility.is_list?(list)
end
test "visible_for_user?", %{
@@ -65,7 +115,8 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
user: user,
mentioned: mentioned,
following: following,
- unrelated: unrelated
+ unrelated: unrelated,
+ list: list
} do
# All visible to author
@@ -73,6 +124,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
assert Visibility.visible_for_user?(private, user)
assert Visibility.visible_for_user?(unlisted, user)
assert Visibility.visible_for_user?(direct, user)
+ assert Visibility.visible_for_user?(list, user)
# All visible to a mentioned user
@@ -80,6 +132,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
assert Visibility.visible_for_user?(private, mentioned)
assert Visibility.visible_for_user?(unlisted, mentioned)
assert Visibility.visible_for_user?(direct, mentioned)
+ assert Visibility.visible_for_user?(list, mentioned)
# DM not visible for just follower
@@ -87,6 +140,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
assert Visibility.visible_for_user?(private, following)
assert Visibility.visible_for_user?(unlisted, following)
refute Visibility.visible_for_user?(direct, following)
+ refute Visibility.visible_for_user?(list, following)
# Public and unlisted visible for unrelated user
@@ -94,6 +148,9 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
assert Visibility.visible_for_user?(unlisted, unrelated)
refute Visibility.visible_for_user?(private, unrelated)
refute Visibility.visible_for_user?(direct, unrelated)
+
+ # Visible for a list member
+ assert Visibility.visible_for_user?(list, unrelated)
end
test "doesn't die when the user doesn't exist",
@@ -110,11 +167,63 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
public: public,
private: private,
direct: direct,
- unlisted: unlisted
+ unlisted: unlisted,
+ list: list
} do
assert Visibility.get_visibility(public) == "public"
assert Visibility.get_visibility(private) == "private"
assert Visibility.get_visibility(direct) == "direct"
assert Visibility.get_visibility(unlisted) == "unlisted"
+ assert Visibility.get_visibility(list) == "list"
+ end
+
+ test "get_visibility with directMessage flag" do
+ assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct"
+ end
+
+ test "get_visibility with listMessage flag" do
+ assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "list"
+ end
+
+ describe "entire_thread_visible_for_user?/2" do
+ test "returns false if not found activity", %{user: user} do
+ refute Visibility.entire_thread_visible_for_user?(%Activity{}, user)
+ end
+
+ test "returns true if activity hasn't 'Create' type", %{user: user} do
+ activity = insert(:like_activity)
+ assert Visibility.entire_thread_visible_for_user?(activity, user)
+ end
+
+ test "returns false when invalid recipients", %{user: user} do
+ author = insert(:user)
+
+ activity =
+ insert(:note_activity,
+ note:
+ insert(:note,
+ user: author,
+ data: %{"to" => ["test-user"]}
+ )
+ )
+
+ refute Visibility.entire_thread_visible_for_user?(activity, user)
+ end
+
+ test "returns true if user following to author" do
+ author = insert(:user)
+ user = insert(:user, following: [author.ap_id])
+
+ activity =
+ insert(:note_activity,
+ note:
+ insert(:note,
+ user: author,
+ data: %{"to" => [user.ap_id]}
+ )
+ )
+
+ assert Visibility.entire_thread_visible_for_user?(activity, user)
+ end
end
end
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 43dcf945a..ee48b752c 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -6,9 +6,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Activity
+ alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.UserInviteToken
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MediaProxy
import Pleroma.Factory
describe "/api/pleroma/admin/users" do
@@ -58,7 +60,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"local" => true,
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
assert expected == json_response(conn, 200)
@@ -445,7 +449,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => admin.nickname,
"roles" => %{"admin" => true, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(admin.name || admin.nickname)
},
%{
"deactivated" => user.info.deactivated,
@@ -453,7 +459,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => false,
- "tags" => ["foo", "bar"]
+ "tags" => ["foo", "bar"],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -492,7 +500,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -514,7 +524,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -536,7 +548,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -558,7 +572,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -580,7 +596,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -602,7 +620,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -619,7 +639,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user2.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user2.name || user2.nickname)
}
]
}
@@ -646,7 +668,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -671,7 +695,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
},
%{
"deactivated" => admin.info.deactivated,
@@ -679,7 +705,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => admin.nickname,
"roles" => %{"admin" => true, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(admin.name || admin.nickname)
},
%{
"deactivated" => false,
@@ -687,7 +715,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"local" => true,
"nickname" => old_admin.nickname,
"roles" => %{"admin" => true, "moderator" => false},
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname)
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -714,7 +744,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => admin.nickname,
"roles" => %{"admin" => true, "moderator" => false},
"local" => admin.local,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(admin.name || admin.nickname)
},
%{
"deactivated" => false,
@@ -722,7 +754,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => second_admin.nickname,
"roles" => %{"admin" => true, "moderator" => false},
"local" => second_admin.local,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname)
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -751,7 +785,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => moderator.nickname,
"roles" => %{"admin" => false, "moderator" => true},
"local" => moderator.local,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(moderator.name || moderator.nickname)
}
]
}
@@ -773,7 +809,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user1.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => user1.local,
- "tags" => ["first"]
+ "tags" => ["first"],
+ "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user1.name || user1.nickname)
},
%{
"deactivated" => false,
@@ -781,7 +819,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user2.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => user2.local,
- "tags" => ["second"]
+ "tags" => ["second"],
+ "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user2.name || user2.nickname)
}
]
|> Enum.sort_by(& &1["nickname"])
@@ -815,7 +855,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => user.local,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
]
}
@@ -838,7 +880,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"nickname" => user.nickname,
"roles" => %{"admin" => false, "moderator" => false},
"local" => true,
- "tags" => []
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname)
}
end
@@ -1190,7 +1234,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
recipients = Enum.map(response["mentions"], & &1["username"])
- assert conn.assigns[:user].nickname in recipients
assert reporter.nickname in recipients
assert response["content"] == "I will check it out"
assert response["visibility"] == "direct"
@@ -1292,4 +1335,578 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert json_response(conn, :bad_request) == "Could not delete"
end
end
+
+ describe "GET /api/pleroma/admin/config" do
+ setup %{conn: conn} do
+ admin = insert(:user, info: %{is_admin: true})
+
+ %{conn: assign(conn, :user, admin)}
+ end
+
+ test "without any settings in db", %{conn: conn} do
+ conn = get(conn, "/api/pleroma/admin/config")
+
+ assert json_response(conn, 200) == %{"configs" => []}
+ end
+
+ test "with settings in db", %{conn: conn} do
+ config1 = insert(:config)
+ config2 = insert(:config)
+
+ conn = get(conn, "/api/pleroma/admin/config")
+
+ %{
+ "configs" => [
+ %{
+ "key" => key1,
+ "value" => _
+ },
+ %{
+ "key" => key2,
+ "value" => _
+ }
+ ]
+ } = json_response(conn, 200)
+
+ assert key1 == config1.key
+ assert key2 == config2.key
+ end
+ end
+
+ describe "POST /api/pleroma/admin/config" do
+ setup %{conn: conn} do
+ admin = insert(:user, info: %{is_admin: true})
+
+ temp_file = "config/test.exported_from_db.secret.exs"
+
+ on_exit(fn ->
+ Application.delete_env(:pleroma, :key1)
+ Application.delete_env(:pleroma, :key2)
+ Application.delete_env(:pleroma, :key3)
+ Application.delete_env(:pleroma, :key4)
+ Application.delete_env(:pleroma, :keyaa1)
+ Application.delete_env(:pleroma, :keyaa2)
+ Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
+ Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
+ :ok = File.rm(temp_file)
+ end)
+
+ dynamic = Pleroma.Config.get([:instance, :dynamic_configuration])
+
+ Pleroma.Config.put([:instance, :dynamic_configuration], true)
+
+ on_exit(fn ->
+ Pleroma.Config.put([:instance, :dynamic_configuration], dynamic)
+ end)
+
+ %{conn: assign(conn, :user, admin)}
+ end
+
+ test "create new config setting in db", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{group: "pleroma", key: "key1", value: "value1"},
+ %{
+ group: "ueberauth",
+ key: "Ueberauth.Strategy.Twitter.OAuth",
+ value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
+ },
+ %{
+ group: "pleroma",
+ key: "key2",
+ value: %{
+ ":nested_1" => "nested_value1",
+ ":nested_2" => [
+ %{":nested_22" => "nested_value222"},
+ %{":nested_33" => %{":nested_44" => "nested_444"}}
+ ]
+ }
+ },
+ %{
+ group: "pleroma",
+ key: "key3",
+ value: [
+ %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
+ %{"nested_4" => true}
+ ]
+ },
+ %{
+ group: "pleroma",
+ key: "key4",
+ value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
+ },
+ %{
+ group: "idna",
+ key: "key5",
+ value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => "key1",
+ "value" => "value1"
+ },
+ %{
+ "group" => "ueberauth",
+ "key" => "Ueberauth.Strategy.Twitter.OAuth",
+ "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}]
+ },
+ %{
+ "group" => "pleroma",
+ "key" => "key2",
+ "value" => %{
+ ":nested_1" => "nested_value1",
+ ":nested_2" => [
+ %{":nested_22" => "nested_value222"},
+ %{":nested_33" => %{":nested_44" => "nested_444"}}
+ ]
+ }
+ },
+ %{
+ "group" => "pleroma",
+ "key" => "key3",
+ "value" => [
+ %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
+ %{"nested_4" => true}
+ ]
+ },
+ %{
+ "group" => "pleroma",
+ "key" => "key4",
+ "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
+ },
+ %{
+ "group" => "idna",
+ "key" => "key5",
+ "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
+ }
+ ]
+ }
+
+ assert Application.get_env(:pleroma, :key1) == "value1"
+
+ assert Application.get_env(:pleroma, :key2) == %{
+ nested_1: "nested_value1",
+ nested_2: [
+ %{nested_22: "nested_value222"},
+ %{nested_33: %{nested_44: "nested_444"}}
+ ]
+ }
+
+ assert Application.get_env(:pleroma, :key3) == [
+ %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
+ %{"nested_4" => true}
+ ]
+
+ assert Application.get_env(:pleroma, :key4) == %{
+ "endpoint" => "https://example.com",
+ nested_5: :upload
+ }
+
+ assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
+ end
+
+ test "update config setting & delete", %{conn: conn} do
+ config1 = insert(:config, key: "keyaa1")
+ config2 = insert(:config, key: "keyaa2")
+
+ insert(:config,
+ group: "ueberauth",
+ key: "Ueberauth.Strategy.Microsoft.OAuth",
+ value: :erlang.term_to_binary([])
+ )
+
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{group: config1.group, key: config1.key, value: "another_value"},
+ %{group: config2.group, key: config2.key, delete: "true"},
+ %{
+ group: "ueberauth",
+ key: "Ueberauth.Strategy.Microsoft.OAuth",
+ delete: "true"
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => config1.key,
+ "value" => "another_value"
+ }
+ ]
+ }
+
+ assert Application.get_env(:pleroma, :keyaa1) == "another_value"
+ refute Application.get_env(:pleroma, :keyaa2)
+ end
+
+ test "common config example", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Captcha.NotReal",
+ "value" => [
+ %{"tuple" => [":enabled", false]},
+ %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
+ %{"tuple" => [":seconds_valid", 60]},
+ %{"tuple" => [":path", ""]},
+ %{"tuple" => [":key1", nil]}
+ ]
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Captcha.NotReal",
+ "value" => [
+ %{"tuple" => [":enabled", false]},
+ %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
+ %{"tuple" => [":seconds_valid", 60]},
+ %{"tuple" => [":path", ""]},
+ %{"tuple" => [":key1", nil]}
+ ]
+ }
+ ]
+ }
+ end
+
+ test "tuples with more than two values", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Web.Endpoint.NotReal",
+ "value" => [
+ %{
+ "tuple" => [
+ ":http",
+ [
+ %{
+ "tuple" => [
+ ":key2",
+ [
+ %{
+ "tuple" => [
+ ":_",
+ [
+ %{
+ "tuple" => [
+ "/api/v1/streaming",
+ "Pleroma.Web.MastodonAPI.WebsocketHandler",
+ []
+ ]
+ },
+ %{
+ "tuple" => [
+ "/websocket",
+ "Phoenix.Endpoint.CowboyWebSocket",
+ %{
+ "tuple" => [
+ "Phoenix.Transports.WebSocket",
+ %{
+ "tuple" => [
+ "Pleroma.Web.Endpoint",
+ "Pleroma.Web.UserSocket",
+ []
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ %{
+ "tuple" => [
+ ":_",
+ "Phoenix.Endpoint.Cowboy2Handler",
+ %{"tuple" => ["Pleroma.Web.Endpoint", []]}
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Web.Endpoint.NotReal",
+ "value" => [
+ %{
+ "tuple" => [
+ ":http",
+ [
+ %{
+ "tuple" => [
+ ":key2",
+ [
+ %{
+ "tuple" => [
+ ":_",
+ [
+ %{
+ "tuple" => [
+ "/api/v1/streaming",
+ "Pleroma.Web.MastodonAPI.WebsocketHandler",
+ []
+ ]
+ },
+ %{
+ "tuple" => [
+ "/websocket",
+ "Phoenix.Endpoint.CowboyWebSocket",
+ %{
+ "tuple" => [
+ "Phoenix.Transports.WebSocket",
+ %{
+ "tuple" => [
+ "Pleroma.Web.Endpoint",
+ "Pleroma.Web.UserSocket",
+ []
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ %{
+ "tuple" => [
+ ":_",
+ "Phoenix.Endpoint.Cowboy2Handler",
+ %{"tuple" => ["Pleroma.Web.Endpoint", []]}
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ end
+
+ test "settings with nesting map", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma",
+ "key" => ":key1",
+ "value" => [
+ %{"tuple" => [":key2", "some_val"]},
+ %{
+ "tuple" => [
+ ":key3",
+ %{
+ ":max_options" => 20,
+ ":max_option_chars" => 200,
+ ":min_expiration" => 0,
+ ":max_expiration" => 31_536_000,
+ "nested" => %{
+ ":max_options" => 20,
+ ":max_option_chars" => 200,
+ ":min_expiration" => 0,
+ ":max_expiration" => 31_536_000
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) ==
+ %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => ":key1",
+ "value" => [
+ %{"tuple" => [":key2", "some_val"]},
+ %{
+ "tuple" => [
+ ":key3",
+ %{
+ ":max_expiration" => 31_536_000,
+ ":max_option_chars" => 200,
+ ":max_options" => 20,
+ ":min_expiration" => 0,
+ "nested" => %{
+ ":max_expiration" => 31_536_000,
+ ":max_option_chars" => 200,
+ ":max_options" => 20,
+ ":min_expiration" => 0
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ end
+
+ test "value as map", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma",
+ "key" => ":key1",
+ "value" => %{"key" => "some_val"}
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) ==
+ %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => ":key1",
+ "value" => %{"key" => "some_val"}
+ }
+ ]
+ }
+ end
+
+ test "dispatch setting", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Web.Endpoint.NotReal",
+ "value" => [
+ %{
+ "tuple" => [
+ ":http",
+ [
+ %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
+ %{"tuple" => [":dispatch", ["{:_,
+ [
+ {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}"]]}
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ })
+
+ dispatch_string =
+ "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
+ "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
+ "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
+ "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma",
+ "key" => "Pleroma.Web.Endpoint.NotReal",
+ "value" => [
+ %{
+ "tuple" => [
+ ":http",
+ [
+ %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
+ %{
+ "tuple" => [
+ ":dispatch",
+ [
+ dispatch_string
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ end
+
+ test "queues key as atom", %{conn: conn} do
+ conn =
+ post(conn, "/api/pleroma/admin/config", %{
+ configs: [
+ %{
+ "group" => "pleroma_job_queue",
+ "key" => ":queues",
+ "value" => [
+ %{"tuple" => [":federator_incoming", 50]},
+ %{"tuple" => [":federator_outgoing", 50]},
+ %{"tuple" => [":web_push", 50]},
+ %{"tuple" => [":mailer", 10]},
+ %{"tuple" => [":transmogrifier", 20]},
+ %{"tuple" => [":scheduled_activities", 10]},
+ %{"tuple" => [":background", 5]}
+ ]
+ }
+ ]
+ })
+
+ assert json_response(conn, 200) == %{
+ "configs" => [
+ %{
+ "group" => "pleroma_job_queue",
+ "key" => ":queues",
+ "value" => [
+ %{"tuple" => [":federator_incoming", 50]},
+ %{"tuple" => [":federator_outgoing", 50]},
+ %{"tuple" => [":web_push", 50]},
+ %{"tuple" => [":mailer", 10]},
+ %{"tuple" => [":transmogrifier", 20]},
+ %{"tuple" => [":scheduled_activities", 10]},
+ %{"tuple" => [":background", 5]}
+ ]
+ }
+ ]
+ }
+ end
+ end
+end
+
+# Needed for testing
+defmodule Pleroma.Web.Endpoint.NotReal do
+end
+
+defmodule Pleroma.Captcha.NotReal do
end
diff --git a/test/web/admin_api/config_test.exs b/test/web/admin_api/config_test.exs
new file mode 100644
index 000000000..d41666ef3
--- /dev/null
+++ b/test/web/admin_api/config_test.exs
@@ -0,0 +1,465 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.ConfigTest do
+ use Pleroma.DataCase, async: true
+ import Pleroma.Factory
+ alias Pleroma.Web.AdminAPI.Config
+
+ test "get_by_key/1" do
+ config = insert(:config)
+ insert(:config)
+
+ assert config == Config.get_by_params(%{group: config.group, key: config.key})
+ end
+
+ test "create/1" do
+ {:ok, config} = Config.create(%{group: "pleroma", key: "some_key", value: "some_value"})
+ assert config == Config.get_by_params(%{group: "pleroma", key: "some_key"})
+ end
+
+ test "update/1" do
+ config = insert(:config)
+ {:ok, updated} = Config.update(config, %{value: "some_value"})
+ loaded = Config.get_by_params(%{group: config.group, key: config.key})
+ assert loaded == updated
+ end
+
+ test "update_or_create/1" do
+ config = insert(:config)
+ key2 = "another_key"
+
+ params = [
+ %{group: "pleroma", key: key2, value: "another_value"},
+ %{group: config.group, key: config.key, value: "new_value"}
+ ]
+
+ assert Repo.all(Config) |> length() == 1
+
+ Enum.each(params, &Config.update_or_create(&1))
+
+ assert Repo.all(Config) |> length() == 2
+
+ config1 = Config.get_by_params(%{group: config.group, key: config.key})
+ config2 = Config.get_by_params(%{group: "pleroma", key: key2})
+
+ assert config1.value == Config.transform("new_value")
+ assert config2.value == Config.transform("another_value")
+ end
+
+ test "delete/1" do
+ config = insert(:config)
+ {:ok, _} = Config.delete(%{key: config.key, group: config.group})
+ refute Config.get_by_params(%{key: config.key, group: config.group})
+ end
+
+ describe "transform/1" do
+ test "string" do
+ binary = Config.transform("value as string")
+ assert binary == :erlang.term_to_binary("value as string")
+ assert Config.from_binary(binary) == "value as string"
+ end
+
+ test "boolean" do
+ binary = Config.transform(false)
+ assert binary == :erlang.term_to_binary(false)
+ assert Config.from_binary(binary) == false
+ end
+
+ test "nil" do
+ binary = Config.transform(nil)
+ assert binary == :erlang.term_to_binary(nil)
+ assert Config.from_binary(binary) == nil
+ end
+
+ test "integer" do
+ binary = Config.transform(150)
+ assert binary == :erlang.term_to_binary(150)
+ assert Config.from_binary(binary) == 150
+ end
+
+ test "atom" do
+ binary = Config.transform(":atom")
+ assert binary == :erlang.term_to_binary(:atom)
+ assert Config.from_binary(binary) == :atom
+ end
+
+ test "pleroma module" do
+ binary = Config.transform("Pleroma.Bookmark")
+ assert binary == :erlang.term_to_binary(Pleroma.Bookmark)
+ assert Config.from_binary(binary) == Pleroma.Bookmark
+ end
+
+ test "phoenix module" do
+ binary = Config.transform("Phoenix.Socket.V1.JSONSerializer")
+ assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer)
+ assert Config.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer
+ end
+
+ test "sigil" do
+ binary = Config.transform("~r/comp[lL][aA][iI][nN]er/")
+ assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
+ assert Config.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/
+ end
+
+ test "2 child tuple" do
+ binary = Config.transform(%{"tuple" => ["v1", ":v2"]})
+ assert binary == :erlang.term_to_binary({"v1", :v2})
+ assert Config.from_binary(binary) == {"v1", :v2}
+ end
+
+ test "tuple with n childs" do
+ binary =
+ Config.transform(%{
+ "tuple" => [
+ "v1",
+ ":v2",
+ "Pleroma.Bookmark",
+ 150,
+ false,
+ "Phoenix.Socket.V1.JSONSerializer"
+ ]
+ })
+
+ assert binary ==
+ :erlang.term_to_binary(
+ {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
+ )
+
+ assert Config.from_binary(binary) ==
+ {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
+ end
+
+ test "tuple with dispatch key" do
+ binary = Config.transform(%{"tuple" => [":dispatch", ["{:_,
+ [
+ {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}"]]})
+
+ assert binary ==
+ :erlang.term_to_binary(
+ {:dispatch,
+ [
+ {:_,
+ [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}
+ ]}
+ )
+
+ assert Config.from_binary(binary) ==
+ {:dispatch,
+ [
+ {:_,
+ [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}
+ ]}
+ end
+
+ test "map with string key" do
+ binary = Config.transform(%{"key" => "value"})
+ assert binary == :erlang.term_to_binary(%{"key" => "value"})
+ assert Config.from_binary(binary) == %{"key" => "value"}
+ end
+
+ test "map with atom key" do
+ binary = Config.transform(%{":key" => "value"})
+ assert binary == :erlang.term_to_binary(%{key: "value"})
+ assert Config.from_binary(binary) == %{key: "value"}
+ end
+
+ test "list of strings" do
+ binary = Config.transform(["v1", "v2", "v3"])
+ assert binary == :erlang.term_to_binary(["v1", "v2", "v3"])
+ assert Config.from_binary(binary) == ["v1", "v2", "v3"]
+ end
+
+ test "list of modules" do
+ binary = Config.transform(["Pleroma.Repo", "Pleroma.Activity"])
+ assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity])
+ assert Config.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity]
+ end
+
+ test "list of atoms" do
+ binary = Config.transform([":v1", ":v2", ":v3"])
+ assert binary == :erlang.term_to_binary([:v1, :v2, :v3])
+ assert Config.from_binary(binary) == [:v1, :v2, :v3]
+ end
+
+ test "list of mixed values" do
+ binary =
+ Config.transform([
+ "v1",
+ ":v2",
+ "Pleroma.Repo",
+ "Phoenix.Socket.V1.JSONSerializer",
+ 15,
+ false
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary([
+ "v1",
+ :v2,
+ Pleroma.Repo,
+ Phoenix.Socket.V1.JSONSerializer,
+ 15,
+ false
+ ])
+
+ assert Config.from_binary(binary) == [
+ "v1",
+ :v2,
+ Pleroma.Repo,
+ Phoenix.Socket.V1.JSONSerializer,
+ 15,
+ false
+ ]
+ end
+
+ test "simple keyword" do
+ binary = Config.transform([%{"tuple" => [":key", "value"]}])
+ assert binary == :erlang.term_to_binary([{:key, "value"}])
+ assert Config.from_binary(binary) == [{:key, "value"}]
+ assert Config.from_binary(binary) == [key: "value"]
+ end
+
+ test "keyword" do
+ binary =
+ Config.transform([
+ %{"tuple" => [":types", "Pleroma.PostgresTypes"]},
+ %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]},
+ %{"tuple" => [":migration_lock", nil]},
+ %{"tuple" => [":key1", 150]},
+ %{"tuple" => [":key2", "string"]}
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary(
+ types: Pleroma.PostgresTypes,
+ telemetry_event: [Pleroma.Repo.Instrumenter],
+ migration_lock: nil,
+ key1: 150,
+ key2: "string"
+ )
+
+ assert Config.from_binary(binary) == [
+ types: Pleroma.PostgresTypes,
+ telemetry_event: [Pleroma.Repo.Instrumenter],
+ migration_lock: nil,
+ key1: 150,
+ key2: "string"
+ ]
+ end
+
+ test "complex keyword with nested mixed childs" do
+ binary =
+ Config.transform([
+ %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]},
+ %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]},
+ %{"tuple" => [":link_name", true]},
+ %{"tuple" => [":proxy_remote", false]},
+ %{"tuple" => [":common_map", %{":key" => "value"}]},
+ %{
+ "tuple" => [
+ ":proxy_opts",
+ [
+ %{"tuple" => [":redirect_on_failure", false]},
+ %{"tuple" => [":max_body_length", 1_048_576]},
+ %{
+ "tuple" => [
+ ":http",
+ [%{"tuple" => [":follow_redirect", true]}, %{"tuple" => [":pool", ":upload"]}]
+ ]
+ }
+ ]
+ ]
+ }
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary(
+ uploader: Pleroma.Uploaders.Local,
+ filters: [Pleroma.Upload.Filter.Dedupe],
+ link_name: true,
+ proxy_remote: false,
+ common_map: %{key: "value"},
+ proxy_opts: [
+ redirect_on_failure: false,
+ max_body_length: 1_048_576,
+ http: [
+ follow_redirect: true,
+ pool: :upload
+ ]
+ ]
+ )
+
+ assert Config.from_binary(binary) ==
+ [
+ uploader: Pleroma.Uploaders.Local,
+ filters: [Pleroma.Upload.Filter.Dedupe],
+ link_name: true,
+ proxy_remote: false,
+ common_map: %{key: "value"},
+ proxy_opts: [
+ redirect_on_failure: false,
+ max_body_length: 1_048_576,
+ http: [
+ follow_redirect: true,
+ pool: :upload
+ ]
+ ]
+ ]
+ end
+
+ test "common keyword" do
+ binary =
+ Config.transform([
+ %{"tuple" => [":level", ":warn"]},
+ %{"tuple" => [":meta", [":all"]]},
+ %{"tuple" => [":path", ""]},
+ %{"tuple" => [":val", nil]},
+ %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]}
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary(
+ level: :warn,
+ meta: [:all],
+ path: "",
+ val: nil,
+ webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
+ )
+
+ assert Config.from_binary(binary) == [
+ level: :warn,
+ meta: [:all],
+ path: "",
+ val: nil,
+ webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
+ ]
+ end
+
+ test "complex keyword with sigil" do
+ binary =
+ Config.transform([
+ %{"tuple" => [":federated_timeline_removal", []]},
+ %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]},
+ %{"tuple" => [":replace", []]}
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary(
+ federated_timeline_removal: [],
+ reject: [~r/comp[lL][aA][iI][nN]er/],
+ replace: []
+ )
+
+ assert Config.from_binary(binary) ==
+ [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []]
+ end
+
+ test "complex keyword with tuples with more than 2 values" do
+ binary =
+ Config.transform([
+ %{
+ "tuple" => [
+ ":http",
+ [
+ %{
+ "tuple" => [
+ ":key1",
+ [
+ %{
+ "tuple" => [
+ ":_",
+ [
+ %{
+ "tuple" => [
+ "/api/v1/streaming",
+ "Pleroma.Web.MastodonAPI.WebsocketHandler",
+ []
+ ]
+ },
+ %{
+ "tuple" => [
+ "/websocket",
+ "Phoenix.Endpoint.CowboyWebSocket",
+ %{
+ "tuple" => [
+ "Phoenix.Transports.WebSocket",
+ %{
+ "tuple" => [
+ "Pleroma.Web.Endpoint",
+ "Pleroma.Web.UserSocket",
+ []
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ %{
+ "tuple" => [
+ ":_",
+ "Phoenix.Endpoint.Cowboy2Handler",
+ %{"tuple" => ["Pleroma.Web.Endpoint", []]}
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ }
+ ])
+
+ assert binary ==
+ :erlang.term_to_binary(
+ http: [
+ key1: [
+ _: [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]
+ ]
+ ]
+ )
+
+ assert Config.from_binary(binary) == [
+ http: [
+ key1: [
+ {:_,
+ [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}
+ ]
+ ]
+ ]
+ end
+ end
+end
diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs
new file mode 100644
index 000000000..a00c9c579
--- /dev/null
+++ b/test/web/admin_api/views/report_view_test.exs
@@ -0,0 +1,130 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.ReportViewTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ alias Pleroma.Web.AdminAPI.ReportView
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ test "renders a report" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id})
+
+ expected = %{
+ content: nil,
+ actor:
+ Map.merge(
+ AccountView.render("account.json", %{user: user}),
+ Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})
+ ),
+ account:
+ Map.merge(
+ AccountView.render("account.json", %{user: other_user}),
+ Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
+ ),
+ statuses: [],
+ state: "open",
+ id: activity.id
+ }
+
+ result =
+ ReportView.render("show.json", %{report: activity})
+ |> Map.delete(:created_at)
+
+ assert result == expected
+ end
+
+ test "includes reported statuses" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "toot"})
+
+ {:ok, report_activity} =
+ CommonAPI.report(user, %{"account_id" => other_user.id, "status_ids" => [activity.id]})
+
+ expected = %{
+ content: nil,
+ actor:
+ Map.merge(
+ AccountView.render("account.json", %{user: user}),
+ Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})
+ ),
+ account:
+ Map.merge(
+ AccountView.render("account.json", %{user: other_user}),
+ Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
+ ),
+ statuses: [StatusView.render("status.json", %{activity: activity})],
+ state: "open",
+ id: report_activity.id
+ }
+
+ result =
+ ReportView.render("show.json", %{report: report_activity})
+ |> Map.delete(:created_at)
+
+ assert result == expected
+ end
+
+ test "renders report's state" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id})
+ {:ok, activity} = CommonAPI.update_report_state(activity.id, "closed")
+ assert %{state: "closed"} = ReportView.render("show.json", %{report: activity})
+ end
+
+ test "renders report description" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.report(user, %{
+ "account_id" => other_user.id,
+ "comment" => "posts are too good for this instance"
+ })
+
+ assert %{content: "posts are too good for this instance"} =
+ ReportView.render("show.json", %{report: activity})
+ end
+
+ test "sanitizes report description" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.report(user, %{
+ "account_id" => other_user.id,
+ "comment" => ""
+ })
+
+ data = Map.put(activity.data, "content", "<script> alert('hecked :D:D:D:D:D:D:D') </script>")
+ activity = Map.put(activity, :data, data)
+
+ refute "<script> alert('hecked :D:D:D:D:D:D:D') </script>" ==
+ ReportView.render("show.json", %{report: activity})[:content]
+ end
+
+ test "doesn't error out when the user doesn't exists" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.report(user, %{
+ "account_id" => other_user.id,
+ "comment" => ""
+ })
+
+ Pleroma.User.delete(other_user)
+ Pleroma.User.invalidate_cache(other_user)
+
+ assert %{} = ReportView.render("show.json", %{report: activity})
+ end
+end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 696060fb1..16b3f121d 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.CommonAPITest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
@@ -33,7 +34,7 @@ defmodule Pleroma.Web.CommonAPITest do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu #2HU"})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert object.data["tag"] == ["2hu"]
end
@@ -56,6 +57,25 @@ defmodule Pleroma.Web.CommonAPITest do
end
describe "posting" do
+ test "it supports explicit addressing" do
+ user = insert(:user)
+ user_two = insert(:user)
+ user_three = insert(:user)
+ user_four = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" =>
+ "Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
+ "to" => [user_two.nickname, user_four.nickname, "nonexistent"]
+ })
+
+ assert user.ap_id in activity.recipients
+ assert user_two.ap_id in activity.recipients
+ assert user_four.ap_id in activity.recipients
+ refute user_three.ap_id in activity.recipients
+ end
+
test "it filters out obviously bad tags when accepting a post as HTML" do
user = insert(:user)
@@ -67,7 +87,7 @@ defmodule Pleroma.Web.CommonAPITest do
"content_type" => "text/html"
})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
end
@@ -83,7 +103,7 @@ defmodule Pleroma.Web.CommonAPITest do
"content_type" => "text/markdown"
})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
end
@@ -101,7 +121,7 @@ defmodule Pleroma.Web.CommonAPITest do
})
Enum.each(["public", "private", "unlisted"], fn visibility ->
- assert {:error, {:private_to_public, _}} =
+ assert {:error, "The message visibility must be direct"} =
CommonAPI.post(user, %{
"status" => "suya..",
"visibility" => visibility,
@@ -109,6 +129,37 @@ defmodule Pleroma.Web.CommonAPITest do
})
end)
end
+
+ test "it allows to address a list" do
+ user = insert(:user)
+ {:ok, list} = Pleroma.List.create("foo", user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+
+ assert activity.data["bcc"] == [list.ap_id]
+ assert activity.recipients == [list.ap_id, user.ap_id]
+ assert activity.data["listMessage"] == list.ap_id
+ end
+
+ test "it returns error when status is empty and no attachments" do
+ user = insert(:user)
+
+ assert {:error, "Cannot post an empty status without attachments"} =
+ CommonAPI.post(user, %{"status" => ""})
+ end
+
+ test "it returns error when character limit is exceeded" do
+ limit = Pleroma.Config.get([:instance, :limit])
+ Pleroma.Config.put([:instance, :limit], 5)
+
+ user = insert(:user)
+
+ assert {:error, "The status is over the character limit"} =
+ CommonAPI.post(user, %{"status" => "foobar"})
+
+ Pleroma.Config.put([:instance, :limit], limit)
+ end
end
describe "reactions" do
@@ -168,6 +219,11 @@ defmodule Pleroma.Web.CommonAPITest do
assert %User{info: %{pinned_activities: [^id]}} = user
end
+ test "unlisted statuses can be pinned", %{user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!", "visibility" => "unlisted"})
+ assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
+ end
+
test "only self-authored can be pinned", %{activity: activity} do
user = insert(:user)
@@ -320,4 +376,79 @@ defmodule Pleroma.Web.CommonAPITest do
assert User.showing_reblogs?(muter, muted) == true
end
end
+
+ describe "unfollow/2" do
+ test "also unsubscribes a user" do
+ [follower, followed] = insert_pair(:user)
+ {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
+ {:ok, followed} = User.subscribe(follower, followed)
+
+ assert User.subscribed_to?(follower, followed)
+
+ {:ok, follower} = CommonAPI.unfollow(follower, followed)
+
+ refute User.subscribed_to?(follower, followed)
+ end
+ end
+
+ describe "accept_follow_request/2" do
+ test "after acceptance, it sets all existing pending follow request states to 'accept'" do
+ user = insert(:user, info: %{locked: true})
+ follower = insert(:user)
+ follower_two = insert(:user)
+
+ {:ok, follow_activity} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
+
+ assert follow_activity.data["state"] == "pending"
+ assert follow_activity_two.data["state"] == "pending"
+ assert follow_activity_three.data["state"] == "pending"
+
+ {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
+
+ assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
+ assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
+ assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
+ end
+
+ test "after rejection, it sets all existing pending follow request states to 'reject'" do
+ user = insert(:user, info: %{locked: true})
+ follower = insert(:user)
+ follower_two = insert(:user)
+
+ {:ok, follow_activity} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
+ {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
+
+ assert follow_activity.data["state"] == "pending"
+ assert follow_activity_two.data["state"] == "pending"
+ assert follow_activity_three.data["state"] == "pending"
+
+ {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
+
+ assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
+ assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
+ assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
+ end
+ end
+
+ describe "vote/3" do
+ test "does not allow to vote twice" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Am I cute?",
+ "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
+ })
+
+ object = Object.normalize(activity)
+
+ {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
+
+ assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
+ end
+ end
end
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index ab4c62b35..af320f31f 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -5,10 +5,16 @@
defmodule Pleroma.Web.CommonAPI.UtilsTest do
alias Pleroma.Builders.UserBuilder
alias Pleroma.Object
+ alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.Endpoint
use Pleroma.DataCase
+ import ExUnit.CaptureLog
+ import Pleroma.Factory
+
+ @public_address "https://www.w3.org/ns/activitystreams#Public"
+
test "it adds attachment links to a given text and attachment set" do
name =
"Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png"
@@ -197,7 +203,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
expected = ""
- assert Utils.date_to_asctime(date) == expected
+ assert capture_log(fn ->
+ assert Utils.date_to_asctime(date) == expected
+ end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
end
test "when date is a Unix timestamp" do
@@ -205,13 +213,151 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
expected = ""
- assert Utils.date_to_asctime(date) == expected
+ assert capture_log(fn ->
+ assert Utils.date_to_asctime(date) == expected
+ end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
end
test "when date is nil" do
expected = ""
- assert Utils.date_to_asctime(nil) == expected
+ assert capture_log(fn ->
+ assert Utils.date_to_asctime(nil) == expected
+ end) =~ "[warn] Date in wrong format, must be ISO 8601"
+ end
+
+ test "when date is a random string" do
+ assert capture_log(fn ->
+ assert Utils.date_to_asctime("foo") == ""
+ end) =~ "[warn] Date foo in wrong format, must be ISO 8601"
+ end
+ end
+
+ describe "get_to_and_cc" do
+ test "for public posts, not a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public")
+
+ assert length(to) == 2
+ assert length(cc) == 1
+
+ assert @public_address in to
+ assert mentioned_user.ap_id in to
+ assert user.follower_address in cc
+ end
+
+ test "for public posts, a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ third_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public")
+
+ assert length(to) == 3
+ assert length(cc) == 1
+
+ assert @public_address in to
+ assert mentioned_user.ap_id in to
+ assert third_user.ap_id in to
+ assert user.follower_address in cc
+ end
+
+ test "for unlisted posts, not a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted")
+
+ assert length(to) == 2
+ assert length(cc) == 1
+
+ assert @public_address in cc
+ assert mentioned_user.ap_id in to
+ assert user.follower_address in to
+ end
+
+ test "for unlisted posts, a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ third_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted")
+
+ assert length(to) == 3
+ assert length(cc) == 1
+
+ assert @public_address in cc
+ assert mentioned_user.ap_id in to
+ assert third_user.ap_id in to
+ assert user.follower_address in to
+ end
+
+ test "for private posts, not a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private")
+
+ assert length(to) == 2
+ assert length(cc) == 0
+
+ assert mentioned_user.ap_id in to
+ assert user.follower_address in to
+ end
+
+ test "for private posts, a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ third_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private")
+
+ assert length(to) == 3
+ assert length(cc) == 0
+
+ assert mentioned_user.ap_id in to
+ assert third_user.ap_id in to
+ assert user.follower_address in to
+ end
+
+ test "for direct posts, not a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct")
+
+ assert length(to) == 1
+ assert length(cc) == 0
+
+ assert mentioned_user.ap_id in to
+ end
+
+ test "for direct posts, a reply" do
+ user = insert(:user)
+ mentioned_user = insert(:user)
+ third_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
+ mentions = [mentioned_user.ap_id]
+
+ {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct")
+
+ assert length(to) == 2
+ assert length(cc) == 0
+
+ assert mentioned_user.ap_id in to
+ assert third_user.ap_id in to
end
end
end
diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs
index 0f43bc8f2..69dd4d747 100644
--- a/test/web/federator_test.exs
+++ b/test/web/federator_test.exs
@@ -12,6 +12,13 @@ defmodule Pleroma.Web.FederatorTest do
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ Pleroma.Config.put(config_path, true)
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
:ok
end
diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs
index aaf2261bb..de6aeec72 100644
--- a/test/web/mastodon_api/account_view_test.exs
+++ b/test/web/mastodon_api/account_view_test.exs
@@ -19,9 +19,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
]
}
+ background_image = %{
+ "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}]
+ }
+
user =
insert(:user, %{
- info: %{note_count: 5, follower_count: 3, source_data: source_data},
+ info: %{
+ note_count: 5,
+ follower_count: 3,
+ source_data: source_data,
+ background: background_image
+ },
nickname: "shp@shitposter.club",
name: ":karjalanpiirakka: shp",
bio: "<script src=\"invalid-html\"></script><span>valid html</span>",
@@ -60,6 +69,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
pleroma: %{}
},
pleroma: %{
+ background_image: "https://example.com/images/asuka_hospital.png",
confirmation_pending: false,
tags: [],
is_admin: false,
@@ -67,7 +77,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
hide_favorites: true,
hide_followers: false,
hide_follows: false,
- relationship: %{}
+ relationship: %{},
+ skip_thread_containment: false
}
}
@@ -78,10 +89,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
user = insert(:user)
notification_settings = %{
- "remote" => true,
- "local" => true,
"followers" => true,
- "follows" => true
+ "follows" => true,
+ "non_follows" => true,
+ "non_followers" => true
}
privacy = user.info.default_scope
@@ -125,6 +136,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
pleroma: %{}
},
pleroma: %{
+ background_image: nil,
confirmation_pending: false,
tags: [],
is_admin: false,
@@ -132,7 +144,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
hide_favorites: true,
hide_followers: false,
hide_follows: false,
- relationship: %{}
+ relationship: %{},
+ skip_thread_containment: false
}
}
@@ -214,6 +227,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
pleroma: %{}
},
pleroma: %{
+ background_image: nil,
confirmation_pending: false,
tags: [],
is_admin: false,
@@ -233,10 +247,32 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
domain_blocking: false,
showing_reblogs: true,
endorsed: false
- }
+ },
+ skip_thread_containment: false
}
}
assert expected == AccountView.render("account.json", %{user: user, for: other_user})
end
+
+ test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
+ user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}})
+
+ result =
+ AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
+
+ assert result.pleroma.settings_store == %{:fe => "test"}
+
+ result = AccountView.render("account.json", %{user: user, with_pleroma_settings: true})
+ assert result.pleroma[:settings_store] == nil
+
+ result = AccountView.render("account.json", %{user: user, for: user})
+ assert result.pleroma[:settings_store] == nil
+ end
+
+ test "sanitizes display names" do
+ user = insert(:user, name: "<marquee> username </marquee>")
+ result = AccountView.render("account.json", %{user: user})
+ refute result.display_name == "<marquee> username </marquee>"
+ end
end
diff --git a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs
new file mode 100644
index 000000000..71d0c8af8
--- /dev/null
+++ b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs
@@ -0,0 +1,304 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ use Pleroma.Web.ConnCase
+
+ import Pleroma.Factory
+
+ describe "updating credentials" do
+ test "sets user settings in a generic way", %{conn: conn} do
+ user = insert(:user)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "pleroma_settings_store" => %{
+ pleroma_fe: %{
+ theme: "bla"
+ }
+ }
+ })
+
+ assert user = json_response(res_conn, 200)
+ assert user["pleroma"]["settings_store"] == %{"pleroma_fe" => %{"theme" => "bla"}}
+
+ user = Repo.get(User, user["id"])
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "pleroma_settings_store" => %{
+ masto_fe: %{
+ theme: "bla"
+ }
+ }
+ })
+
+ assert user = json_response(res_conn, 200)
+
+ assert user["pleroma"]["settings_store"] ==
+ %{
+ "pleroma_fe" => %{"theme" => "bla"},
+ "masto_fe" => %{"theme" => "bla"}
+ }
+
+ user = Repo.get(User, user["id"])
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "pleroma_settings_store" => %{
+ masto_fe: %{
+ theme: "blub"
+ }
+ }
+ })
+
+ assert user = json_response(res_conn, 200)
+
+ assert user["pleroma"]["settings_store"] ==
+ %{
+ "pleroma_fe" => %{"theme" => "bla"},
+ "masto_fe" => %{"theme" => "blub"}
+ }
+ end
+
+ test "updates the user's bio", %{conn: conn} do
+ user = insert(:user)
+ user2 = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "note" => "I drink #cofe with @#{user2.nickname}"
+ })
+
+ assert user = json_response(conn, 200)
+
+ assert user["note"] ==
+ ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag">#cofe</a> with <span class="h-card"><a data-user=") <>
+ user2.id <>
+ ~s(" class="u-url mention" href=") <>
+ user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
+ end
+
+ test "updates the user's locking status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
+
+ assert user = json_response(conn, 200)
+ assert user["locked"] == true
+ end
+
+ test "updates the user's default scope", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
+
+ assert user = json_response(conn, 200)
+ assert user["source"]["privacy"] == "cofe"
+ end
+
+ test "updates the user's hide_followers status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
+
+ assert user = json_response(conn, 200)
+ assert user["pleroma"]["hide_followers"] == true
+ end
+
+ test "updates the user's skip_thread_containment option", %{conn: conn} do
+ user = insert(:user)
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{skip_thread_containment: "true"})
+ |> json_response(200)
+
+ assert response["pleroma"]["skip_thread_containment"] == true
+ assert refresh_record(user).info.skip_thread_containment
+ end
+
+ test "updates the user's hide_follows status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
+
+ assert user = json_response(conn, 200)
+ assert user["pleroma"]["hide_follows"] == true
+ end
+
+ test "updates the user's hide_favorites status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
+
+ assert user = json_response(conn, 200)
+ assert user["pleroma"]["hide_favorites"] == true
+ end
+
+ test "updates the user's show_role status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
+
+ assert user = json_response(conn, 200)
+ assert user["source"]["pleroma"]["show_role"] == false
+ end
+
+ test "updates the user's no_rich_text status", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
+
+ assert user = json_response(conn, 200)
+ assert user["source"]["pleroma"]["no_rich_text"] == true
+ end
+
+ test "updates the user's name", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
+
+ assert user = json_response(conn, 200)
+ assert user["display_name"] == "markorepairs"
+ end
+
+ test "updates the user's avatar", %{conn: conn} do
+ user = insert(:user)
+
+ new_avatar = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
+
+ assert user_response = json_response(conn, 200)
+ assert user_response["avatar"] != User.avatar_url(user)
+ end
+
+ test "updates the user's banner", %{conn: conn} do
+ user = insert(:user)
+
+ new_header = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
+
+ assert user_response = json_response(conn, 200)
+ assert user_response["header"] != User.banner_url(user)
+ end
+
+ test "updates the user's background", %{conn: conn} do
+ user = insert(:user)
+
+ new_header = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "pleroma_background_image" => new_header
+ })
+
+ assert user_response = json_response(conn, 200)
+ assert user_response["pleroma"]["background_image"]
+ end
+
+ test "requires 'write' permission", %{conn: conn} do
+ token1 = insert(:oauth_token, scopes: ["read"])
+ token2 = insert(:oauth_token, scopes: ["write", "follow"])
+
+ for token <- [token1, token2] do
+ conn =
+ conn
+ |> put_req_header("authorization", "Bearer #{token.token}")
+ |> patch("/api/v1/accounts/update_credentials", %{})
+
+ if token == token1 do
+ assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
+ else
+ assert json_response(conn, 200)
+ end
+ end
+ end
+
+ test "updates profile emojos", %{conn: conn} do
+ user = insert(:user)
+
+ note = "*sips :blank:*"
+ name = "I am :firefox:"
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{
+ "note" => note,
+ "display_name" => name
+ })
+
+ assert json_response(conn, 200)
+
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}")
+
+ assert user = json_response(conn, 200)
+
+ assert user["note"] == note
+ assert user["display_name"] == name
+ assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
+ end
+ end
+end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 1d9f5a816..af24fddc1 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -24,6 +24,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
import ExUnit.CaptureLog
import Tesla.Mock
+ @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
+
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
@@ -33,7 +35,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user = insert(:user)
following = insert(:user)
- {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
+ {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
conn =
conn
@@ -56,7 +58,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
following = insert(:user)
capture_log(fn ->
- {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
+ {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
{:ok, [_activity]} =
OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
@@ -94,150 +96,283 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> json_response(403) == %{"error" => "This resource requires authentication."}
end
- test "posting a status", %{conn: conn} do
- user = insert(:user)
+ describe "posting statuses" do
+ setup do
+ user = insert(:user)
- idempotency_key = "Pikachu rocks!"
+ conn =
+ build_conn()
+ |> assign(:user, user)
- conn_one =
- conn
- |> assign(:user, user)
- |> put_req_header("idempotency-key", idempotency_key)
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
+ [conn: conn]
+ end
- {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
- # Six hours
- assert ttl > :timer.seconds(6 * 60 * 60 - 1)
+ test "posting a status", %{conn: conn} do
+ idempotency_key = "Pikachu rocks!"
- assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
- json_response(conn_one, 200)
+ conn_one =
+ conn
+ |> put_req_header("idempotency-key", idempotency_key)
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
- assert Activity.get_by_id(id)
+ {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
+ # Six hours
+ assert ttl > :timer.seconds(6 * 60 * 60 - 1)
- conn_two =
- conn
- |> assign(:user, user)
- |> put_req_header("idempotency-key", idempotency_key)
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
+ assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
+ json_response(conn_one, 200)
- assert %{"id" => second_id} = json_response(conn_two, 200)
+ assert Activity.get_by_id(id)
- assert id == second_id
+ conn_two =
+ conn
+ |> put_req_header("idempotency-key", idempotency_key)
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
- conn_three =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
+ assert %{"id" => second_id} = json_response(conn_two, 200)
+ assert id == second_id
- assert %{"id" => third_id} = json_response(conn_three, 200)
+ conn_three =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
- refute id == third_id
- end
+ assert %{"id" => third_id} = json_response(conn_three, 200)
+ refute id == third_id
+ end
- test "posting a sensitive status", %{conn: conn} do
- user = insert(:user)
+ test "replying to a status", %{conn: conn} do
+ user = insert(:user)
+ {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
- assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
- assert Activity.get_by_id(id)
- end
+ assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- test "posting a fake status", %{conn: conn} do
- user = insert(:user)
+ activity = Activity.get_by_id(id)
- real_conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" =>
- "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
- })
+ assert activity.data["context"] == replied_to.data["context"]
+ assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+ end
- real_status = json_response(real_conn, 200)
+ test "replying to a direct message with visibility other than direct", %{conn: conn} do
+ user = insert(:user)
+ {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
- assert real_status
- assert Object.get_by_ap_id(real_status["uri"])
+ Enum.each(["public", "private", "unlisted"], fn visibility ->
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "@#{user.nickname} hey",
+ "in_reply_to_id" => replied_to.id,
+ "visibility" => visibility
+ })
- real_status =
- real_status
- |> Map.put("id", nil)
- |> Map.put("url", nil)
- |> Map.put("uri", nil)
- |> Map.put("created_at", nil)
- |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+ assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
+ end)
+ end
- fake_conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" =>
- "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
- "preview" => true
- })
+ test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
- fake_status = json_response(fake_conn, 200)
+ assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ end
- assert fake_status
- refute Object.get_by_ap_id(fake_status["uri"])
+ test "posting a sensitive status", %{conn: conn} do
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
- fake_status =
- fake_status
- |> Map.put("id", nil)
- |> Map.put("url", nil)
- |> Map.put("uri", nil)
- |> Map.put("created_at", nil)
- |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+ assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ end
- assert real_status == fake_status
- end
+ test "posting a fake status", %{conn: conn} do
+ real_conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
+ })
- test "posting a status with OGP link preview", %{conn: conn} do
- Pleroma.Config.put([:rich_media, :enabled], true)
- user = insert(:user)
+ real_status = json_response(real_conn, 200)
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "http://example.com/ogp"
- })
+ assert real_status
+ assert Object.get_by_ap_id(real_status["uri"])
+
+ real_status =
+ real_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ fake_conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
+ "preview" => true
+ })
- assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
- assert Activity.get_by_id(id)
- Pleroma.Config.put([:rich_media, :enabled], false)
+ fake_status = json_response(fake_conn, 200)
+
+ assert fake_status
+ refute Object.get_by_ap_id(fake_status["uri"])
+
+ fake_status =
+ fake_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ assert real_status == fake_status
+ end
+
+ test "posting a status with OGP link preview", %{conn: conn} do
+ Pleroma.Config.put([:rich_media, :enabled], true)
+
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "https://example.com/ogp"
+ })
+
+ assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ Pleroma.Config.put([:rich_media, :enabled], false)
+ end
+
+ test "posting a direct status", %{conn: conn} do
+ user2 = insert(:user)
+ content = "direct cofe @#{user2.nickname}"
+
+ conn =
+ conn
+ |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
+
+ assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
+ assert activity = Activity.get_by_id(id)
+ assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
+ assert activity.data["to"] == [user2.ap_id]
+ assert activity.data["cc"] == []
+ end
end
- test "posting a direct status", %{conn: conn} do
- user1 = insert(:user)
- user2 = insert(:user)
- content = "direct cofe @#{user2.nickname}"
+ describe "posting polls" do
+ test "posting a poll", %{conn: conn} do
+ user = insert(:user)
+ time = NaiveDateTime.utc_now()
- conn =
- conn
- |> assign(:user, user1)
- |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "Who is the #bestgrill?",
+ "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
+ })
- assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
- assert activity = Activity.get_by_id(id)
- assert activity.recipients == [user2.ap_id, user1.ap_id]
- assert activity.data["to"] == [user2.ap_id]
- assert activity.data["cc"] == []
+ response = json_response(conn, 200)
+
+ assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
+ title in ["Rei", "Asuka", "Misato"]
+ end)
+
+ assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
+ refute response["poll"]["expred"]
+ end
+
+ test "option limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Pleroma.Config.get([:instance, :poll_limits, :max_options])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "desu~",
+ "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Poll can't contain more than #{limit} options"
+ end
+
+ test "option character limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "...",
+ "poll" => %{
+ "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
+ "expires_in" => 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Poll options cannot be longer than #{limit} characters each"
+ end
+
+ test "minimal date limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "imagine arbitrary limits",
+ "poll" => %{
+ "options" => ["this post was made by pleroma gang"],
+ "expires_in" => limit - 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Expiration date is too soon"
+ end
+
+ test "maximum date limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "imagine arbitrary limits",
+ "poll" => %{
+ "options" => ["this post was made by pleroma gang"],
+ "expires_in" => limit + 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Expiration date is too far in the future"
+ end
end
test "direct timeline", %{conn: conn} do
@@ -317,12 +452,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
test "Conversations", %{conn: conn} do
user_one = insert(:user)
user_two = insert(:user)
+ user_three = insert(:user)
{:ok, user_two} = User.follow(user_two, user_one)
{:ok, direct} =
CommonAPI.post(user_one, %{
- "status" => "Hi @#{user_two.nickname}!",
+ "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
"visibility" => "direct"
})
@@ -348,7 +484,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
}
] = response
+ account_ids = Enum.map(res_accounts, & &1["id"])
assert length(res_accounts) == 2
+ assert user_two.id in account_ids
+ assert user_three.id in account_ids
assert is_binary(res_id)
assert unread == true
assert res_last_status["id"] == direct.id
@@ -400,81 +539,146 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert status["id"] == direct.id
end
- test "replying to a status", %{conn: conn} do
+ test "verify_credentials", %{conn: conn} do
user = insert(:user)
- {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/verify_credentials")
+
+ response = json_response(conn, 200)
+
+ assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
+ assert response["pleroma"]["chat_token"]
+ assert id == to_string(user.id)
+ end
+
+ test "verify_credentials default scope unlisted", %{conn: conn} do
+ user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
conn =
conn
|> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+ |> get("/api/v1/accounts/verify_credentials")
- assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+ assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
+ assert id == to_string(user.id)
+ end
- activity = Activity.get_by_id(id)
+ test "apps/verify_credentials", %{conn: conn} do
+ token = insert(:oauth_token)
- assert activity.data["context"] == replied_to.data["context"]
- assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+ conn =
+ conn
+ |> assign(:user, token.user)
+ |> assign(:token, token)
+ |> get("/api/v1/apps/verify_credentials")
+
+ app = Repo.preload(token, :app).app
+
+ expected = %{
+ "name" => app.client_name,
+ "website" => app.website,
+ "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+ }
+
+ assert expected == json_response(conn, 200)
end
- test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
+ test "user avatar can be set", %{conn: conn} do
user = insert(:user)
+ avatar_image = File.read!("test/fixtures/avatar_data_uri")
conn =
conn
|> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
+ |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
- assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+ user = refresh_record(user)
- activity = Activity.get_by_id(id)
+ assert %{
+ "name" => _,
+ "type" => _,
+ "url" => [
+ %{
+ "href" => _,
+ "mediaType" => _,
+ "type" => _
+ }
+ ]
+ } = user.avatar
- assert activity
+ assert %{"url" => _} = json_response(conn, 200)
end
- test "verify_credentials", %{conn: conn} do
+ test "user avatar can be reset", %{conn: conn} do
user = insert(:user)
conn =
conn
|> assign(:user, user)
- |> get("/api/v1/accounts/verify_credentials")
+ |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
- assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
- assert id == to_string(user.id)
+ user = User.get_cached_by_id(user.id)
+
+ assert user.avatar == nil
+
+ assert %{"url" => nil} = json_response(conn, 200)
end
- test "verify_credentials default scope unlisted", %{conn: conn} do
- user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
+ test "can set profile banner", %{conn: conn} do
+ user = insert(:user)
conn =
conn
|> assign(:user, user)
- |> get("/api/v1/accounts/verify_credentials")
+ |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
- assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
- assert id == to_string(user.id)
+ user = refresh_record(user)
+ assert user.info.banner["type"] == "Image"
+
+ assert %{"url" => _} = json_response(conn, 200)
end
- test "apps/verify_credentials", %{conn: conn} do
- token = insert(:oauth_token)
+ test "can reset profile banner", %{conn: conn} do
+ user = insert(:user)
conn =
conn
- |> assign(:user, token.user)
- |> assign(:token, token)
- |> get("/api/v1/apps/verify_credentials")
+ |> assign(:user, user)
+ |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
- app = Repo.preload(token, :app).app
+ user = refresh_record(user)
+ assert user.info.banner == %{}
- expected = %{
- "name" => app.client_name,
- "website" => app.website,
- "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
- }
+ assert %{"url" => nil} = json_response(conn, 200)
+ end
- assert expected == json_response(conn, 200)
+ test "background image can be set", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
+
+ user = refresh_record(user)
+ assert user.info.background["type"] == "Image"
+ assert %{"url" => _} = json_response(conn, 200)
+ end
+
+ test "background image can be reset", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
+
+ user = refresh_record(user)
+ assert user.info.background == %{}
+ assert %{"url" => nil} = json_response(conn, 200)
end
test "creates an oauth app", %{conn: conn} do
@@ -800,8 +1004,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
test "list timeline", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
- {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
- {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
+ {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
+ {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
{:ok, list} = Pleroma.List.create("name", user)
{:ok, list} = Pleroma.List.follow(list, other_user)
@@ -818,10 +1022,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
+ {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
{:ok, _activity_two} =
- TwitterAPI.create_status(other_user, %{
+ CommonAPI.post(other_user, %{
"status" => "Marisa is cute.",
"visibility" => "private"
})
@@ -845,8 +1049,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} =
- TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
{:ok, [_notification]} = Notification.create_notifications(activity)
@@ -868,8 +1071,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} =
- TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
@@ -891,8 +1093,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} =
- TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
@@ -908,8 +1109,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} =
- TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
{:ok, [_notification]} = Notification.create_notifications(activity)
@@ -1070,6 +1270,71 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
result = json_response(conn_res, 200)
assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
end
+
+ test "doesn't see notifications after muting user with notifications", %{conn: conn} do
+ user = insert(:user)
+ user2 = insert(:user)
+
+ {:ok, _, _, _} = CommonAPI.follow(user, user2)
+ {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
+
+ conn = assign(conn, :user, user)
+
+ conn = get(conn, "/api/v1/notifications")
+
+ assert length(json_response(conn, 200)) == 1
+
+ {:ok, user} = User.mute(user, user2)
+
+ conn = assign(build_conn(), :user, user)
+ conn = get(conn, "/api/v1/notifications")
+
+ assert json_response(conn, 200) == []
+ end
+
+ test "see notifications after muting user without notifications", %{conn: conn} do
+ user = insert(:user)
+ user2 = insert(:user)
+
+ {:ok, _, _, _} = CommonAPI.follow(user, user2)
+ {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
+
+ conn = assign(conn, :user, user)
+
+ conn = get(conn, "/api/v1/notifications")
+
+ assert length(json_response(conn, 200)) == 1
+
+ {:ok, user} = User.mute(user, user2, false)
+
+ conn = assign(build_conn(), :user, user)
+ conn = get(conn, "/api/v1/notifications")
+
+ assert length(json_response(conn, 200)) == 1
+ end
+
+ test "see notifications after muting user with notifications and with_muted parameter", %{
+ conn: conn
+ } do
+ user = insert(:user)
+ user2 = insert(:user)
+
+ {:ok, _, _, _} = CommonAPI.follow(user, user2)
+ {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
+
+ conn = assign(conn, :user, user)
+
+ conn = get(conn, "/api/v1/notifications")
+
+ assert length(json_response(conn, 200)) == 1
+
+ {:ok, user} = User.mute(user, user2)
+
+ conn = assign(build_conn(), :user, user)
+ conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
+
+ assert length(json_response(conn, 200)) == 1
+ end
end
describe "reblogging" do
@@ -1126,6 +1391,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert to_string(activity.id) == id
end
+
+ test "returns 400 error when activity is not exist", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/foo/reblog")
+
+ assert json_response(conn, 400) == %{"error" => "Could not repeat"}
+ end
end
describe "unreblogging" do
@@ -1144,6 +1420,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert to_string(activity.id) == id
end
+
+ test "returns 400 error when activity is not exist", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/foo/unreblog")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
+ end
end
describe "favoriting" do
@@ -1162,16 +1449,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert to_string(activity.id) == id
end
- test "returns 500 for a wrong id", %{conn: conn} do
+ test "returns 400 error for a wrong id", %{conn: conn} do
user = insert(:user)
- resp =
+ conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses/1/favourite")
- |> json_response(500)
- assert resp == "Something went wrong"
+ assert json_response(conn, 400) == %{"error" => "Could not favorite"}
end
end
@@ -1192,6 +1478,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert to_string(activity.id) == id
end
+
+ test "returns 400 error for a wrong id", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/unfavourite")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
+ end
end
describe "user timelines" do
@@ -1262,10 +1559,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
media =
TwitterAPI.upload(file, user, "json")
- |> Poison.decode!()
+ |> Jason.decode!()
{:ok, image_post} =
- TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
+ CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
conn =
conn
@@ -1301,6 +1598,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(post.id)
end
+
+ test "filters user's statuses by a hashtag", %{conn: conn} do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
+ {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
+
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
+
+ assert [%{"id" => id}] = json_response(conn, 200)
+ assert id == to_string(post.id)
+ end
end
describe "user relationships" do
@@ -1320,6 +1630,82 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
end
+ describe "media upload" do
+ setup do
+ upload_config = Pleroma.Config.get([Pleroma.Upload])
+ proxy_config = Pleroma.Config.get([:media_proxy])
+
+ on_exit(fn ->
+ Pleroma.Config.put([Pleroma.Upload], upload_config)
+ Pleroma.Config.put([:media_proxy], proxy_config)
+ end)
+
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ image = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ [conn: conn, image: image]
+ end
+
+ test "returns uploaded image", %{conn: conn, image: image} do
+ desc = "Description of the image"
+
+ media =
+ conn
+ |> post("/api/v1/media", %{"file" => image, "description" => desc})
+ |> json_response(:ok)
+
+ assert media["type"] == "image"
+ assert media["description"] == desc
+ assert media["id"]
+
+ object = Repo.get(Object, media["id"])
+ assert object.data["actor"] == User.ap_id(conn.assigns[:user])
+ end
+
+ test "returns proxied url when media proxy is enabled", %{conn: conn, image: image} do
+ Pleroma.Config.put([Pleroma.Upload, :base_url], "https://media.pleroma.social")
+
+ proxy_url = "https://cache.pleroma.social"
+ Pleroma.Config.put([:media_proxy, :enabled], true)
+ Pleroma.Config.put([:media_proxy, :base_url], proxy_url)
+
+ media =
+ conn
+ |> post("/api/v1/media", %{"file" => image})
+ |> json_response(:ok)
+
+ assert String.starts_with?(media["url"], proxy_url)
+ end
+
+ test "returns media url when proxy is enabled but media url is whitelisted", %{
+ conn: conn,
+ image: image
+ } do
+ media_url = "https://media.pleroma.social"
+ Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
+
+ Pleroma.Config.put([:media_proxy, :enabled], true)
+ Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social")
+ Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"])
+
+ media =
+ conn
+ |> post("/api/v1/media", %{"file" => image})
+ |> json_response(:ok)
+
+ assert String.starts_with?(media["url"], media_url)
+ end
+ end
+
describe "locked accounts" do
test "/api/v1/follow_requests works" do
user = insert(:user, %{info: %User.Info{locked: true}})
@@ -1429,32 +1815,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert id == user.id
end
- test "media upload", %{conn: conn} do
- file = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "an_image.jpg"
- }
-
- desc = "Description of the image"
-
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/media", %{"file" => file, "description" => desc})
-
- assert media = json_response(conn, 200)
-
- assert media["type"] == "image"
- assert media["description"] == desc
- assert media["id"]
-
- object = Repo.get(Object, media["id"])
- assert object.data["actor"] == User.ap_id(user)
- end
-
test "mascot upload", %{conn: conn} do
user = insert(:user)
@@ -1525,7 +1885,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
following = insert(:user)
capture_log(fn ->
- {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
+ {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
{:ok, [_activity]} =
OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
@@ -1838,25 +2198,52 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"error" => "Record not found"} = json_response(conn_res, 404)
end
- test "muting / unmuting a user", %{conn: conn} do
- user = insert(:user)
- other_user = insert(:user)
+ describe "mute/unmute" do
+ test "with notifications", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/mute")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/mute")
- assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
+ response = json_response(conn, 200)
- user = User.get_cached_by_id(user.id)
+ assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
+ user = User.get_cached_by_id(user.id)
- conn =
- build_conn()
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/unmute")
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/unmute")
+
+ response = json_response(conn, 200)
+ assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
+ end
- assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
+ test "without notifications", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
+
+ response = json_response(conn, 200)
+
+ assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
+ user = User.get_cached_by_id(user.id)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/unmute")
+
+ response = json_response(conn, 200)
+ assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
+ end
end
test "subscribing / unsubscribing to a user", %{conn: conn} do
@@ -1983,104 +2370,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end)
end
- test "account search", %{conn: conn} do
- user = insert(:user)
- user_two = insert(:user, %{nickname: "shp@shitposter.club"})
- user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
-
- results =
- conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/search", %{"q" => "shp"})
- |> json_response(200)
-
- result_ids = for result <- results, do: result["acct"]
-
- assert user_two.nickname in result_ids
- assert user_three.nickname in result_ids
-
- results =
- conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/search", %{"q" => "2hu"})
- |> json_response(200)
-
- result_ids = for result <- results, do: result["acct"]
-
- assert user_three.nickname in result_ids
- end
-
- test "search", %{conn: conn} do
- user = insert(:user)
- user_two = insert(:user, %{nickname: "shp@shitposter.club"})
- user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
-
- {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
-
- {:ok, _activity} =
- CommonAPI.post(user, %{
- "status" => "This is about 2hu, but private",
- "visibility" => "private"
- })
-
- {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
-
- conn =
- conn
- |> get("/api/v1/search", %{"q" => "2hu"})
-
- assert results = json_response(conn, 200)
-
- [account | _] = results["accounts"]
- assert account["id"] == to_string(user_three.id)
-
- assert results["hashtags"] == []
-
- [status] = results["statuses"]
- assert status["id"] == to_string(activity.id)
- end
-
- test "search fetches remote statuses", %{conn: conn} do
- capture_log(fn ->
- conn =
- conn
- |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
-
- assert results = json_response(conn, 200)
-
- [status] = results["statuses"]
- assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
- end)
- end
-
- test "search doesn't show statuses that it shouldn't", %{conn: conn} do
- {:ok, activity} =
- CommonAPI.post(insert(:user), %{
- "status" => "This is about 2hu, but private",
- "visibility" => "private"
- })
-
- capture_log(fn ->
- conn =
- conn
- |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
-
- assert results = json_response(conn, 200)
-
- [] = results["statuses"]
- end)
- end
-
- test "search fetches remote accounts", %{conn: conn} do
- conn =
- conn
- |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
-
- assert results = json_response(conn, 200)
- [account] = results["accounts"]
- assert account["acct"] == "shp@social.heldscal.la"
- end
-
test "returns the favorites of a user", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
@@ -2321,205 +2610,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
end
- describe "updating credentials" do
- test "updates the user's bio", %{conn: conn} do
- user = insert(:user)
- user2 = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{
- "note" => "I drink #cofe with @#{user2.nickname}"
- })
-
- assert user = json_response(conn, 200)
-
- assert user["note"] ==
- ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag">#cofe</a> with <span class="h-card"><a data-user=") <>
- user2.id <>
- ~s(" class="u-url mention" href=") <>
- user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
- end
-
- test "updates the user's locking status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
-
- assert user = json_response(conn, 200)
- assert user["locked"] == true
- end
-
- test "updates the user's default scope", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
-
- assert user = json_response(conn, 200)
- assert user["source"]["privacy"] == "cofe"
- end
-
- test "updates the user's hide_followers status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
-
- assert user = json_response(conn, 200)
- assert user["pleroma"]["hide_followers"] == true
- end
-
- test "updates the user's hide_follows status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
-
- assert user = json_response(conn, 200)
- assert user["pleroma"]["hide_follows"] == true
- end
-
- test "updates the user's hide_favorites status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
-
- assert user = json_response(conn, 200)
- assert user["pleroma"]["hide_favorites"] == true
- end
-
- test "updates the user's show_role status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
-
- assert user = json_response(conn, 200)
- assert user["source"]["pleroma"]["show_role"] == false
- end
-
- test "updates the user's no_rich_text status", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
-
- assert user = json_response(conn, 200)
- assert user["source"]["pleroma"]["no_rich_text"] == true
- end
-
- test "updates the user's name", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
-
- assert user = json_response(conn, 200)
- assert user["display_name"] == "markorepairs"
- end
-
- test "updates the user's avatar", %{conn: conn} do
- user = insert(:user)
-
- new_avatar = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "an_image.jpg"
- }
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
-
- assert user_response = json_response(conn, 200)
- assert user_response["avatar"] != User.avatar_url(user)
- end
-
- test "updates the user's banner", %{conn: conn} do
- user = insert(:user)
-
- new_header = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "an_image.jpg"
- }
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
-
- assert user_response = json_response(conn, 200)
- assert user_response["header"] != User.banner_url(user)
- end
-
- test "requires 'write' permission", %{conn: conn} do
- token1 = insert(:oauth_token, scopes: ["read"])
- token2 = insert(:oauth_token, scopes: ["write", "follow"])
-
- for token <- [token1, token2] do
- conn =
- conn
- |> put_req_header("authorization", "Bearer #{token.token}")
- |> patch("/api/v1/accounts/update_credentials", %{})
-
- if token == token1 do
- assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
- else
- assert json_response(conn, 200)
- end
- end
- end
-
- test "updates profile emojos", %{conn: conn} do
- user = insert(:user)
-
- note = "*sips :blank:*"
- name = "I am :firefox:"
-
- conn =
- conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{
- "note" => note,
- "display_name" => name
- })
-
- assert json_response(conn, 200)
-
- conn =
- conn
- |> get("/api/v1/accounts/#{user.id}")
-
- assert user = json_response(conn, 200)
-
- assert user["note"] == note
- assert user["display_name"] == name
- assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
- end
- end
-
test "get instance information", %{conn: conn} do
conn = get(conn, "/api/v1/instance")
assert result = json_response(conn, 200)
@@ -2538,7 +2628,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
"stats" => _,
"thumbnail" => _,
"languages" => _,
- "registrations" => _
+ "registrations" => _,
+ "poll_limits" => _
} = result
assert email == from_config_email
@@ -2553,7 +2644,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
insert(:user, %{local: false, nickname: "u@peer1.com"})
insert(:user, %{local: false, nickname: "u@peer2.com"})
- {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
+ {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
# Stats should count users with missing or nil `info.deactivated` value
user = User.get_cached_by_id(user.id)
@@ -2646,6 +2737,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> json_response(200)
end
+ test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
+ {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{dm.id}/pin")
+
+ assert json_response(conn, 400) == %{"error" => "Could not pin"}
+ end
+
test "unpin status", %{conn: conn, user: user, activity: activity} do
{:ok, _} = CommonAPI.pin(activity.id, user)
@@ -2665,6 +2767,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> json_response(200)
end
+ test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/unpin")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unpin"}
+ end
+
test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
{:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
@@ -2684,37 +2795,54 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> post("/api/v1/statuses/#{activity_two.id}/pin")
|> json_response(400)
end
+ end
- test "Status rich-media Card", %{conn: conn, user: user} do
+ describe "cards" do
+ setup do
Pleroma.Config.put([:rich_media, :enabled], true)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
+
+ on_exit(fn ->
+ Pleroma.Config.put([:rich_media, :enabled], false)
+ end)
+
+ user = insert(:user)
+ %{user: user}
+ end
+
+ test "returns rich-media card", %{conn: conn, user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
+
+ card_data = %{
+ "image" => "http://ia.media-imdb.com/images/rock.jpg",
+ "provider_name" => "www.imdb.com",
+ "provider_url" => "http://www.imdb.com",
+ "title" => "The Rock",
+ "type" => "link",
+ "url" => "http://www.imdb.com/title/tt0117500/",
+ "description" =>
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
+ "pleroma" => %{
+ "opengraph" => %{
+ "image" => "http://ia.media-imdb.com/images/rock.jpg",
+ "title" => "The Rock",
+ "type" => "video.movie",
+ "url" => "http://www.imdb.com/title/tt0117500/",
+ "description" =>
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
+ }
+ }
+ }
response =
conn
|> get("/api/v1/statuses/#{activity.id}/card")
|> json_response(200)
- assert response == %{
- "image" => "http://ia.media-imdb.com/images/rock.jpg",
- "provider_name" => "www.imdb.com",
- "provider_url" => "http://www.imdb.com",
- "title" => "The Rock",
- "type" => "link",
- "url" => "http://www.imdb.com/title/tt0117500/",
- "description" => nil,
- "pleroma" => %{
- "opengraph" => %{
- "image" => "http://ia.media-imdb.com/images/rock.jpg",
- "title" => "The Rock",
- "type" => "video.movie",
- "url" => "http://www.imdb.com/title/tt0117500/"
- }
- }
- }
+ assert response == card_data
# works with private posts
{:ok, activity} =
- CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
+ CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
response_two =
conn
@@ -2722,9 +2850,34 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> get("/api/v1/statuses/#{activity.id}/card")
|> json_response(200)
- assert response_two == response
+ assert response_two == card_data
+ end
- Pleroma.Config.put([:rich_media, :enabled], false)
+ test "replaces missing description with an empty string", %{conn: conn, user: user} do
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/card")
+ |> json_response(:ok)
+
+ assert response == %{
+ "type" => "link",
+ "title" => "Pleroma",
+ "description" => "",
+ "image" => nil,
+ "provider_name" => "pleroma.social",
+ "provider_url" => "https://pleroma.social",
+ "url" => "https://pleroma.social/",
+ "pleroma" => %{
+ "opengraph" => %{
+ "title" => "Pleroma",
+ "type" => "website",
+ "url" => "https://pleroma.social/"
+ }
+ }
+ }
end
end
@@ -2797,6 +2950,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> json_response(200)
end
+ test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.add_mute(user, activity)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/mute")
+
+ assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
+ end
+
test "unmute conversation", %{conn: conn, user: user, activity: activity} do
{:ok, _} = CommonAPI.add_mute(user, activity)
@@ -2811,31 +2975,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
end
- test "flavours switching (Pleroma Extension)", %{conn: conn} do
- user = insert(:user)
-
- get_old_flavour =
- conn
- |> assign(:user, user)
- |> get("/api/v1/pleroma/flavour")
-
- assert "glitch" == json_response(get_old_flavour, 200)
-
- set_flavour =
- conn
- |> assign(:user, user)
- |> post("/api/v1/pleroma/flavour/vanilla")
-
- assert "vanilla" == json_response(set_flavour, 200)
-
- get_new_flavour =
- conn
- |> assign(:user, user)
- |> post("/api/v1/pleroma/flavour/vanilla")
-
- assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
- end
-
describe "reports" do
setup do
reporter = insert(:user)
@@ -2866,7 +3005,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> post("/api/v1/reports", %{
"account_id" => target_user.id,
"status_ids" => [activity.id],
- "comment" => "bad status!"
+ "comment" => "bad status!",
+ "forward" => "false"
})
|> json_response(200)
end
@@ -2899,6 +3039,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
|> json_response(400)
end
+
+ test "returns error when account is not exist", %{
+ conn: conn,
+ reporter: reporter,
+ activity: activity
+ } do
+ conn =
+ conn
+ |> assign(:user, reporter)
+ |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
+
+ assert json_response(conn, 400) == %{"error" => "Account not found"}
+ end
end
describe "link headers" do
@@ -2970,6 +3123,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert Map.has_key?(emoji, "static_url")
assert Map.has_key?(emoji, "tags")
assert is_list(emoji["tags"])
+ assert Map.has_key?(emoji, "category")
assert Map.has_key?(emoji, "url")
assert Map.has_key?(emoji, "visible_in_picker")
end
@@ -3257,7 +3411,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
user2 = insert(:user)
user3 = insert(:user)
- {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
+ {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
# Reply to status from another user
conn1 =
@@ -3298,24 +3452,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
describe "create account by app" do
- setup do
- enabled = Pleroma.Config.get([:app_account_creation, :enabled])
- max_requests = Pleroma.Config.get([:app_account_creation, :max_requests])
- interval = Pleroma.Config.get([:app_account_creation, :interval])
-
- Pleroma.Config.put([:app_account_creation, :enabled], true)
- Pleroma.Config.put([:app_account_creation, :max_requests], 5)
- Pleroma.Config.put([:app_account_creation, :interval], 1)
-
- on_exit(fn ->
- Pleroma.Config.put([:app_account_creation, :enabled], enabled)
- Pleroma.Config.put([:app_account_creation, :max_requests], max_requests)
- Pleroma.Config.put([:app_account_creation, :interval], interval)
- end)
-
- :ok
- end
-
test "Account registration via Application", %{conn: conn} do
conn =
conn
@@ -3418,7 +3554,257 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
agreement: true
})
- assert json_response(conn, 403) == %{"error" => "Rate limit exceeded."}
+ assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
+ end
+ end
+
+ describe "GET /api/v1/polls/:id" do
+ test "returns poll entity for object id", %{conn: conn} do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Pleroma does",
+ "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
+ })
+
+ object = Object.normalize(activity)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/polls/#{object.id}")
+
+ response = json_response(conn, 200)
+ id = object.id
+ assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
+ end
+
+ test "does not expose polls for private statuses", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Pleroma does",
+ "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
+ "visibility" => "private"
+ })
+
+ object = Object.normalize(activity)
+
+ conn =
+ conn
+ |> assign(:user, other_user)
+ |> get("/api/v1/polls/#{object.id}")
+
+ assert json_response(conn, 404)
+ end
+ end
+
+ describe "POST /api/v1/polls/:id/votes" do
+ test "votes are added to the poll", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "A very delicious sandwich",
+ "poll" => %{
+ "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
+ "expires_in" => 20,
+ "multiple" => true
+ }
+ })
+
+ object = Object.normalize(activity)
+
+ conn =
+ conn
+ |> assign(:user, other_user)
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
+
+ assert json_response(conn, 200)
+ object = Object.get_by_id(object.id)
+
+ assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
+ total_items == 1
+ end)
+ end
+
+ test "author can't vote", %{conn: conn} do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Am I cute?",
+ "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
+ })
+
+ object = Object.normalize(activity)
+
+ assert conn
+ |> assign(:user, user)
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
+ |> json_response(422) == %{"error" => "Poll's author can't vote"}
+
+ object = Object.get_by_id(object.id)
+
+ refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
+ end
+
+ test "does not allow multiple choices on a single-choice question", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "The glass is",
+ "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
+ })
+
+ object = Object.normalize(activity)
+
+ assert conn
+ |> assign(:user, other_user)
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
+ |> json_response(422) == %{"error" => "Too many choices"}
+
+ object = Object.get_by_id(object.id)
+
+ refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
+ total_items == 1
+ end)
+ end
+
+ test "does not allow choice index to be greater than options count", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Am I cute?",
+ "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
+ })
+
+ object = Object.normalize(activity)
+
+ conn =
+ conn
+ |> assign(:user, other_user)
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
+
+ assert json_response(conn, 422) == %{"error" => "Invalid indices"}
+ end
+
+ test "returns 404 error when object is not exist", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
+
+ assert json_response(conn, 404) == %{"error" => "Record not found"}
+ end
+
+ test "returns 404 when poll is private and not available for user", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Am I cute?",
+ "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
+ "visibility" => "private"
+ })
+
+ object = Object.normalize(activity)
+
+ conn =
+ conn
+ |> assign(:user, other_user)
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
+
+ assert json_response(conn, 404) == %{"error" => "Record not found"}
+ end
+ end
+
+ describe "GET /api/v1/statuses/:id/favourited_by" do
+ setup do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ [conn: conn, activity: activity]
+ end
+
+ test "returns users who have favorited the status", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+
+ assert id == other_user.id
+ end
+
+ test "returns empty array when status has not been favorited yet", %{
+ conn: conn,
+ activity: activity
+ } do
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
+ end
+ end
+
+ describe "GET /api/v1/statuses/:id/reblogged_by" do
+ setup do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ [conn: conn, activity: activity]
+ end
+
+ test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+
+ assert id == other_user.id
+ end
+
+ test "returns empty array when status has not been reblogged yet", %{
+ conn: conn,
+ activity: activity
+ } do
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
end
end
end
diff --git a/test/web/mastodon_api/search_controller_test.exs b/test/web/mastodon_api/search_controller_test.exs
new file mode 100644
index 000000000..9f50c09f4
--- /dev/null
+++ b/test/web/mastodon_api/search_controller_test.exs
@@ -0,0 +1,267 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Object
+ alias Pleroma.Web
+ alias Pleroma.Web.CommonAPI
+ import Pleroma.Factory
+ import ExUnit.CaptureLog
+ import Tesla.Mock
+ import Mock
+
+ setup do
+ mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ describe ".search2" do
+ test "it returns empty result if user or status search return undefined error", %{conn: conn} do
+ with_mocks [
+ {Pleroma.User, [], [search: fn _q, _o -> raise "Oops" end]},
+ {Pleroma.Activity, [], [search: fn _u, _q, _o -> raise "Oops" end]}
+ ] do
+ conn = get(conn, "/api/v2/search", %{"q" => "2hu"})
+
+ assert results = json_response(conn, 200)
+
+ assert results["accounts"] == []
+ assert results["statuses"] == []
+ end
+ end
+
+ test "search", %{conn: conn} do
+ user = insert(:user)
+ user_two = insert(:user, %{nickname: "shp@shitposter.club"})
+ user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu private"})
+
+ {:ok, _activity} =
+ CommonAPI.post(user, %{
+ "status" => "This is about 2hu, but private",
+ "visibility" => "private"
+ })
+
+ {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
+
+ conn = get(conn, "/api/v2/search", %{"q" => "2hu #private"})
+
+ assert results = json_response(conn, 200)
+
+ [account | _] = results["accounts"]
+ assert account["id"] == to_string(user_three.id)
+
+ assert results["hashtags"] == [
+ %{"name" => "private", "url" => "#{Web.base_url()}/tag/private"}
+ ]
+
+ [status] = results["statuses"]
+ assert status["id"] == to_string(activity.id)
+ end
+ end
+
+ describe ".account_search" do
+ test "account search", %{conn: conn} do
+ user = insert(:user)
+ user_two = insert(:user, %{nickname: "shp@shitposter.club"})
+ user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ results =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/search", %{"q" => "shp"})
+ |> json_response(200)
+
+ result_ids = for result <- results, do: result["acct"]
+
+ assert user_two.nickname in result_ids
+ assert user_three.nickname in result_ids
+
+ results =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/search", %{"q" => "2hu"})
+ |> json_response(200)
+
+ result_ids = for result <- results, do: result["acct"]
+
+ assert user_three.nickname in result_ids
+ end
+ end
+
+ describe ".search" do
+ test "it returns empty result if user or status search return undefined error", %{conn: conn} do
+ with_mocks [
+ {Pleroma.User, [], [search: fn _q, _o -> raise "Oops" end]},
+ {Pleroma.Activity, [], [search: fn _u, _q, _o -> raise "Oops" end]}
+ ] do
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu"})
+
+ assert results = json_response(conn, 200)
+
+ assert results["accounts"] == []
+ assert results["statuses"] == []
+ end
+ end
+
+ test "search", %{conn: conn} do
+ user = insert(:user)
+ user_two = insert(:user, %{nickname: "shp@shitposter.club"})
+ user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+
+ {:ok, _activity} =
+ CommonAPI.post(user, %{
+ "status" => "This is about 2hu, but private",
+ "visibility" => "private"
+ })
+
+ {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
+
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu"})
+
+ assert results = json_response(conn, 200)
+
+ [account | _] = results["accounts"]
+ assert account["id"] == to_string(user_three.id)
+
+ assert results["hashtags"] == []
+
+ [status] = results["statuses"]
+ assert status["id"] == to_string(activity.id)
+ end
+
+ test "search fetches remote statuses", %{conn: conn} do
+ capture_log(fn ->
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
+
+ assert results = json_response(conn, 200)
+
+ [status] = results["statuses"]
+
+ assert status["uri"] ==
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ end)
+ end
+
+ test "search doesn't show statuses that it shouldn't", %{conn: conn} do
+ {:ok, activity} =
+ CommonAPI.post(insert(:user), %{
+ "status" => "This is about 2hu, but private",
+ "visibility" => "private"
+ })
+
+ capture_log(fn ->
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
+
+ assert results = json_response(conn, 200)
+
+ [] = results["statuses"]
+ end)
+ end
+
+ test "search fetches remote accounts", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
+
+ assert results = json_response(conn, 200)
+ [account] = results["accounts"]
+ assert account["acct"] == "shp@social.heldscal.la"
+ end
+
+ test "search doesn't fetch remote accounts if resolve is false", %{conn: conn} do
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "false"})
+
+ assert results = json_response(conn, 200)
+ assert [] == results["accounts"]
+ end
+
+ test "search with limit and offset", %{conn: conn} do
+ user = insert(:user)
+ _user_two = insert(:user, %{nickname: "shp@shitposter.club"})
+ _user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ {:ok, _activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+ {:ok, _activity2} = CommonAPI.post(user, %{"status" => "This is also about 2hu"})
+
+ result =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1})
+
+ assert results = json_response(result, 200)
+ assert [%{"id" => activity_id1}] = results["statuses"]
+ assert [_] = results["accounts"]
+
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "limit" => 1, "offset" => 1})
+ |> json_response(200)
+
+ assert [%{"id" => activity_id2}] = results["statuses"]
+ assert [] = results["accounts"]
+
+ assert activity_id1 != activity_id2
+ end
+
+ test "search returns results only for the given type", %{conn: conn} do
+ user = insert(:user)
+ _user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ {:ok, _activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+
+ assert %{"statuses" => [_activity], "accounts" => [], "hashtags" => []} =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "type" => "statuses"})
+ |> json_response(200)
+
+ assert %{"statuses" => [], "accounts" => [_user_two], "hashtags" => []} =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "type" => "accounts"})
+ |> json_response(200)
+ end
+
+ test "search uses account_id to filter statuses by the author", %{conn: conn} do
+ user = insert(:user, %{nickname: "shp@shitposter.club"})
+ user_two = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
+
+ {:ok, activity1} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
+ {:ok, activity2} = CommonAPI.post(user_two, %{"status" => "This is also about 2hu"})
+
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user.id})
+ |> json_response(200)
+
+ assert [%{"id" => activity_id1}] = results["statuses"]
+ assert activity_id1 == activity1.id
+ assert [_] = results["accounts"]
+
+ results =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu", "account_id" => user_two.id})
+ |> json_response(200)
+
+ assert [%{"id" => activity_id2}] = results["statuses"]
+ assert activity_id2 == activity2.id
+ end
+ end
+end
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index d7c800e83..995bd52c8 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
test "a note with null content" do
note = insert(:note_activity)
- note_object = Object.normalize(note.data["object"])
+ note_object = Object.normalize(note)
data =
note_object.data
@@ -73,26 +73,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
test "a note activity" do
note = insert(:note_activity)
+ object_data = Object.normalize(note).data
user = User.get_cached_by_ap_id(note.data["actor"])
- convo_id = Utils.context_to_conversation_id(note.data["object"]["context"])
+ convo_id = Utils.context_to_conversation_id(object_data["context"])
status = StatusView.render("status.json", %{activity: note})
created_at =
- (note.data["object"]["published"] || "")
+ (object_data["published"] || "")
|> String.replace(~r/\.\d+Z/, ".000Z")
expected = %{
id: to_string(note.id),
- uri: note.data["object"]["id"],
+ uri: object_data["id"],
url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),
account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
card: nil,
reblog: nil,
- content: HtmlSanitizeEx.basic_html(note.data["object"]["content"]),
+ content: HtmlSanitizeEx.basic_html(object_data["content"]),
created_at: created_at,
reblogs_count: 0,
replies_count: 0,
@@ -103,14 +104,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
muted: false,
pinned: false,
sensitive: false,
- spoiler_text: HtmlSanitizeEx.basic_html(note.data["object"]["summary"]),
+ poll: nil,
+ spoiler_text: HtmlSanitizeEx.basic_html(object_data["summary"]),
visibility: "public",
media_attachments: [],
mentions: [],
tags: [
%{
- name: "#{note.data["object"]["tag"]}",
- url: "/tag/#{note.data["object"]["tag"]}"
+ name: "#{object_data["tag"]}",
+ url: "/tag/#{object_data["tag"]}"
}
],
application: %{
@@ -130,8 +132,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
local: true,
conversation_id: convo_id,
in_reply_to_account_acct: nil,
- content: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["content"])},
- spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["summary"])}
+ content: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["content"])},
+ spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])}
}
}
@@ -201,10 +203,71 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("status.json", %{activity: activity})
- actor = User.get_cached_by_ap_id(activity.actor)
-
assert status.mentions ==
- Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
+ Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end)
+ end
+
+ test "create mentions from the 'to' field" do
+ %User{ap_id: recipient_ap_id} = insert(:user)
+ cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
+
+ object =
+ insert(:note, %{
+ data: %{
+ "to" => [recipient_ap_id],
+ "cc" => cc
+ }
+ })
+
+ activity =
+ insert(:note_activity, %{
+ note: object,
+ recipients: [recipient_ap_id | cc]
+ })
+
+ assert length(activity.recipients) == 3
+
+ %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity})
+
+ assert length(mentions) == 1
+ assert mention.url == recipient_ap_id
+ end
+
+ test "create mentions from the 'tag' field" do
+ recipient = insert(:user)
+ cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
+
+ object =
+ insert(:note, %{
+ data: %{
+ "cc" => cc,
+ "tag" => [
+ %{
+ "href" => recipient.ap_id,
+ "name" => recipient.nickname,
+ "type" => "Mention"
+ },
+ %{
+ "href" => "https://example.com/search?tag=test",
+ "name" => "#test",
+ "type" => "Hashtag"
+ }
+ ]
+ }
+ })
+
+ activity =
+ insert(:note_activity, %{
+ note: object,
+ recipients: [recipient.ap_id | cc]
+ })
+
+ assert length(activity.recipients) == 3
+
+ %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity})
+
+ assert length(mentions) == 1
+ assert mention.url == recipient.ap_id
end
test "attachments" do
@@ -341,4 +404,154 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
StatusView.render("card.json", %{page_url: page_url, rich_media: card})
end
end
+
+ describe "poll view" do
+ test "renders a poll" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Is Tenshi eating a corndog cute?",
+ "poll" => %{
+ "options" => ["absolutely!", "sure", "yes", "why are you even asking?"],
+ "expires_in" => 20
+ }
+ })
+
+ object = Object.normalize(activity)
+
+ expected = %{
+ emojis: [],
+ expired: false,
+ id: object.id,
+ multiple: false,
+ options: [
+ %{title: "absolutely!", votes_count: 0},
+ %{title: "sure", votes_count: 0},
+ %{title: "yes", votes_count: 0},
+ %{title: "why are you even asking?", votes_count: 0}
+ ],
+ voted: false,
+ votes_count: 0
+ }
+
+ result = StatusView.render("poll.json", %{object: object})
+ expires_at = result.expires_at
+ result = Map.delete(result, :expires_at)
+
+ assert result == expected
+
+ expires_at = NaiveDateTime.from_iso8601!(expires_at)
+ assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20
+ end
+
+ test "detects if it is multiple choice" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Which Mastodon developer is your favourite?",
+ "poll" => %{
+ "options" => ["Gargron", "Eugen"],
+ "expires_in" => 20,
+ "multiple" => true
+ }
+ })
+
+ object = Object.normalize(activity)
+
+ assert %{multiple: true} = StatusView.render("poll.json", %{object: object})
+ end
+
+ test "detects emoji" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "What's with the smug face?",
+ "poll" => %{
+ "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"],
+ "expires_in" => 20
+ }
+ })
+
+ object = Object.normalize(activity)
+
+ assert %{emojis: [%{shortcode: "blank"}]} =
+ StatusView.render("poll.json", %{object: object})
+ end
+
+ test "detects vote status" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "Which input devices do you use?",
+ "poll" => %{
+ "options" => ["mouse", "trackball", "trackpoint"],
+ "multiple" => true,
+ "expires_in" => 20
+ }
+ })
+
+ object = Object.normalize(activity)
+
+ {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2])
+
+ result = StatusView.render("poll.json", %{object: object, for: other_user})
+
+ assert result[:voted] == true
+ assert Enum.at(result[:options], 1)[:votes_count] == 1
+ assert Enum.at(result[:options], 2)[:votes_count] == 1
+ end
+ end
+
+ test "embeds a relationship in the account" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "drink more water"
+ })
+
+ result = StatusView.render("status.json", %{activity: activity, for: other_user})
+
+ assert result[:account][:pleroma][:relationship] ==
+ AccountView.render("relationship.json", %{user: other_user, target: user})
+ end
+
+ test "embeds a relationship in the account in reposts" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "˙˙ɐʎns"
+ })
+
+ {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user)
+
+ result = StatusView.render("status.json", %{activity: activity, for: user})
+
+ assert result[:account][:pleroma][:relationship] ==
+ AccountView.render("relationship.json", %{user: user, target: other_user})
+
+ assert result[:reblog][:account][:pleroma][:relationship] ==
+ AccountView.render("relationship.json", %{user: user, target: user})
+ end
+
+ test "visibility/list" do
+ user = insert(:user)
+
+ {:ok, list} = Pleroma.List.create("foo", user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+
+ status = StatusView.render("status.json", activity: activity)
+
+ assert status.visibility == "list"
+ end
end
diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs
new file mode 100644
index 000000000..53b8f556b
--- /dev/null
+++ b/test/web/media_proxy/media_proxy_controller_test.exs
@@ -0,0 +1,73 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
+ use Pleroma.Web.ConnCase
+ import Mock
+ alias Pleroma.Config
+
+ setup do
+ media_proxy_config = Config.get([:media_proxy]) || []
+ on_exit(fn -> Config.put([:media_proxy], media_proxy_config) end)
+ :ok
+ end
+
+ test "it returns 404 when MediaProxy disabled", %{conn: conn} do
+ Config.put([:media_proxy, :enabled], false)
+
+ assert %Plug.Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/hhgfh/eeeee")
+
+ assert %Plug.Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/hhgfh/eeee/fff")
+ end
+
+ test "it returns 403 when signature invalidated", %{conn: conn} do
+ Config.put([:media_proxy, :enabled], true)
+ Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+ path = URI.parse(Pleroma.Web.MediaProxy.encode_url("https://google.fn")).path
+ Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
+
+ assert %Plug.Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, path)
+
+ assert %Plug.Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/hhgfh/eeee")
+
+ assert %Plug.Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/hhgfh/eeee/fff")
+ end
+
+ test "redirects on valid url when filename invalidated", %{conn: conn} do
+ Config.put([:media_proxy, :enabled], true)
+ Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+ url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")
+ invalid_url = String.replace(url, "test.png", "test-file.png")
+ response = get(conn, invalid_url)
+ html = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
+ assert response.status == 302
+ assert response.resp_body == html
+ end
+
+ test "it performs ReverseProxy.call when signature valid", %{conn: conn} do
+ Config.put([:media_proxy, :enabled], true)
+ Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+ url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")
+
+ with_mock Pleroma.ReverseProxy,
+ call: fn _conn, _url, _opts -> %Plug.Conn{status: :success} end do
+ assert %Plug.Conn{status: :success} = get(conn, url)
+ end
+ end
+end
diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs
new file mode 100644
index 000000000..cb4807e0b
--- /dev/null
+++ b/test/web/media_proxy/media_proxy_test.exs
@@ -0,0 +1,215 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxyTest do
+ use ExUnit.Case
+ import Pleroma.Web.MediaProxy
+ alias Pleroma.Web.MediaProxy.MediaProxyController
+
+ setup do
+ enabled = Pleroma.Config.get([:media_proxy, :enabled])
+ on_exit(fn -> Pleroma.Config.put([:media_proxy, :enabled], enabled) end)
+ :ok
+ end
+
+ describe "when enabled" do
+ setup do
+ Pleroma.Config.put([:media_proxy, :enabled], true)
+ :ok
+ end
+
+ test "ignores invalid url" do
+ assert url(nil) == nil
+ assert url("") == nil
+ end
+
+ test "ignores relative url" do
+ assert url("/local") == "/local"
+ assert url("/") == "/"
+ end
+
+ test "ignores local url" do
+ local_url = Pleroma.Web.Endpoint.url() <> "/hello"
+ local_root = Pleroma.Web.Endpoint.url()
+ assert url(local_url) == local_url
+ assert url(local_root) == local_root
+ end
+
+ test "encodes and decodes URL" do
+ url = "https://pleroma.soykaf.com/static/logo.png"
+ encoded = url(url)
+
+ assert String.starts_with?(
+ encoded,
+ Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
+ )
+
+ assert String.ends_with?(encoded, "/logo.png")
+
+ assert decode_result(encoded) == url
+ end
+
+ test "encodes and decodes URL without a path" do
+ url = "https://pleroma.soykaf.com"
+ encoded = url(url)
+ assert decode_result(encoded) == url
+ end
+
+ test "encodes and decodes URL without an extension" do
+ url = "https://pleroma.soykaf.com/path/"
+ encoded = url(url)
+ assert String.ends_with?(encoded, "/path")
+ assert decode_result(encoded) == url
+ 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"
+ encoded = url(url)
+ assert String.ends_with?(encoded, "/logo.png")
+ assert decode_result(encoded) == url
+ end
+
+ test "validates signature" do
+ secret_key_base = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
+
+ on_exit(fn ->
+ Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], secret_key_base)
+ end)
+
+ encoded = url("https://pleroma.social")
+
+ Pleroma.Config.put(
+ [Pleroma.Web.Endpoint, :secret_key_base],
+ "00000000000000000000000000000000000000000000000"
+ )
+
+ [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
+ assert decode_url(sig, base64) == {:error, :invalid_signature}
+ end
+
+ test "filename_matches preserves the encoded or decoded path" do
+ assert MediaProxyController.filename_matches(
+ %{"filename" => "/Hello world.jpg"},
+ "/Hello world.jpg",
+ "http://pleroma.social/Hello world.jpg"
+ ) == :ok
+
+ assert MediaProxyController.filename_matches(
+ %{"filename" => "/Hello%20world.jpg"},
+ "/Hello%20world.jpg",
+ "http://pleroma.social/Hello%20world.jpg"
+ ) == :ok
+
+ assert MediaProxyController.filename_matches(
+ %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"},
+ "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
+ "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
+ ) == :ok
+
+ assert MediaProxyController.filename_matches(
+ %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jp"},
+ "/my%2Flong%2Furl%2F2019%2F07%2FS.jp",
+ "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
+ ) == {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}
+ end
+
+ test "uses the configured base_url" do
+ base_url = Pleroma.Config.get([:media_proxy, :base_url])
+
+ if base_url do
+ on_exit(fn ->
+ Pleroma.Config.put([:media_proxy, :base_url], base_url)
+ end)
+ end
+
+ Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social")
+
+ url = "https://pleroma.soykaf.com/static/logo.png"
+ encoded = url(url)
+
+ assert String.starts_with?(encoded, Pleroma.Config.get([:media_proxy, :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 = 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.
+ test "preserve non-unicode characters per RFC3986" do
+ url =
+ "https://pleroma.com/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-._~:/?#[]@!$&'()*+,;=|^`{}"
+
+ encoded = url(url)
+ assert decode_result(encoded) == url
+ end
+
+ test "preserve unicode characters" do
+ url = "https://ko.wikipedia.org/wiki/위키백과:대문"
+
+ encoded = url(url)
+ assert decode_result(encoded) == url
+ end
+
+ test "does not change whitelisted urls" do
+ upload_config = Pleroma.Config.get([Pleroma.Upload])
+ media_url = "https://media.pleroma.social"
+ Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
+ Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"])
+ Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social")
+
+ url = "#{media_url}/static/logo.png"
+ encoded = url(url)
+
+ assert String.starts_with?(encoded, media_url)
+
+ Pleroma.Config.put([Pleroma.Upload], upload_config)
+ end
+ end
+
+ describe "when disabled" do
+ setup do
+ enabled = Pleroma.Config.get([:media_proxy, :enabled])
+
+ if enabled do
+ Pleroma.Config.put([:media_proxy, :enabled], false)
+
+ on_exit(fn ->
+ Pleroma.Config.put([:media_proxy, :enabled], enabled)
+ :ok
+ end)
+ end
+
+ :ok
+ end
+
+ test "does not encode remote urls" do
+ assert url("https://google.fr") == "https://google.fr"
+ end
+ end
+
+ defp decode_result(encoded) do
+ [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
+ {:ok, decoded} = decode_url(sig, base64)
+ decoded
+ end
+
+ test "mediaproxy whitelist" do
+ Pleroma.Config.put([:media_proxy, :enabled], true)
+ Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"])
+ url = "https://feld.me/foo.png"
+
+ unencoded = url(url)
+ assert unencoded == url
+ end
+end
diff --git a/test/web/metadata/player_view_test.exs b/test/web/metadata/player_view_test.exs
new file mode 100644
index 000000000..742b0ed8b
--- /dev/null
+++ b/test/web/metadata/player_view_test.exs
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.PlayerViewTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.Metadata.PlayerView
+
+ test "it renders audio tag" do
+ res =
+ PlayerView.render(
+ "player.html",
+ %{"mediaType" => "audio", "href" => "test-href"}
+ )
+ |> Phoenix.HTML.safe_to_string()
+
+ assert res ==
+ "<audio controls><source src=\"test-href\" type=\"audio\">Your browser does not support audio playback.</audio>"
+ end
+
+ test "it renders videos tag" do
+ res =
+ PlayerView.render(
+ "player.html",
+ %{"mediaType" => "video", "href" => "test-href"}
+ )
+ |> Phoenix.HTML.safe_to_string()
+
+ assert res ==
+ "<video controls loop><source src=\"test-href\" type=\"video\">Your browser does not support video playback.</video>"
+ end
+end
diff --git a/test/web/metadata/rel_me_test.exs b/test/web/metadata/rel_me_test.exs
index f66bf7834..3874e077b 100644
--- a/test/web/metadata/rel_me_test.exs
+++ b/test/web/metadata/rel_me_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Metadata.Providers.RelMeTest do
use Pleroma.DataCase
import Pleroma.Factory
diff --git a/test/web/metadata/twitter_card_test.exs b/test/web/metadata/twitter_card_test.exs
new file mode 100644
index 000000000..0814006d2
--- /dev/null
+++ b/test/web/metadata/twitter_card_test.exs
@@ -0,0 +1,123 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.Metadata.Providers.TwitterCard
+ alias Pleroma.Web.Metadata.Utils
+ alias Pleroma.Web.Router
+
+ test "it renders twitter card for user info" do
+ user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
+ avatar_url = Utils.attachment_url(User.avatar_url(user))
+ res = TwitterCard.build_tags(%{user: user})
+
+ assert res == [
+ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
+ {:meta, [property: "twitter:description", content: "born 19 March 1994"], []},
+ {:meta, [property: "twitter:image", content: avatar_url], []},
+ {:meta, [property: "twitter:card", content: "summary"], []}
+ ]
+ end
+
+ test "it does not render attachments if post is nsfw" do
+ Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false)
+ user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI"})
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "tag" => [],
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "pleroma in a nutshell",
+ "sensitive" => true,
+ "attachment" => [
+ %{
+ "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"}]
+ },
+ %{
+ "url" => [
+ %{
+ "mediaType" => "application/octet-stream",
+ "href" => "https://pleroma.gov/fqa/badapple.sfc"
+ }
+ ]
+ },
+ %{
+ "url" => [
+ %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"}
+ ]
+ }
+ ]
+ }
+ })
+
+ result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
+
+ assert [
+ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
+ {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
+ {:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
+ []},
+ {:meta, [property: "twitter:card", content: "summary_large_image"], []}
+ ] == result
+ end
+
+ test "it renders supported types of attachments and skips unknown types" do
+ user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI"})
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "tag" => [],
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "pleroma in a nutshell",
+ "attachment" => [
+ %{
+ "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"}]
+ },
+ %{
+ "url" => [
+ %{
+ "mediaType" => "application/octet-stream",
+ "href" => "https://pleroma.gov/fqa/badapple.sfc"
+ }
+ ]
+ },
+ %{
+ "url" => [
+ %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"}
+ ]
+ }
+ ]
+ }
+ })
+
+ result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
+
+ assert [
+ {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
+ {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
+ {:meta, [property: "twitter:card", content: "summary_large_image"], []},
+ {:meta, [property: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []},
+ {:meta, [property: "twitter:card", content: "player"], []},
+ {:meta,
+ [
+ property: "twitter:player",
+ content: Router.Helpers.o_status_url(Endpoint, :notice_player, activity.id)
+ ], []},
+ {:meta, [property: "twitter:player:width", content: "480"], []},
+ {:meta, [property: "twitter:player:height", content: "480"], []}
+ ] == result
+ end
+end
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index be1173513..d7f848bfa 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -83,4 +83,47 @@ defmodule Pleroma.Web.NodeInfoTest do
Pleroma.Config.put([:instance, :safe_dm_mentions], option)
end
+
+ test "it shows MRF transparency data if enabled", %{conn: conn} do
+ option = Pleroma.Config.get([:instance, :mrf_transparency])
+ Pleroma.Config.put([:instance, :mrf_transparency], true)
+
+ simple_config = %{"reject" => ["example.com"]}
+ Pleroma.Config.put(:mrf_simple, simple_config)
+
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["mrf_simple"] == simple_config
+
+ Pleroma.Config.put([:instance, :mrf_transparency], option)
+ Pleroma.Config.put(:mrf_simple, %{})
+ end
+
+ test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
+ option = Pleroma.Config.get([:instance, :mrf_transparency])
+ Pleroma.Config.put([:instance, :mrf_transparency], true)
+
+ exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
+ Pleroma.Config.put([:instance, :mrf_transparency_exclusions], ["other.site"])
+
+ simple_config = %{"reject" => ["example.com", "other.site"]}
+ expected_config = %{"reject" => ["example.com"]}
+
+ Pleroma.Config.put(:mrf_simple, simple_config)
+
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["mrf_simple"] == expected_config
+ assert response["metadata"]["federation"]["exclusions"] == true
+
+ Pleroma.Config.put([:instance, :mrf_transparency], option)
+ Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
+ Pleroma.Config.put(:mrf_simple, %{})
+ end
end
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 1c04ac9ad..aae34804d 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Authorization
+ alias Pleroma.Web.OAuth.OAuthController
alias Pleroma.Web.OAuth.Token
@oauth_config_path [:oauth2, :issue_new_refresh_token]
@@ -49,7 +50,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"response_type" => "code",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"scope" => "read"
}
)
@@ -72,7 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scope" => "read follow",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => "a_state"
}
}
@@ -98,11 +99,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "with user-bound registration, GET /oauth/<provider>/callback redirects to `redirect_uri` with `code`",
%{app: app, conn: conn} do
registration = insert(:registration)
+ redirect_uri = OAuthController.default_redirect_uri(app)
state_params = %{
"scope" => Enum.join(app.scopes, " "),
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => ""
}
@@ -121,7 +123,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
)
assert response = html_response(conn, 302)
- assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end
end
@@ -132,7 +134,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
state_params = %{
"scope" => "read write",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => "a_state"
}
@@ -165,7 +167,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
state_params = %{
"scope" => Enum.join(app.scopes, " "),
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => ""
}
@@ -199,7 +201,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scopes" => app.scopes,
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => "a_state",
"nickname" => nil,
"email" => "john@doe.com"
@@ -218,6 +220,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn: conn
} do
registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+ redirect_uri = OAuthController.default_redirect_uri(app)
conn =
conn
@@ -229,7 +232,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scopes" => app.scopes,
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => "a_state",
"nickname" => "availablenick",
"email" => "available@email.com"
@@ -238,7 +241,36 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
)
assert response = html_response(conn, 302)
- assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
+ end
+
+ test "with unlisted `redirect_uri`, POST /oauth/register?op=register results in HTTP 401",
+ %{
+ app: app,
+ conn: conn
+ } do
+ registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+ unlisted_redirect_uri = "http://cross-site-request.com"
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post(
+ "/oauth/register",
+ %{
+ "op" => "register",
+ "authorization" => %{
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => unlisted_redirect_uri,
+ "state" => "a_state",
+ "nickname" => "availablenick",
+ "email" => "available@email.com"
+ }
+ }
+ )
+
+ assert response = html_response(conn, 401)
end
test "with invalid params, POST /oauth/register?op=register renders registration_details page",
@@ -254,7 +286,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scopes" => app.scopes,
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => "a_state",
"nickname" => "availablenickname",
"email" => "available@email.com"
@@ -286,6 +318,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
} do
user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
registration = insert(:registration, user: nil)
+ redirect_uri = OAuthController.default_redirect_uri(app)
conn =
conn
@@ -297,7 +330,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scopes" => app.scopes,
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => "a_state",
"name" => user.nickname,
"password" => "testpassword"
@@ -306,7 +339,37 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
)
assert response = html_response(conn, 302)
- assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
+ end
+
+ test "with unlisted `redirect_uri`, POST /oauth/register?op=connect results in HTTP 401`",
+ %{
+ app: app,
+ conn: conn
+ } do
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
+ registration = insert(:registration, user: nil)
+ unlisted_redirect_uri = "http://cross-site-request.com"
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post(
+ "/oauth/register",
+ %{
+ "op" => "connect",
+ "authorization" => %{
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => unlisted_redirect_uri,
+ "state" => "a_state",
+ "name" => user.nickname,
+ "password" => "testpassword"
+ }
+ }
+ )
+
+ assert response = html_response(conn, 401)
end
test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
@@ -322,7 +385,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"scopes" => app.scopes,
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"state" => "a_state",
"name" => user.nickname,
"password" => "wrong password"
@@ -358,7 +421,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"response_type" => "code",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"scope" => "read"
}
)
@@ -378,7 +441,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"authorization" => %{
"response_type" => "code",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"scope" => "read"
}
}
@@ -399,7 +462,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"response_type" => "code",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"scope" => "read",
"force_login" => "true"
}
@@ -408,7 +471,61 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
assert html_response(conn, 200) =~ ~s(type="submit")
end
- test "redirects to app if user is already authenticated", %{app: app, conn: conn} do
+ test "with existing authentication and non-OOB `redirect_uri`, redirects to app with `token` and `state` params",
+ %{
+ app: app,
+ conn: conn
+ } do
+ token = insert(:oauth_token, app_id: app.id)
+
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
+ "state" => "specific_client_state",
+ "scope" => "read"
+ }
+ )
+
+ assert URI.decode(redirected_to(conn)) ==
+ "https://redirect.url?access_token=#{token.token}&state=specific_client_state"
+ end
+
+ test "with existing authentication and unlisted non-OOB `redirect_uri`, redirects without credentials",
+ %{
+ app: app,
+ conn: conn
+ } do
+ unlisted_redirect_uri = "http://cross-site-request.com"
+ token = insert(:oauth_token, app_id: app.id)
+
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => unlisted_redirect_uri,
+ "state" => "specific_client_state",
+ "scope" => "read"
+ }
+ )
+
+ assert redirected_to(conn) == unlisted_redirect_uri
+ end
+
+ test "with existing authentication and OOB `redirect_uri`, redirects to app with `token` and `state` params",
+ %{
+ app: app,
+ conn: conn
+ } do
token = insert(:oauth_token, app_id: app.id)
conn =
@@ -419,12 +536,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"response_type" => "code",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
"scope" => "read"
}
)
- assert redirected_to(conn) == "https://redirect.url"
+ assert html_response(conn, 200) =~ "Authorization exists"
end
end
@@ -432,6 +549,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "redirects with oauth authorization" do
user = insert(:user)
app = insert(:oauth_app, scopes: ["read", "write", "follow"])
+ redirect_uri = OAuthController.default_redirect_uri(app)
conn =
build_conn()
@@ -440,14 +558,14 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"name" => user.nickname,
"password" => "test",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"scope" => "read write",
"state" => "statepassed"
}
})
target = redirected_to(conn)
- assert target =~ app.redirect_uris
+ assert target =~ redirect_uri
query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
@@ -460,6 +578,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "returns 401 for wrong credentials", %{conn: conn} do
user = insert(:user)
app = insert(:oauth_app)
+ redirect_uri = OAuthController.default_redirect_uri(app)
result =
conn
@@ -468,7 +587,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"name" => user.nickname,
"password" => "wrong",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => "statepassed",
"scope" => Enum.join(app.scopes, " ")
}
@@ -477,7 +596,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
# Keep the details
assert result =~ app.client_id
- assert result =~ app.redirect_uris
+ assert result =~ redirect_uri
# Error message
assert result =~ "Invalid Username/Password"
@@ -486,6 +605,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "returns 401 for missing scopes", %{conn: conn} do
user = insert(:user)
app = insert(:oauth_app)
+ redirect_uri = OAuthController.default_redirect_uri(app)
result =
conn
@@ -494,7 +614,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"name" => user.nickname,
"password" => "test",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => "statepassed",
"scope" => ""
}
@@ -503,7 +623,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
# Keep the details
assert result =~ app.client_id
- assert result =~ app.redirect_uris
+ assert result =~ redirect_uri
# Error message
assert result =~ "This action is outside the authorized scopes"
@@ -512,6 +632,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "returns 401 for scopes beyond app scopes", %{conn: conn} do
user = insert(:user)
app = insert(:oauth_app, scopes: ["read", "write"])
+ redirect_uri = OAuthController.default_redirect_uri(app)
result =
conn
@@ -520,7 +641,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"name" => user.nickname,
"password" => "test",
"client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => redirect_uri,
"state" => "statepassed",
"scope" => "read write follow"
}
@@ -529,7 +650,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
# Keep the details
assert result =~ app.client_id
- assert result =~ app.redirect_uris
+ assert result =~ redirect_uri
# Error message
assert result =~ "This action is outside the authorized scopes"
@@ -548,7 +669,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|> post("/oauth/token", %{
"grant_type" => "authorization_code",
"code" => auth.token,
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
@@ -602,7 +723,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|> post("/oauth/token", %{
"grant_type" => "authorization_code",
"code" => auth.token,
- "redirect_uri" => app.redirect_uris
+ "redirect_uri" => OAuthController.default_redirect_uri(app)
})
assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
@@ -647,7 +768,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|> post("/oauth/token", %{
"grant_type" => "authorization_code",
"code" => auth.token,
- "redirect_uri" => app.redirect_uris
+ "redirect_uri" => OAuthController.default_redirect_uri(app)
})
assert resp = json_response(conn, 400)
@@ -726,7 +847,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|> post("/oauth/token", %{
"grant_type" => "authorization_code",
"code" => "Imobviouslyinvalid",
- "redirect_uri" => app.redirect_uris,
+ "redirect_uri" => OAuthController.default_redirect_uri(app),
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs
index 16ee02abb..a3a92ce5b 100644
--- a/test/web/ostatus/activity_representer_test.exs
+++ b/test/web/ostatus/activity_representer_test.exs
@@ -38,22 +38,23 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
test "a note activity" do
note_activity = insert(:note_activity)
+ object_data = Object.normalize(note_activity).data
user = User.get_cached_by_ap_id(note_activity.data["actor"])
expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <id>#{note_activity.data["object"]["id"]}</id>
+ <id>#{object_data["id"]}</id>
<title>New note by #{user.nickname}</title>
- <content type="html">#{note_activity.data["object"]["content"]}</content>
- <published>#{note_activity.data["object"]["published"]}</published>
- <updated>#{note_activity.data["object"]["published"]}</updated>
+ <content type="html">#{object_data["content"]}</content>
+ <published>#{object_data["published"]}</published>
+ <updated>#{object_data["published"]}</updated>
<ostatus:conversation ref="#{note_activity.data["context"]}">#{note_activity.data["context"]}</ostatus:conversation>
<link ref="#{note_activity.data["context"]}" rel="ostatus:conversation" />
- <summary>#{note_activity.data["object"]["summary"]}</summary>
- <link type="application/atom+xml" href="#{note_activity.data["object"]["id"]}" rel="self" />
- <link type="text/html" href="#{note_activity.data["object"]["id"]}" rel="alternate" />
+ <summary>#{object_data["summary"]}</summary>
+ <link type="application/atom+xml" href="#{object_data["id"]}" rel="self" />
+ <link type="text/html" href="#{object_data["id"]}" rel="alternate" />
<category term="2hu"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link name="2hu" rel="emoji" href="corndog.png" />
@@ -106,7 +107,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
test "an announce activity" do
note = insert(:note_activity)
user = insert(:user)
- object = Object.get_cached_by_ap_id(note.data["object"]["id"])
+ object = Object.normalize(note)
{:ok, announce, _object} = ActivityPub.announce(user, object)
@@ -125,7 +126,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<id>#{announce.data["id"]}</id>
<title>#{user.nickname} repeated a notice</title>
- <content type="html">RT #{note.data["object"]["content"]}</content>
+ <content type="html">RT #{object.data["content"]}</content>
<published>#{announce.data["published"]}</published>
<updated>#{announce.data["published"]}</updated>
<ostatus:conversation ref="#{announce.data["context"]}">#{announce.data["context"]}</ostatus:conversation>
diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs
index ca6e61339..cd0447af7 100644
--- a/test/web/ostatus/incoming_documents/delete_handling_test.exs
+++ b/test/web/ostatus/incoming_documents/delete_handling_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
use Pleroma.DataCase
@@ -17,8 +21,9 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
test "it removes the mentioned activity" do
note = insert(:note_activity)
second_note = insert(:note_activity)
+ object = Object.normalize(note)
+ second_object = Object.normalize(second_note)
user = insert(:user)
- object = Object.get_by_ap_id(note.data["object"]["id"])
{:ok, like, _object} = Pleroma.Web.ActivityPub.ActivityPub.like(user, object)
@@ -26,16 +31,16 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
File.read!("test/fixtures/delete.xml")
|> String.replace(
"tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status",
- note.data["object"]["id"]
+ object.data["id"]
)
{:ok, [delete]} = OStatus.handle_incoming(incoming)
refute Activity.get_by_id(note.id)
refute Activity.get_by_id(like.id)
- assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
+ assert Object.get_by_ap_id(object.data["id"]).data["type"] == "Tombstone"
assert Activity.get_by_id(second_note.id)
- assert Object.get_by_ap_id(second_note.data["object"]["id"])
+ assert Object.get_by_ap_id(second_object.data["id"])
assert delete.data["type"] == "Delete"
end
diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs
index 7441e5fce..3dd8c6491 100644
--- a/test/web/ostatus/ostatus_controller_test.exs
+++ b/test/web/ostatus/ostatus_controller_test.exs
@@ -12,6 +12,13 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ Pleroma.Config.put(config_path, true)
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
:ok
end
@@ -65,6 +72,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "gets a feed", %{conn: conn} do
note_activity = insert(:note_activity)
+ object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
conn =
@@ -72,7 +80,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> put_req_header("content-type", "application/atom+xml")
|> get("/users/#{user.nickname}/feed.atom")
- assert response(conn, 200) =~ note_activity.data["object"]["content"]
+ assert response(conn, 200) =~ object.data["content"]
end
test "returns 404 for a missing feed", %{conn: conn} do
@@ -86,8 +94,9 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "gets an object", %{conn: conn} do
note_activity = insert(:note_activity)
+ object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
- [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
+ [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
url = "/objects/#{uuid}"
conn =
@@ -106,7 +115,8 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "404s on private objects", %{conn: conn} do
note_activity = insert(:direct_note_activity)
- [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
+ object = Object.normalize(note_activity)
+ [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
conn
|> get("/objects/#{uuid}")
@@ -131,8 +141,8 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "404s on deleted objects", %{conn: conn} do
note_activity = insert(:note_activity)
- [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
+ [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
conn
|> put_req_header("accept", "application/xml")
diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs
index f6be16862..4e8f3a0fc 100644
--- a/test/web/ostatus/ostatus_test.exs
+++ b/test/web/ostatus/ostatus_test.exs
@@ -11,8 +11,10 @@ defmodule Pleroma.Web.OStatusTest do
alias Pleroma.User
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML
- import Pleroma.Factory
+
import ExUnit.CaptureLog
+ import Mock
+ import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -28,7 +30,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming note - GS, Salmon" do
incoming = File.read!("test/fixtures/incoming_note_activity.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
user = User.get_cached_by_ap_id(activity.data["actor"])
assert user.info.note_count == 1
@@ -51,7 +53,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming notes - GS, subscription" do
incoming = File.read!("test/fixtures/ostatus_incoming_post.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -65,7 +67,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming notes with attachments - GS, subscription" do
incoming = File.read!("test/fixtures/incoming_websub_gnusocial_attachments.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -78,7 +80,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming notes with tags" do
incoming = File.read!("test/fixtures/ostatus_incoming_post_tag.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert object.data["tag"] == ["nsfw"]
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
@@ -95,7 +97,7 @@ defmodule Pleroma.Web.OStatusTest do
incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -107,7 +109,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming notes - Mastodon, with CW" do
incoming = File.read!("test/fixtures/mastodon-note-cw.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -119,7 +121,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming unlisted messages, put public into cc" do
incoming = File.read!("test/fixtures/mastodon-note-unlisted.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
refute "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["cc"]
@@ -130,7 +132,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming retweets - Mastodon, with CW" do
incoming = File.read!("test/fixtures/cw_retweet.xml")
{:ok, [[_activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)
- retweeted_object = Object.normalize(retweeted_activity.data["object"])
+ retweeted_object = Object.normalize(retweeted_activity)
assert retweeted_object.data["summary"] == "Hey."
end
@@ -138,7 +140,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming notes - GS, subscription, reply" do
incoming = File.read!("test/fixtures/ostatus_incoming_reply.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -164,7 +166,7 @@ defmodule Pleroma.Web.OStatusTest do
refute activity.local
retweeted_activity = Activity.get_by_id(retweeted_activity.id)
- retweeted_object = Object.normalize(retweeted_activity.data["object"])
+ retweeted_object = Object.normalize(retweeted_activity)
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
refute retweeted_activity.local
@@ -176,18 +178,19 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming retweets - GS, subscription - local message" do
incoming = File.read!("test/fixtures/share-gs-local.xml")
note_activity = insert(:note_activity)
+ object = Object.normalize(note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
incoming =
incoming
- |> String.replace("LOCAL_ID", note_activity.data["object"]["id"])
+ |> String.replace("LOCAL_ID", object.data["id"])
|> String.replace("LOCAL_USER", user.ap_id)
{:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Announce"
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
- assert activity.data["object"] == retweeted_activity.data["object"]["id"]
+ assert activity.data["object"] == object.data["id"]
assert user.ap_id in activity.data["to"]
refute activity.local
@@ -202,7 +205,7 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming retweets - Mastodon, salmon" do
incoming = File.read!("test/fixtures/share.xml")
{:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)
- retweeted_object = Object.normalize(retweeted_activity.data["object"])
+ retweeted_object = Object.normalize(retweeted_activity)
assert activity.data["type"] == "Announce"
assert activity.data["actor"] == "https://mastodon.social/users/lambadalambda"
@@ -251,25 +254,29 @@ defmodule Pleroma.Web.OStatusTest do
test "handle incoming favorites with locally available object - GS, websub" do
note_activity = insert(:note_activity)
+ object = Object.normalize(note_activity)
incoming =
File.read!("test/fixtures/favorite_with_local_note.xml")
- |> String.replace("localid", note_activity.data["object"]["id"])
+ |> String.replace("localid", object.data["id"])
{:ok, [[activity, favorited_activity]]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Like"
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
- assert activity.data["object"] == favorited_activity.data["object"]["id"]
+ assert activity.data["object"] == object.data["id"]
refute activity.local
assert note_activity.id == favorited_activity.id
assert favorited_activity.local
end
- test "handle incoming replies" do
+ test_with_mock "handle incoming replies, fetching replied-to activities if we don't have them",
+ OStatus,
+ [:passthrough],
+ [] do
incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity, false)
assert activity.data["type"] == "Create"
assert object.data["type"] == "Note"
@@ -282,6 +289,23 @@ defmodule Pleroma.Web.OStatusTest do
assert object.data["id"] == "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note"
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
+
+ assert called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_))
+ end
+
+ test_with_mock "handle incoming replies, not fetching replied-to activities beyond max_replies_depth",
+ OStatus,
+ [:passthrough],
+ [] do
+ incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")
+
+ with_mock Pleroma.Web.Federator,
+ allowed_incoming_reply_depth?: fn _ -> false end do
+ {:ok, [activity]} = OStatus.handle_incoming(incoming)
+ object = Object.normalize(activity, false)
+
+ refute called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_))
+ end
end
test "handle incoming follows" do
@@ -315,13 +339,14 @@ defmodule Pleroma.Web.OStatusTest do
"undo:tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00"
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
- assert is_map(activity.data["object"])
- assert activity.data["object"]["type"] == "Follow"
- assert activity.data["object"]["object"] == "https://pawoo.net/users/pekorino"
+ embedded_object = activity.data["object"]
+ assert is_map(embedded_object)
+ assert embedded_object["type"] == "Follow"
+ assert embedded_object["object"] == "https://pawoo.net/users/pekorino"
refute activity.local
follower = User.get_cached_by_ap_id(activity.data["actor"])
- followed = User.get_cached_by_ap_id(activity.data["object"]["object"])
+ followed = User.get_cached_by_ap_id(embedded_object["object"])
refute User.following?(follower, followed)
end
@@ -538,8 +563,7 @@ defmodule Pleroma.Web.OStatusTest do
test "Article objects are not representable" do
note_activity = insert(:note_activity)
-
- note_object = Object.normalize(note_activity.data["object"])
+ note_object = Object.normalize(note_activity)
note_data =
note_object.data
diff --git a/test/web/plugs/federating_plug_test.exs b/test/web/plugs/federating_plug_test.exs
index 612db7e32..c01e01124 100644
--- a/test/web/plugs/federating_plug_test.exs
+++ b/test/web/plugs/federating_plug_test.exs
@@ -5,12 +5,17 @@
defmodule Pleroma.Web.FederatingPlugTest do
use Pleroma.Web.ConnCase
- test "returns and halt the conn when federating is disabled" do
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:federating, false)
+ setup_all do
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
+ :ok
+ end
- Application.put_env(:pleroma, :instance, instance)
+ test "returns and halt the conn when federating is disabled" do
+ Pleroma.Config.put([:instance, :federating], false)
conn =
build_conn()
@@ -18,15 +23,11 @@ defmodule Pleroma.Web.FederatingPlugTest do
assert conn.status == 404
assert conn.halted
-
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:federating, true)
-
- Application.put_env(:pleroma, :instance, instance)
end
test "does nothing when federating is enabled" do
+ Pleroma.Config.put([:instance, :federating], true)
+
conn =
build_conn()
|> Pleroma.Web.FederatingPlug.call(%{})
diff --git a/test/web/rel_me_test.exs b/test/web/rel_me_test.exs
index 5188f4de1..85515c432 100644
--- a/test/web/rel_me_test.exs
+++ b/test/web/rel_me_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.RelMeTest do
use ExUnit.Case, async: true
diff --git a/test/web/rich_media/helpers_test.exs b/test/web/rich_media/helpers_test.exs
index 53b0596f5..92198f3d9 100644
--- a/test/web/rich_media/helpers_test.exs
+++ b/test/web/rich_media/helpers_test.exs
@@ -1,14 +1,23 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.RichMedia.HelpersTest do
use Pleroma.DataCase
+ alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.RichMedia.Helpers
import Pleroma.Factory
import Tesla.Mock
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ rich_media = Config.get([:rich_media, :enabled])
+ on_exit(fn -> Config.put([:rich_media, :enabled], rich_media) end)
+
:ok
end
@@ -21,11 +30,9 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
"content_type" => "text/markdown"
})
- Pleroma.Config.put([:rich_media, :enabled], true)
+ Config.put([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
-
- Pleroma.Config.put([:rich_media, :enabled], false)
end
test "refuses to crawl malformed URLs" do
@@ -37,11 +44,9 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
"content_type" => "text/markdown"
})
- Pleroma.Config.put([:rich_media, :enabled], true)
+ Config.put([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
-
- Pleroma.Config.put([:rich_media, :enabled], false)
end
test "crawls valid, complete URLs" do
@@ -49,16 +54,14 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
{:ok, activity} =
CommonAPI.post(user, %{
- "status" => "[test](http://example.com/ogp)",
+ "status" => "[test](https://example.com/ogp)",
"content_type" => "text/markdown"
})
- Pleroma.Config.put([:rich_media, :enabled], true)
+ Config.put([:rich_media, :enabled], true)
- assert %{page_url: "http://example.com/ogp", rich_media: _} =
+ assert %{page_url: "https://example.com/ogp", rich_media: _} =
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
-
- Pleroma.Config.put([:rich_media, :enabled], false)
end
test "refuses to crawl URLs from posts marked sensitive" do
@@ -74,11 +77,9 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
assert object.data["sensitive"]
- Pleroma.Config.put([:rich_media, :enabled], true)
+ Config.put([:rich_media, :enabled], true)
assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
-
- Pleroma.Config.put([:rich_media, :enabled], false)
end
test "refuses to crawl URLs from posts tagged NSFW" do
@@ -93,10 +94,28 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
assert object.data["sensitive"]
- Pleroma.Config.put([:rich_media, :enabled], true)
+ Config.put([:rich_media, :enabled], true)
assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ end
+
+ test "refuses to crawl URLs of private network from posts" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "http://127.0.0.1:4000/notice/9kCP7VNyPJXFOXDrgO"})
+
+ {:ok, activity2} = CommonAPI.post(user, %{"status" => "https://10.111.10.1/notice/9kCP7V"})
+ {:ok, activity3} = CommonAPI.post(user, %{"status" => "https://172.16.32.40/notice/9kCP7V"})
+ {:ok, activity4} = CommonAPI.post(user, %{"status" => "https://192.168.10.40/notice/9kCP7V"})
+ {:ok, activity5} = CommonAPI.post(user, %{"status" => "https://pleroma.local/notice/9kCP7V"})
+
+ Config.put([:rich_media, :enabled], true)
- Pleroma.Config.put([:rich_media, :enabled], false)
+ assert %{} = Helpers.fetch_data_for_activity(activity)
+ assert %{} = Helpers.fetch_data_for_activity(activity2)
+ assert %{} = Helpers.fetch_data_for_activity(activity3)
+ assert %{} = Helpers.fetch_data_for_activity(activity4)
+ assert %{} = Helpers.fetch_data_for_activity(activity5)
end
end
diff --git a/test/web/rich_media/parser_test.exs b/test/web/rich_media/parser_test.exs
index 47b127cf9..19c19e895 100644
--- a/test/web/rich_media/parser_test.exs
+++ b/test/web/rich_media/parser_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.RichMedia.ParserTest do
use ExUnit.Case, async: true
@@ -11,6 +15,21 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
%{
method: :get,
+ url: "http://example.com/non-ogp"
+ } ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/non_ogp_embed.html")}
+
+ %{
+ method: :get,
+ url: "http://example.com/ogp-missing-title"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/rich_media/ogp-missing-title.html")
+ }
+
+ %{
+ method: :get,
url: "http://example.com/twitter-card"
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/twitter_card.html")}
@@ -38,12 +57,32 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
assert {:error, _} = Pleroma.Web.RichMedia.Parser.parse("http://example.com/empty")
end
+ test "doesn't just add a title" do
+ assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/non-ogp") ==
+ {:error, "Found metadata was invalid or incomplete: %{}"}
+ end
+
test "parses ogp" do
assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/ogp") ==
{:ok,
%{
image: "http://ia.media-imdb.com/images/rock.jpg",
title: "The Rock",
+ description:
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
+ type: "video.movie",
+ url: "http://www.imdb.com/title/tt0117500/"
+ }}
+ end
+
+ test "falls back to <title> when ogp:title is missing" do
+ assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/ogp-missing-title") ==
+ {:ok,
+ %{
+ image: "http://ia.media-imdb.com/images/rock.jpg",
+ title: "The Rock (1996)",
+ description:
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
type: "video.movie",
url: "http://www.imdb.com/title/tt0117500/"
}}
diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs
index bfe18cb7f..4633d7765 100644
--- a/test/web/streamer_test.exs
+++ b/test/web/streamer_test.exs
@@ -11,6 +11,62 @@ defmodule Pleroma.Web.StreamerTest do
alias Pleroma.Web.Streamer
import Pleroma.Factory
+ setup do
+ skip_thread_containment = Pleroma.Config.get([:instance, :skip_thread_containment])
+
+ on_exit(fn ->
+ Pleroma.Config.put([:instance, :skip_thread_containment], skip_thread_containment)
+ end)
+
+ :ok
+ end
+
+ describe "user streams" do
+ setup do
+ GenServer.start(Streamer, %{}, name: Streamer)
+
+ on_exit(fn ->
+ if pid = Process.whereis(Streamer) do
+ Process.exit(pid, :kill)
+ end
+ end)
+
+ user = insert(:user)
+ notify = insert(:notification, user: user, activity: build(:note_activity))
+ {:ok, %{user: user, notify: notify}}
+ end
+
+ test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
+ task =
+ Task.async(fn ->
+ assert_receive {:text, _}, 4_000
+ end)
+
+ Streamer.add_socket(
+ "user",
+ %{transport_pid: task.pid, assigns: %{user: user}}
+ )
+
+ Streamer.stream("user", notify)
+ Task.await(task)
+ end
+
+ test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do
+ task =
+ Task.async(fn ->
+ assert_receive {:text, _}, 4_000
+ end)
+
+ Streamer.add_socket(
+ "user:notification",
+ %{transport_pid: task.pid, assigns: %{user: user}}
+ )
+
+ Streamer.stream("user:notification", notify)
+ Task.await(task)
+ end
+ end
+
test "it sends to public" do
user = insert(:user)
other_user = insert(:user)
@@ -68,6 +124,74 @@ defmodule Pleroma.Web.StreamerTest do
Task.await(task)
end
+ describe "thread_containment" do
+ test "it doesn't send to user if recipients invalid and thread containment is enabled" do
+ Pleroma.Config.put([:instance, :skip_thread_containment], false)
+ author = insert(:user)
+ user = insert(:user, following: [author.ap_id])
+
+ activity =
+ insert(:note_activity,
+ note:
+ insert(:note,
+ user: author,
+ data: %{"to" => ["TEST-FFF"]}
+ )
+ )
+
+ task = Task.async(fn -> refute_receive {:text, _}, 1_000 end)
+ fake_socket = %{transport_pid: task.pid, assigns: %{user: user}}
+ topics = %{"public" => [fake_socket]}
+ Streamer.push_to_socket(topics, "public", activity)
+
+ Task.await(task)
+ end
+
+ test "it sends message if recipients invalid and thread containment is disabled" do
+ Pleroma.Config.put([:instance, :skip_thread_containment], true)
+ author = insert(:user)
+ user = insert(:user, following: [author.ap_id])
+
+ activity =
+ insert(:note_activity,
+ note:
+ insert(:note,
+ user: author,
+ data: %{"to" => ["TEST-FFF"]}
+ )
+ )
+
+ task = Task.async(fn -> assert_receive {:text, _}, 1_000 end)
+ fake_socket = %{transport_pid: task.pid, assigns: %{user: user}}
+ topics = %{"public" => [fake_socket]}
+ Streamer.push_to_socket(topics, "public", activity)
+
+ Task.await(task)
+ end
+
+ test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do
+ Pleroma.Config.put([:instance, :skip_thread_containment], false)
+ author = insert(:user)
+ user = insert(:user, following: [author.ap_id], info: %{skip_thread_containment: true})
+
+ activity =
+ insert(:note_activity,
+ note:
+ insert(:note,
+ user: author,
+ data: %{"to" => ["TEST-FFF"]}
+ )
+ )
+
+ task = Task.async(fn -> assert_receive {:text, _}, 1_000 end)
+ fake_socket = %{transport_pid: task.pid, assigns: %{user: user}}
+ topics = %{"public" => [fake_socket]}
+ Streamer.push_to_socket(topics, "public", activity)
+
+ Task.await(task)
+ end
+ end
+
test "it doesn't send to blocked users" do
user = insert(:user)
blocked_user = insert(:user)
@@ -232,4 +356,110 @@ defmodule Pleroma.Web.StreamerTest do
Task.await(task)
end
+
+ describe "direct streams" do
+ setup do
+ GenServer.start(Streamer, %{}, name: Streamer)
+
+ on_exit(fn ->
+ if pid = Process.whereis(Streamer) do
+ Process.exit(pid, :kill)
+ end
+ end)
+
+ :ok
+ end
+
+ test "it sends conversation update to the 'direct' stream", %{} do
+ user = insert(:user)
+ another_user = insert(:user)
+
+ task =
+ Task.async(fn ->
+ assert_receive {:text, _received_event}, 4_000
+ end)
+
+ Streamer.add_socket(
+ "direct",
+ %{transport_pid: task.pid, assigns: %{user: user}}
+ )
+
+ {:ok, _create_activity} =
+ CommonAPI.post(another_user, %{
+ "status" => "hey @#{user.nickname}",
+ "visibility" => "direct"
+ })
+
+ Task.await(task)
+ end
+
+ test "it doesn't send conversation update to the 'direct' streamj when the last message in the conversation is deleted" do
+ user = insert(:user)
+ another_user = insert(:user)
+
+ {:ok, create_activity} =
+ CommonAPI.post(another_user, %{
+ "status" => "hi @#{user.nickname}",
+ "visibility" => "direct"
+ })
+
+ task =
+ Task.async(fn ->
+ assert_receive {:text, received_event}, 4_000
+ assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
+
+ refute_receive {:text, _}, 4_000
+ end)
+
+ Streamer.add_socket(
+ "direct",
+ %{transport_pid: task.pid, assigns: %{user: user}}
+ )
+
+ {:ok, _} = CommonAPI.delete(create_activity.id, another_user)
+
+ Task.await(task)
+ end
+
+ test "it sends conversation update to the 'direct' stream when a message is deleted" do
+ user = insert(:user)
+ another_user = insert(:user)
+
+ {:ok, create_activity} =
+ CommonAPI.post(another_user, %{
+ "status" => "hi @#{user.nickname}",
+ "visibility" => "direct"
+ })
+
+ {:ok, create_activity2} =
+ CommonAPI.post(another_user, %{
+ "status" => "hi @#{user.nickname}",
+ "in_reply_to_status_id" => create_activity.id,
+ "visibility" => "direct"
+ })
+
+ task =
+ Task.async(fn ->
+ assert_receive {:text, received_event}, 4_000
+ assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
+
+ assert_receive {:text, received_event}, 4_000
+
+ assert %{"event" => "conversation", "payload" => received_payload} =
+ Jason.decode!(received_event)
+
+ assert %{"last_status" => last_status} = Jason.decode!(received_payload)
+ assert last_status["id"] == to_string(create_activity.id)
+ end)
+
+ Streamer.add_socket(
+ "direct",
+ %{transport_pid: task.pid, assigns: %{user: user}}
+ )
+
+ {:ok, _} = CommonAPI.delete(create_activity2.id, another_user)
+
+ Task.await(task)
+ end
+ end
end
diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs
new file mode 100644
index 000000000..3a7246ea8
--- /dev/null
+++ b/test/web/twitter_api/password_controller_test.exs
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.PasswordResetToken
+ alias Pleroma.Web.OAuth.Token
+ import Pleroma.Factory
+
+ describe "GET /api/pleroma/password_reset/token" do
+ test "it returns error when token invalid", %{conn: conn} do
+ response =
+ conn
+ |> get("/api/pleroma/password_reset/token")
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Invalid Token</h2>"
+ end
+
+ test "it shows password reset form", %{conn: conn} do
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+
+ response =
+ conn
+ |> get("/api/pleroma/password_reset/#{token.token}")
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Password Reset for #{user.nickname}</h2>"
+ end
+ end
+
+ describe "POST /api/pleroma/password_reset" do
+ test "it returns HTTP 200", %{conn: conn} do
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+ {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{})
+
+ params = %{
+ "password" => "test",
+ password_confirmation: "test",
+ token: token.token
+ }
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> post("/api/pleroma/password_reset", %{data: params})
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Password changed!</h2>"
+
+ user = refresh_record(user)
+ assert Comeonin.Pbkdf2.checkpw("test", user.password_hash)
+ assert length(Token.get_user_tokens(user)) == 0
+ end
+ end
+end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index e194f14fb..de6177575 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -40,6 +40,18 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
user = refresh_record(user)
assert user.info.banner["type"] == "Image"
end
+
+ test "profile banner can be reset", %{conn: conn} do
+ user = insert(:user)
+
+ conn
+ |> assign(:user, user)
+ |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => ""})
+ |> json_response(200)
+
+ user = refresh_record(user)
+ assert user.info.banner == %{}
+ end
end
describe "POST /api/qvitter/update_background_image" do
@@ -54,6 +66,18 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
user = refresh_record(user)
assert user.info.background["type"] == "Image"
end
+
+ test "background can be reset", %{conn: conn} do
+ user = insert(:user)
+
+ conn
+ |> assign(:user, user)
+ |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => ""})
+ |> json_response(200)
+
+ user = refresh_record(user)
+ assert user.info.background == %{}
+ end
end
describe "POST /api/account/verify_credentials" do
@@ -144,41 +168,25 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
end
test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, false)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], false)
conn
|> get("/api/statuses/public_timeline.json")
|> json_response(403)
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, true)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], true)
end
test "returns 200 to authenticated request when the instance is not public",
%{conn: conn, user: user} do
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, false)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], false)
conn
|> with_credentials(user.nickname, "test")
|> get("/api/statuses/public_timeline.json")
|> json_response(200)
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, true)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], true)
end
test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
@@ -214,41 +222,25 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
setup [:valid_user]
test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, false)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], false)
conn
|> get("/api/statuses/public_and_external_timeline.json")
|> json_response(403)
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, true)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], true)
end
test "returns 200 to authenticated request when the instance is not public",
%{conn: conn, user: user} do
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, false)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], false)
conn
|> with_credentials(user.nickname, "test")
|> get("/api/statuses/public_and_external_timeline.json")
|> json_response(200)
- instance =
- Application.get_env(:pleroma, :instance)
- |> Keyword.put(:public, true)
-
- Application.put_env(:pleroma, :instance, instance)
+ Pleroma.Config.put([:instance, :public], true)
end
test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do
@@ -529,6 +521,38 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
for: current_user
})
end
+
+ test "muted user", %{conn: conn, user: current_user} do
+ other_user = insert(:user)
+
+ {:ok, current_user} = User.mute(current_user, other_user)
+
+ {:ok, _activity} =
+ ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/qvitter/statuses/notifications.json")
+
+ assert json_response(conn, 200) == []
+ end
+
+ test "muted user with with_muted parameter", %{conn: conn, user: current_user} do
+ other_user = insert(:user)
+
+ {:ok, current_user} = User.mute(current_user, other_user)
+
+ {:ok, _activity} =
+ ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/qvitter/statuses/notifications.json", %{"with_muted" => "true"})
+
+ assert length(json_response(conn, 200)) == 1
+ end
end
describe "POST /api/qvitter/statuses/notifications/read" do
@@ -853,6 +877,19 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
assert json_response(conn, 200) ==
UserView.render("show.json", %{user: current_user, for: current_user})
end
+
+ test "user avatar can be reset", %{conn: conn, user: current_user} do
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/qvitter/update_avatar.json", %{img: ""})
+
+ current_user = User.get_cached_by_id(current_user.id)
+ assert current_user.avatar == nil
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: current_user, for: current_user})
+ end
end
describe "GET /api/qvitter/mutes.json" do
@@ -924,7 +961,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
test "with credentials", %{conn: conn, user: current_user} do
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
ActivityPub.like(current_user, object)
conn =
@@ -1527,7 +1564,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
"hide_follows" => "false"
})
- user = Repo.get!(User, user.id)
+ user = refresh_record(user)
assert user.info.hide_follows == false
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
end
@@ -1580,6 +1617,29 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
end
+ test "it sets and un-sets skip_thread_containment", %{conn: conn} do
+ user = insert(:user)
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "true"})
+ |> json_response(200)
+
+ assert response["pleroma"]["skip_thread_containment"] == true
+ user = refresh_record(user)
+ assert user.info.skip_thread_containment
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "false"})
+ |> json_response(200)
+
+ assert response["pleroma"]["skip_thread_containment"] == false
+ refute refresh_record(user).info.skip_thread_containment
+ end
+
test "it locks an account", %{conn: conn} do
user = insert(:user)
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index d601c8f1f..cbe83852e 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
}
{:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
expected_text =
"Hello again, <span class='h-card'><a data-user='#{mentioned_user.id}' class='u-url mention' href='shp'>@<span>shp</span></a></span>.&lt;script&gt;&lt;/script&gt;<br>This is on another :firefox: line. <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a class='hashtag' data-tag='epic' href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a class='hashtag' data-tag='phantasmagoric' href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>"
@@ -91,7 +91,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
}
{:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
input = %{
"status" => "Here's your (you).",
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
}
{:ok, reply = %Activity{}} = TwitterAPI.create_status(user, input)
- reply_object = Object.normalize(reply.data["object"])
+ reply_object = Object.normalize(reply)
assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"])
@@ -116,8 +116,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user, followed, _activity} = TwitterAPI.follow(user, %{"user_id" => followed.id})
assert User.ap_followers(followed) in user.following
- {:error, msg} = TwitterAPI.follow(user, %{"user_id" => followed.id})
- assert msg == "Could not follow user: #{followed.nickname} is already on your list."
+ {:ok, _, _, _} = TwitterAPI.follow(user, %{"user_id" => followed.id})
end
test "Follow another user using screen_name" do
@@ -132,8 +131,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
followed = User.get_cached_by_ap_id(followed.ap_id)
assert followed.info.follower_count == 1
- {:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
- assert msg == "Could not follow user: #{followed.nickname} is already on your list."
+ {:ok, _, _, _} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
end
test "Unfollow another user using user_id" do
@@ -218,7 +216,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
assert ActivityView.render("activity.json", %{activity: updated_activity})["fave_num"] == 1
- object = Object.normalize(note_activity.data["object"])
+ object = Object.normalize(note_activity)
assert object.data["like_count"] == 1
@@ -226,7 +224,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, _status} = TwitterAPI.fav(other_user, note_activity.id)
- object = Object.normalize(note_activity.data["object"])
+ object = Object.normalize(note_activity)
assert object.data["like_count"] == 2
@@ -237,7 +235,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
test "it unfavorites a status, returns the updated activity" do
user = insert(:user)
note_activity = insert(:note_activity)
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+ object = Object.normalize(note_activity)
{:ok, _like_activity, _object} = ActivityPub.like(user, object)
updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 2cd82b3e7..21324399f 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
use Pleroma.Web.ConnCase
@@ -102,7 +106,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn
|> assign(:user, user)
|> put("/api/pleroma/notification_settings", %{
- "remote" => false,
"followers" => false,
"bar" => 1
})
@@ -110,8 +113,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user = Repo.get(User, user.id)
- assert %{"remote" => false, "local" => true, "followers" => false, "follows" => true} ==
- user.info.notification_settings
+ assert %{
+ "followers" => false,
+ "follows" => true,
+ "non_follows" => true,
+ "non_followers" => true
+ } == user.info.notification_settings
end
end
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index 43bd77f78..56d861efb 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -126,7 +126,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
other_user = insert(:user, %{nickname: "shp"})
{:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
result = ActivityView.render("activity.json", activity: activity)
@@ -177,7 +177,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
user = insert(:user)
other_user = insert(:user, %{nickname: "shp"})
{:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
convo_id = Utils.context_to_conversation_id(object.data["context"])
@@ -351,7 +351,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
"is_post_verb" => false,
"statusnet_html" => "deleted notice {{tag",
"text" => "deleted notice {{tag",
- "uri" => delete.data["object"],
+ "uri" => Object.normalize(delete).data["id"],
"user" => UserView.render("show.json", user: user)
}
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 74526673c..70c5a0b7f 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -99,7 +99,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
- "tags" => []
+ "tags" => [],
+ "skip_thread_containment" => false
},
"rights" => %{"admin" => false, "delete_others_notice" => false},
"role" => "member"
@@ -112,9 +113,11 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
as_user = UserView.render("show.json", %{user: user, for: user})
assert as_user["default_scope"] == user.info.default_scope
assert as_user["no_rich_text"] == user.info.no_rich_text
+ assert as_user["pleroma"]["notification_settings"] == user.info.notification_settings
as_stranger = UserView.render("show.json", %{user: user})
refute as_stranger["default_scope"]
refute as_stranger["no_rich_text"]
+ refute as_stranger["pleroma"]["notification_settings"]
end
test "A user for a given other follower", %{user: user} do
@@ -152,7 +155,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
- "tags" => []
+ "tags" => [],
+ "skip_thread_containment" => false
},
"rights" => %{"admin" => false, "delete_others_notice" => false},
"role" => "member"
@@ -197,7 +201,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
- "tags" => []
+ "tags" => [],
+ "skip_thread_containment" => false
},
"rights" => %{"admin" => false, "delete_others_notice" => false},
"role" => "member"
@@ -279,7 +284,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
- "tags" => []
+ "tags" => [],
+ "skip_thread_containment" => false
},
"rights" => %{"admin" => false, "delete_others_notice" => false},
"role" => "member"
diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs
index 43fccfc7a..a14ed3126 100644
--- a/test/web/web_finger/web_finger_controller_test.exs
+++ b/test/web/web_finger/web_finger_controller_test.exs
@@ -10,6 +10,12 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ Pleroma.Config.put(config_path, true)
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
:ok
end
diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs
index 335c95b18..0578b4b8e 100644
--- a/test/web/web_finger/web_finger_test.exs
+++ b/test/web/web_finger/web_finger_test.exs
@@ -104,5 +104,16 @@ defmodule Pleroma.Web.WebFingerTest do
assert template == "http://status.alpicola.com/main/xrd?uri={uri}"
end
+
+ test "it works with idna domains as nickname" do
+ nickname = "lain@" <> to_string(:idna.encode("zetsubou.みんな"))
+
+ {:ok, _data} = WebFinger.finger(nickname)
+ end
+
+ test "it works with idna domains as link" do
+ ap_id = "https://" <> to_string(:idna.encode("zetsubou.みんな")) <> "/users/lain"
+ {:ok, _data} = WebFinger.finger(ap_id)
+ end
end
end
diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs
index f79745d58..aa7262beb 100644
--- a/test/web/websub/websub_controller_test.exs
+++ b/test/web/websub/websub_controller_test.exs
@@ -9,6 +9,16 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do
alias Pleroma.Web.Websub
alias Pleroma.Web.Websub.WebsubClientSubscription
+ setup_all do
+ config_path = [:instance, :federating]
+ initial_setting = Pleroma.Config.get(config_path)
+
+ Pleroma.Config.put(config_path, true)
+ on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
+ :ok
+ end
+
test "websub subscription request", %{conn: conn} do
user = insert(:user)