diff options
Diffstat (limited to 'test/web')
170 files changed, 0 insertions, 38369 deletions
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs deleted file mode 100644 index ed900d8f8..000000000 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ /dev/null @@ -1,1534 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do - use Pleroma.Web.ConnCase - use Oban.Testing, repo: Pleroma.Repo - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.Delivery - alias Pleroma.Instances - alias Pleroma.Object - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.ObjectView - alias Pleroma.Web.ActivityPub.Relay - alias Pleroma.Web.ActivityPub.UserView - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Endpoint - alias Pleroma.Workers.ReceiverWorker - - import Pleroma.Factory - - require Pleroma.Constants - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance, :federating], true) - - describe "/relay" do - setup do: clear_config([:instance, :allow_relay]) - - test "with the relay active, it returns the relay user", %{conn: conn} do - res = - conn - |> get(activity_pub_path(conn, :relay)) - |> json_response(200) - - assert res["id"] =~ "/relay" - end - - test "with the relay disabled, it returns 404", %{conn: conn} do - Config.put([:instance, :allow_relay], false) - - conn - |> get(activity_pub_path(conn, :relay)) - |> json_response(404) - end - - test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) - user = insert(:user) - - conn - |> assign(:user, user) - |> get(activity_pub_path(conn, :relay)) - |> json_response(404) - end - end - - describe "/internal/fetch" do - test "it returns the internal fetch user", %{conn: conn} do - res = - conn - |> get(activity_pub_path(conn, :internal_fetch)) - |> json_response(200) - - assert res["id"] =~ "/fetch" - end - - test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) - user = insert(:user) - - conn - |> assign(:user, user) - |> get(activity_pub_path(conn, :internal_fetch)) - |> json_response(404) - end - end - - describe "/users/:nickname" do - test "it returns a json representation of the user with accept application/json", %{ - conn: conn - } do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/users/#{user.nickname}") - - user = User.get_cached_by_id(user.id) - - assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) - end - - test "it returns a json representation of the user with accept application/activity+json", %{ - conn: conn - } do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}") - - user = User.get_cached_by_id(user.id) - - assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) - end - - test "it returns a json representation of the user with accept application/ld+json", %{ - conn: conn - } do - user = insert(:user) - - conn = - conn - |> put_req_header( - "accept", - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - ) - |> get("/users/#{user.nickname}") - - user = User.get_cached_by_id(user.id) - - assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) - end - - test "it returns 404 for remote users", %{ - conn: conn - } do - user = insert(:user, local: false, nickname: "remoteuser@example.com") - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/users/#{user.nickname}.json") - - assert json_response(conn, 404) - end - - test "it returns error when user is not found", %{conn: conn} do - response = - conn - |> put_req_header("accept", "application/json") - |> get("/users/jimm") - |> json_response(404) - - assert response == "Not found" - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - - conn = - put_req_header( - conn, - "accept", - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - ) - - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}.json", user) - end - end - - describe "mastodon compatibility routes" do - test "it returns a json representation of the object with accept application/json", %{ - conn: conn - } do - {:ok, object} = - %{ - "type" => "Note", - "content" => "hey", - "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", - "actor" => Endpoint.url() <> "/users/raymoo", - "to" => [Pleroma.Constants.as_public()] - } - |> Object.create() - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/users/raymoo/statuses/999999999") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: object}) - end - - test "it returns a json representation of the activity with accept application/json", %{ - conn: conn - } do - {:ok, object} = - %{ - "type" => "Note", - "content" => "hey", - "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", - "actor" => Endpoint.url() <> "/users/raymoo", - "to" => [Pleroma.Constants.as_public()] - } - |> Object.create() - - {:ok, activity, _} = - %{ - "id" => object.data["id"] <> "/activity", - "type" => "Create", - "object" => object.data["id"], - "actor" => object.data["actor"], - "to" => object.data["to"] - } - |> ActivityPub.persist(local: true) - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/users/raymoo/statuses/999999999/activity") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity}) - end - end - - describe "/objects/:uuid" do - test "it returns a json representation of the object with accept application/json", %{ - conn: conn - } do - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/objects/#{uuid}") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note}) - end - - test "it returns a json representation of the object with accept application/activity+json", - %{conn: conn} do - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note}) - end - - test "it returns a json representation of the object with accept application/ld+json", %{ - conn: conn - } do - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header( - "accept", - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - ) - |> get("/objects/#{uuid}") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note}) - end - - test "it returns 404 for non-public messages", %{conn: conn} do - note = insert(:direct_note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn, 404) - end - - test "it returns 404 for tombstone objects", %{conn: conn} do - tombstone = insert(:tombstone) - uuid = String.split(tombstone.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn, 404) - end - - test "it caches a response", %{conn: conn} do - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn1 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn1, :ok) - assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"})) - - conn2 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn1, :ok) == json_response(conn2, :ok) - assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"})) - end - - test "cached purged after object deletion", %{conn: conn} do - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn1 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert json_response(conn1, :ok) - assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"})) - - Object.delete(note) - - conn2 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/objects/#{uuid}") - - assert "Not found" == json_response(conn2, :not_found) - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - note = insert(:note) - uuid = String.split(note.data["id"], "/") |> List.last() - - conn = put_req_header(conn, "accept", "application/activity+json") - - ensure_federating_or_authenticated(conn, "/objects/#{uuid}", user) - end - end - - describe "/activities/:uuid" do - test "it returns a json representation of the activity", %{conn: conn} do - activity = insert(:note_activity) - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity}) - end - - test "it returns 404 for non-public activities", %{conn: conn} do - activity = insert(:direct_note_activity) - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert json_response(conn, 404) - end - - test "it caches a response", %{conn: conn} do - activity = insert(:note_activity) - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn1 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert json_response(conn1, :ok) - assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"})) - - conn2 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert json_response(conn1, :ok) == json_response(conn2, :ok) - assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"})) - end - - test "cached purged after activity deletion", %{conn: conn} do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "cofe"}) - - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn1 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert json_response(conn1, :ok) - assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"})) - - Activity.delete_all_by_object_ap_id(activity.object.data["id"]) - - conn2 = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/activities/#{uuid}") - - assert "Not found" == json_response(conn2, :not_found) - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - activity = insert(:note_activity) - uuid = String.split(activity.data["id"], "/") |> List.last() - - conn = put_req_header(conn, "accept", "application/activity+json") - - ensure_federating_or_authenticated(conn, "/activities/#{uuid}", user) - end - end - - describe "/inbox" do - test "it inserts an incoming activity into the database", %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - @tag capture_log: true - test "it inserts an incoming activity into the database" <> - "even if we can't fetch the user but have it in our db", - %{conn: conn} do - user = - insert(:user, - ap_id: "https://mastodon.example.org/users/raymoo", - ap_enabled: true, - local: false, - last_refreshed_at: nil - ) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("actor", user.ap_id) - |> put_in(["object", "attridbutedTo"], user.ap_id) - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - test "it clears `unreachable` federation status of the sender", %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - - sender_url = data["actor"] - Instances.set_consistently_unreachable(sender_url) - refute Instances.reachable?(sender_url) - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/inbox", data) - - assert "ok" == json_response(conn, 200) - assert Instances.reachable?(sender_url) - end - - test "accept follow activity", %{conn: conn} do - Pleroma.Config.put([:instance, :federating], true) - relay = Relay.get_actor() - - assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor") - - followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor") - relay = refresh_record(relay) - - accept = - File.read!("test/fixtures/relay/accept-follow.json") - |> String.replace("{{ap_id}}", relay.ap_id) - |> String.replace("{{activity_id}}", activity.data["id"]) - - assert "ok" == - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/inbox", accept) - |> json_response(200) - - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - - assert Pleroma.FollowingRelationship.following?( - relay, - followed_relay - ) - - Mix.shell(Mix.Shell.Process) - - on_exit(fn -> - Mix.shell(Mix.Shell.IO) - end) - - :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) - assert_receive {:mix_shell, :info, ["relay.mastodon.host"]} - end - - @tag capture_log: true - test "without valid signature, " <> - "it only accepts Create activities and requires enabled federation", - %{conn: conn} do - data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!() - - conn = put_req_header(conn, "content-type", "application/activity+json") - - Config.put([:instance, :federating], false) - - conn - |> post("/inbox", data) - |> json_response(403) - - conn - |> post("/inbox", non_create_data) - |> json_response(403) - - Config.put([:instance, :federating], true) - - ret_conn = post(conn, "/inbox", data) - assert "ok" == json_response(ret_conn, 200) - - conn - |> post("/inbox", non_create_data) - |> json_response(400) - end - end - - describe "/users/:nickname/inbox" do - setup do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - [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 - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do - user = insert(:user) - - data = - Map.put(data, "to", user.ap_id) - |> Map.delete("cc") - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - test "it accepts messages with cc as string instead of array", %{conn: conn, data: data} do - user = insert(:user) - - data = - Map.put(data, "cc", user.ap_id) - |> Map.delete("to") - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - %Activity{} = activity = Activity.get_by_ap_id(data["id"]) - assert user.ap_id in activity.recipients - end - - test "it accepts messages with bcc as string instead of array", %{conn: conn, data: data} do - user = insert(:user) - - data = - Map.put(data, "bcc", user.ap_id) - |> Map.delete("to") - |> Map.delete("cc") - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - test "it accepts announces with to as string instead of array", %{conn: conn} do - user = insert(:user) - - {:ok, post} = CommonAPI.post(user, %{status: "hey"}) - announcer = insert(:user, local: false) - - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => announcer.ap_id, - "id" => "#{announcer.ap_id}/statuses/19512778738411822/activity", - "object" => post.data["object"], - "to" => "https://www.w3.org/ns/activitystreams#Public", - "cc" => [user.ap_id], - "type" => "Announce" - } - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - %Activity{} = activity = Activity.get_by_ap_id(data["id"]) - assert "https://www.w3.org/ns/activitystreams#Public" in activity.recipients - end - - 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) - - object = - data["object"] - |> Map.put("attributedTo", actor.ap_id) - - data = - data - |> Map.put("actor", actor.ap_id) - |> Map.put("object", object) - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{recipient.nickname}/inbox", data) - - assert "ok" == json_response(conn, 200) - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - assert Activity.get_by_ap_id(data["id"]) - end - - test "it rejects reads from other users", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - conn = - conn - |> assign(:user, other_user) - |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/inbox") - - assert json_response(conn, 403) - end - - 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 = - conn - |> assign(:user, user) - |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/inbox?page=true") - - assert response(conn, 200) =~ note_object.data["content"] - end - - test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do - user = insert(:user) - data = Map.put(data, "bcc", [user.ap_id]) - - sender_host = URI.parse(data["actor"]).host - Instances.set_consistently_unreachable(sender_host) - refute Instances.reachable?(sender_host) - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - 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) - - ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) - - 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 - - test "it requires authentication", %{conn: conn} do - user = insert(:user) - conn = put_req_header(conn, "accept", "application/activity+json") - - ret_conn = get(conn, "/users/#{user.nickname}/inbox") - assert json_response(ret_conn, 403) - - ret_conn = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/inbox") - - assert json_response(ret_conn, 200) - end - end - - describe "GET /users/:nickname/outbox" do - test "it paginates correctly", %{conn: conn} do - user = insert(:user) - conn = assign(conn, :user, user) - outbox_endpoint = user.ap_id <> "/outbox" - - _posts = - for i <- 0..25 do - {:ok, activity} = CommonAPI.post(user, %{status: "post #{i}"}) - activity - end - - result = - conn - |> put_req_header("accept", "application/activity+json") - |> get(outbox_endpoint <> "?page=true") - |> json_response(200) - - result_ids = Enum.map(result["orderedItems"], fn x -> x["id"] end) - assert length(result["orderedItems"]) == 20 - assert length(result_ids) == 20 - assert result["next"] - assert String.starts_with?(result["next"], outbox_endpoint) - - result_next = - conn - |> put_req_header("accept", "application/activity+json") - |> get(result["next"]) - |> json_response(200) - - result_next_ids = Enum.map(result_next["orderedItems"], fn x -> x["id"] end) - assert length(result_next["orderedItems"]) == 6 - assert length(result_next_ids) == 6 - refute Enum.find(result_next_ids, fn x -> x in result_ids end) - refute Enum.find(result_ids, fn x -> x in result_next_ids end) - assert String.starts_with?(result["id"], outbox_endpoint) - - result_next_again = - conn - |> put_req_header("accept", "application/activity+json") - |> get(result_next["id"]) - |> json_response(200) - - assert result_next == result_next_again - end - - test "it returns 200 even if there're no activities", %{conn: conn} do - user = insert(:user) - outbox_endpoint = user.ap_id <> "/outbox" - - conn = - conn - |> assign(:user, user) - |> put_req_header("accept", "application/activity+json") - |> get(outbox_endpoint) - - result = json_response(conn, 200) - assert outbox_endpoint == result["id"] - end - - 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 = - conn - |> assign(:user, user) - |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/outbox?page=true") - - assert response(conn, 200) =~ note_object.data["content"] - end - - test "it returns an announce activity in a collection", %{conn: conn} do - announce_activity = insert(:announce_activity) - user = User.get_cached_by_ap_id(announce_activity.data["actor"]) - - conn = - conn - |> assign(:user, user) - |> put_req_header("accept", "application/activity+json") - |> get("/users/#{user.nickname}/outbox?page=true") - - assert response(conn, 200) =~ announce_activity.data["object"] - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - conn = put_req_header(conn, "accept", "application/activity+json") - - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}/outbox", user) - end - end - - describe "POST /users/:nickname/outbox (C2S)" do - setup do - [ - activity: %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Create", - "object" => %{"type" => "Note", "content" => "AP C2S test"}, - "to" => "https://www.w3.org/ns/activitystreams#Public", - "cc" => [] - } - ] - end - - test "it rejects posts from other users / unauthenticated users", %{ - conn: conn, - activity: activity - } do - user = insert(:user) - other_user = insert(:user) - conn = put_req_header(conn, "content-type", "application/activity+json") - - conn - |> post("/users/#{user.nickname}/outbox", activity) - |> json_response(403) - - conn - |> assign(:user, other_user) - |> post("/users/#{user.nickname}/outbox", activity) - |> json_response(403) - end - - test "it inserts an incoming create activity into the database", %{ - conn: conn, - activity: activity - } do - user = insert(:user) - - result = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", activity) - |> json_response(201) - - assert Activity.get_by_ap_id(result["id"]) - assert result["object"] - assert %Object{data: object} = Object.normalize(result["object"]) - assert object["content"] == activity["object"]["content"] - end - - test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do - user = insert(:user) - - activity = - activity - |> put_in(["object", "type"], "Benis") - - _result = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", activity) - |> json_response(400) - end - - test "it inserts an incoming sensitive activity into the database", %{ - conn: conn, - activity: activity - } do - user = insert(:user) - conn = assign(conn, :user, user) - object = Map.put(activity["object"], "sensitive", true) - activity = Map.put(activity, "object", object) - - response = - conn - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", activity) - |> json_response(201) - - assert Activity.get_by_ap_id(response["id"]) - assert response["object"] - assert %Object{data: response_object} = Object.normalize(response["object"]) - assert response_object["sensitive"] == true - assert response_object["content"] == activity["object"]["content"] - - representation = - conn - |> put_req_header("accept", "application/activity+json") - |> get(response["id"]) - |> json_response(200) - - assert representation["object"]["sensitive"] == true - end - - test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do - user = insert(:user) - activity = Map.put(activity, "type", "BadType") - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", activity) - - assert json_response(conn, 400) - end - - 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_object.data["id"] - } - } - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", data) - - result = json_response(conn, 201) - assert Activity.get_by_ap_id(result["id"]) - - 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_object.data["id"] - } - } - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", data) - - assert json_response(conn, 400) - end - - test "it 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_object.data["id"] - } - } - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/outbox", data) - - result = json_response(conn, 201) - assert Activity.get_by_ap_id(result["id"]) - - assert object = Object.get_by_ap_id(note_object.data["id"]) - assert object.data["like_count"] == 1 - end - - test "it doesn't spreads faulty attributedTo or actor fields", %{ - conn: conn, - activity: activity - } do - reimu = insert(:user, nickname: "reimu") - cirno = insert(:user, nickname: "cirno") - - assert reimu.ap_id - assert cirno.ap_id - - activity = - activity - |> put_in(["object", "actor"], reimu.ap_id) - |> put_in(["object", "attributedTo"], reimu.ap_id) - |> put_in(["actor"], reimu.ap_id) - |> put_in(["attributedTo"], reimu.ap_id) - - _reimu_outbox = - conn - |> assign(:user, cirno) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{reimu.nickname}/outbox", activity) - |> json_response(403) - - cirno_outbox = - conn - |> assign(:user, cirno) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{cirno.nickname}/outbox", activity) - |> json_response(201) - - assert cirno_outbox["attributedTo"] == nil - assert cirno_outbox["actor"] == cirno.ap_id - - assert cirno_object = Object.normalize(cirno_outbox["object"]) - assert cirno_object.data["actor"] == cirno.ap_id - assert cirno_object.data["attributedTo"] == cirno.ap_id - end - end - - describe "/relay/followers" do - test "it returns relay followers", %{conn: conn} do - relay_actor = Relay.get_actor() - user = insert(:user) - User.follow(user, relay_actor) - - result = - conn - |> get("/relay/followers") - |> json_response(200) - - assert result["first"]["orderedItems"] == [user.ap_id] - end - - test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) - user = insert(:user) - - conn - |> assign(:user, user) - |> get("/relay/followers") - |> json_response(404) - end - end - - describe "/relay/following" do - test "it returns relay following", %{conn: conn} do - result = - conn - |> get("/relay/following") - |> json_response(200) - - assert result["first"]["orderedItems"] == [] - end - - test "on non-federating instance, it returns 404", %{conn: conn} do - Config.put([:instance, :federating], false) - user = insert(:user) - - conn - |> assign(:user, user) - |> get("/relay/following") - |> json_response(404) - end - end - - describe "/users/:nickname/followers" do - test "it returns the followers in a collection", %{conn: conn} do - user = insert(:user) - user_two = insert(:user) - User.follow(user, user_two) - - result = - conn - |> assign(:user, user_two) - |> get("/users/#{user_two.nickname}/followers") - |> json_response(200) - - assert result["first"]["orderedItems"] == [user.ap_id] - end - - test "it returns a uri if the user has 'hide_followers' set", %{conn: conn} do - user = insert(:user) - user_two = insert(:user, hide_followers: true) - User.follow(user, user_two) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user_two.nickname}/followers") - |> json_response(200) - - 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 from another user", - %{conn: conn} do - user = insert(:user) - other_user = insert(:user, hide_followers: true) - - result = - conn - |> assign(:user, user) - |> get("/users/#{other_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, 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 - user = insert(:user) - - Enum.each(1..15, fn _ -> - other_user = insert(:user) - User.follow(other_user, user) - end) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/followers") - |> json_response(200) - - assert length(result["first"]["orderedItems"]) == 10 - assert result["first"]["totalItems"] == 15 - assert result["totalItems"] == 15 - - result = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/followers?page=2") - |> json_response(200) - - assert length(result["orderedItems"]) == 5 - assert result["totalItems"] == 15 - end - - test "does not require authentication", %{conn: conn} do - user = insert(:user) - - conn - |> get("/users/#{user.nickname}/followers") - |> json_response(200) - end - end - - describe "/users/:nickname/following" do - test "it returns the following in a collection", %{conn: conn} do - user = insert(:user) - user_two = insert(:user) - User.follow(user, user_two) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/following") - |> json_response(200) - - assert result["first"]["orderedItems"] == [user_two.ap_id] - end - - test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do - user = insert(:user) - user_two = insert(:user, hide_follows: true) - User.follow(user, user_two) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user_two.nickname}/following") - |> json_response(200) - - 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 from another user", - %{conn: conn} do - user = insert(:user) - user_two = insert(:user, hide_follows: true) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user_two.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, 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 - user = insert(:user) - - Enum.each(1..15, fn _ -> - user = User.get_cached_by_id(user.id) - other_user = insert(:user) - User.follow(user, other_user) - end) - - result = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/following") - |> json_response(200) - - assert length(result["first"]["orderedItems"]) == 10 - assert result["first"]["totalItems"] == 15 - assert result["totalItems"] == 15 - - result = - conn - |> assign(:user, user) - |> get("/users/#{user.nickname}/following?page=2") - |> json_response(200) - - assert length(result["orderedItems"]) == 5 - assert result["totalItems"] == 15 - end - - test "does not require authentication", %{conn: conn} do - user = insert(:user) - - conn - |> get("/users/#{user.nickname}/following") - |> json_response(200) - end - end - - describe "delivery tracking" do - test "it tracks a signed object fetch", %{conn: conn} do - user = insert(:user, local: false) - activity = insert(:note_activity) - object = Object.normalize(activity) - - object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) - - conn - |> put_req_header("accept", "application/activity+json") - |> assign(:user, user) - |> get(object_path) - |> json_response(200) - - assert Delivery.get(object.id, user.id) - end - - test "it tracks a signed activity fetch", %{conn: conn} do - user = insert(:user, local: false) - activity = insert(:note_activity) - object = Object.normalize(activity) - - activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) - - conn - |> put_req_header("accept", "application/activity+json") - |> assign(:user, user) - |> get(activity_path) - |> json_response(200) - - assert Delivery.get(object.id, user.id) - end - - test "it tracks a signed object fetch when the json is cached", %{conn: conn} do - user = insert(:user, local: false) - other_user = insert(:user, local: false) - activity = insert(:note_activity) - object = Object.normalize(activity) - - object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) - - conn - |> put_req_header("accept", "application/activity+json") - |> assign(:user, user) - |> get(object_path) - |> json_response(200) - - build_conn() - |> put_req_header("accept", "application/activity+json") - |> assign(:user, other_user) - |> get(object_path) - |> json_response(200) - - assert Delivery.get(object.id, user.id) - assert Delivery.get(object.id, other_user.id) - end - - test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do - user = insert(:user, local: false) - other_user = insert(:user, local: false) - activity = insert(:note_activity) - object = Object.normalize(activity) - - activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) - - conn - |> put_req_header("accept", "application/activity+json") - |> assign(:user, user) - |> get(activity_path) - |> json_response(200) - - build_conn() - |> put_req_header("accept", "application/activity+json") - |> assign(:user, other_user) - |> get(activity_path) - |> json_response(200) - - assert Delivery.get(object.id, user.id) - assert Delivery.get(object.id, other_user.id) - end - end - - describe "Additional ActivityPub C2S endpoints" do - test "GET /api/ap/whoami", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> get("/api/ap/whoami") - - user = User.get_cached_by_id(user.id) - - assert UserView.render("user.json", %{user: user}) == json_response(conn, 200) - - conn - |> get("/api/ap/whoami") - |> json_response(403) - end - - setup do: clear_config([:media_proxy]) - setup do: clear_config([Pleroma.Upload]) - - test "POST /api/ap/upload_media", %{conn: conn} do - user = insert(:user) - - desc = "Description of the image" - - image = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - object = - conn - |> assign(:user, user) - |> post("/api/ap/upload_media", %{"file" => image, "description" => desc}) - |> json_response(:created) - - assert object["name"] == desc - assert object["type"] == "Document" - assert object["actor"] == user.ap_id - assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"] - assert is_binary(object_href) - assert object_mediatype == "image/jpeg" - - activity_request = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Create", - "object" => %{ - "type" => "Note", - "content" => "AP C2S test, attachment", - "attachment" => [object] - }, - "to" => "https://www.w3.org/ns/activitystreams#Public", - "cc" => [] - } - - activity_response = - conn - |> assign(:user, user) - |> post("/users/#{user.nickname}/outbox", activity_request) - |> json_response(:created) - - assert activity_response["id"] - assert activity_response["object"] - assert activity_response["actor"] == user.ap_id - - assert %Object{data: %{"attachment" => [attachment]}} = - Object.normalize(activity_response["object"]) - - assert attachment["type"] == "Document" - assert attachment["name"] == desc - - assert [ - %{ - "href" => ^object_href, - "type" => "Link", - "mediaType" => ^object_mediatype - } - ] = attachment["url"] - - # Fails if unauthenticated - conn - |> post("/api/ap/upload_media", %{"file" => image, "description" => desc}) - |> json_response(403) - end - end -end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs deleted file mode 100644 index d6eab7337..000000000 --- a/test/web/activity_pub/activity_pub_test.exs +++ /dev/null @@ -1,2102 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ActivityPubTest do - use Pleroma.DataCase - use Oban.Testing, repo: Pleroma.Repo - - alias Pleroma.Activity - alias Pleroma.Builders.ActivityBuilder - alias Pleroma.Config - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.CommonAPI - - import ExUnit.CaptureLog - import Mock - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance, :federating]) - - describe "streaming out participations" do - test "it streams them out" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - {:ok, conversation} = Pleroma.Conversation.create_or_bump_for(activity) - - participations = - conversation.participations - |> Repo.preload(:user) - - with_mock Pleroma.Web.Streamer, - stream: fn _, _ -> nil end do - ActivityPub.stream_out_participations(conversation.participations) - - assert called(Pleroma.Web.Streamer.stream("participation", participations)) - end - end - - test "streams them out on activity creation" do - user_one = insert(:user) - user_two = insert(:user) - - with_mock Pleroma.Web.Streamer, - stream: fn _, _ -> nil end do - {:ok, activity} = - CommonAPI.post(user_one, %{ - status: "@#{user_two.nickname}", - visibility: "direct" - }) - - conversation = - activity.data["context"] - |> Pleroma.Conversation.get_for_ap_id() - |> Repo.preload(participations: :user) - - assert called(Pleroma.Web.Streamer.stream("participation", conversation.participations)) - end - end - end - - describe "fetching restricted by visibility" do - test "it restricts by the appropriate visibility" do - user = insert(:user) - - {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - - {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"}) - - {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) - - activities = ActivityPub.fetch_activities([], %{visibility: "direct", actor_id: user.ap_id}) - - assert activities == [direct_activity] - - activities = - ActivityPub.fetch_activities([], %{visibility: "unlisted", actor_id: user.ap_id}) - - assert activities == [unlisted_activity] - - activities = - ActivityPub.fetch_activities([], %{visibility: "private", actor_id: user.ap_id}) - - assert activities == [private_activity] - - activities = ActivityPub.fetch_activities([], %{visibility: "public", actor_id: user.ap_id}) - - assert activities == [public_activity] - - activities = - ActivityPub.fetch_activities([], %{ - visibility: ~w[private public], - actor_id: user.ap_id - }) - - assert activities == [public_activity, private_activity] - end - end - - describe "fetching excluded by visibility" do - test "it excludes by the appropriate visibility" do - user = insert(:user) - - {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - - {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"}) - - {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) - - activities = - ActivityPub.fetch_activities([], %{ - exclude_visibilities: "direct", - actor_id: user.ap_id - }) - - assert public_activity in activities - assert unlisted_activity in activities - assert private_activity in activities - refute direct_activity in activities - - activities = - ActivityPub.fetch_activities([], %{ - exclude_visibilities: "unlisted", - actor_id: user.ap_id - }) - - assert public_activity in activities - refute unlisted_activity in activities - assert private_activity in activities - assert direct_activity in activities - - activities = - ActivityPub.fetch_activities([], %{ - exclude_visibilities: "private", - actor_id: user.ap_id - }) - - assert public_activity in activities - assert unlisted_activity in activities - refute private_activity in activities - assert direct_activity in activities - - activities = - ActivityPub.fetch_activities([], %{ - exclude_visibilities: "public", - actor_id: user.ap_id - }) - - refute public_activity in activities - assert unlisted_activity in activities - assert private_activity in activities - assert direct_activity in activities - end - end - - describe "building a user from his ap id" do - test "it returns a user" do - user_id = "http://mastodon.example.org/users/admin" - {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) - assert user.ap_id == user_id - assert user.nickname == "admin@mastodon.example.org" - assert user.ap_enabled - assert user.follower_address == "http://mastodon.example.org/users/admin/followers" - end - - test "it returns a user that is invisible" do - user_id = "http://mastodon.example.org/users/relay" - {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) - assert User.invisible?(user) - end - - test "it returns a user that accepts chat messages" do - user_id = "http://mastodon.example.org/users/admin" - {:ok, user} = ActivityPub.make_user_from_ap_id(user_id) - - assert user.accepts_chat_messages - end - end - - test "it fetches the appropriate tag-restricted posts" do - user = insert(:user) - - {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"}) - {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"}) - {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"}) - - fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"}) - - fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]}) - - fetch_three = - ActivityPub.fetch_activities([], %{ - type: "Create", - tag: ["test", "essais"], - tag_reject: ["reject"] - }) - - fetch_four = - ActivityPub.fetch_activities([], %{ - type: "Create", - tag: ["test"], - tag_all: ["test", "reject"] - }) - - assert fetch_one == [status_one, status_three] - assert fetch_two == [status_one, status_two, status_three] - assert fetch_three == [status_one, status_two] - assert fetch_four == [status_three] - end - - describe "insertion" do - test "drops activities beyond a certain limit" do - limit = Config.get([:instance, :remote_limit]) - - random_text = - :crypto.strong_rand_bytes(limit + 1) - |> Base.encode64() - |> binary_part(0, limit + 1) - - data = %{ - "ok" => true, - "object" => %{ - "content" => random_text - } - } - - assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data) - end - - test "doesn't drop activities with content being null" do - user = insert(:user) - - data = %{ - "actor" => user.ap_id, - "to" => [], - "object" => %{ - "actor" => user.ap_id, - "to" => [], - "type" => "Note", - "content" => nil - } - } - - assert {:ok, _} = ActivityPub.insert(data) - end - - test "returns the activity if one with the same id is already in" do - activity = insert(:note_activity) - {:ok, new_activity} = ActivityPub.insert(activity.data) - - assert activity.id == new_activity.id - end - - test "inserts a given map into the activity database, giving it an id if it has none." do - user = insert(:user) - - data = %{ - "actor" => user.ap_id, - "to" => [], - "object" => %{ - "actor" => user.ap_id, - "to" => [], - "type" => "Note", - "content" => "hey" - } - } - - {:ok, %Activity{} = activity} = ActivityPub.insert(data) - assert activity.data["ok"] == data["ok"] - assert is_binary(activity.data["id"]) - - given_id = "bla" - - data = %{ - "id" => given_id, - "actor" => user.ap_id, - "to" => [], - "context" => "blabla", - "object" => %{ - "actor" => user.ap_id, - "to" => [], - "type" => "Note", - "content" => "hey" - } - } - - {:ok, %Activity{} = activity} = ActivityPub.insert(data) - assert activity.data["ok"] == data["ok"] - assert activity.data["id"] == given_id - assert activity.data["context"] == "blabla" - assert activity.data["context_id"] - end - - test "adds a context when none is there" do - user = insert(:user) - - data = %{ - "actor" => user.ap_id, - "to" => [], - "object" => %{ - "actor" => user.ap_id, - "to" => [], - "type" => "Note", - "content" => "hey" - } - } - - {:ok, %Activity{} = activity} = ActivityPub.insert(data) - object = Pleroma.Object.normalize(activity) - - assert is_binary(activity.data["context"]) - assert is_binary(object.data["context"]) - assert activity.data["context_id"] - assert object.data["context_id"] - end - - test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do - user = insert(:user) - - data = %{ - "actor" => user.ap_id, - "to" => [], - "object" => %{ - "actor" => user.ap_id, - "to" => [], - "type" => "Note", - "content" => "hey" - } - } - - {:ok, %Activity{} = activity} = ActivityPub.insert(data) - assert object = Object.normalize(activity) - assert is_binary(object.data["id"]) - end - end - - describe "listen activities" do - test "does not increase user note count" do - user = insert(:user) - - {:ok, activity} = - ActivityPub.listen(%{ - to: ["https://www.w3.org/ns/activitystreams#Public"], - actor: user, - context: "", - object: %{ - "actor" => user.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "artist" => "lain", - "title" => "lain radio episode 1", - "length" => 180_000, - "type" => "Audio" - } - }) - - assert activity.actor == user.ap_id - - user = User.get_cached_by_id(user.id) - assert user.note_count == 0 - end - - test "can be fetched into a timeline" do - _listen_activity_1 = insert(:listen) - _listen_activity_2 = insert(:listen) - _listen_activity_3 = insert(:listen) - - timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]}) - - assert length(timeline) == 3 - end - end - - describe "create activities" do - test "it reverts create" do - user = insert(:user) - - with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do - assert {:error, :reverted} = - ActivityPub.create(%{ - to: ["user1", "user2"], - actor: user, - context: "", - object: %{ - "to" => ["user1", "user2"], - "type" => "Note", - "content" => "testing" - } - }) - end - - assert Repo.aggregate(Activity, :count, :id) == 0 - assert Repo.aggregate(Object, :count, :id) == 0 - end - - test "removes doubled 'to' recipients" do - user = insert(:user) - - {:ok, activity} = - ActivityPub.create(%{ - to: ["user1", "user1", "user2"], - actor: user, - context: "", - object: %{ - "to" => ["user1", "user1", "user2"], - "type" => "Note", - "content" => "testing" - } - }) - - assert activity.data["to"] == ["user1", "user2"] - assert activity.actor == user.ap_id - assert activity.recipients == ["user1", "user2", user.ap_id] - end - - test "increases user note count only for public activities" do - user = insert(:user) - - {:ok, _} = - CommonAPI.post(User.get_cached_by_id(user.id), %{ - status: "1", - visibility: "public" - }) - - {:ok, _} = - CommonAPI.post(User.get_cached_by_id(user.id), %{ - status: "2", - visibility: "unlisted" - }) - - {:ok, _} = - CommonAPI.post(User.get_cached_by_id(user.id), %{ - status: "2", - visibility: "private" - }) - - {:ok, _} = - CommonAPI.post(User.get_cached_by_id(user.id), %{ - status: "3", - visibility: "direct" - }) - - user = User.get_cached_by_id(user.id) - assert user.note_count == 2 - end - - test "increases replies count" do - user = insert(:user) - user2 = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"}) - ap_id = activity.data["id"] - reply_data = %{status: "1", in_reply_to_status_id: activity.id} - - # public - {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) - assert object.data["repliesCount"] == 1 - - # unlisted - {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) - assert object.data["repliesCount"] == 2 - - # private - {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) - assert object.data["repliesCount"] == 2 - - # direct - {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct")) - assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) - assert object.data["repliesCount"] == 2 - end - end - - describe "fetch activities for recipients" do - test "retrieve the activities for certain recipients" do - {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]}) - {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]}) - {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]}) - - activities = ActivityPub.fetch_activities(["someone", "someone_else"]) - assert length(activities) == 2 - assert activities == [activity_one, activity_two] - end - end - - describe "fetch activities in context" do - test "retrieves activities that have a given context" do - {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) - {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"}) - {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) - {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"}) - activity_five = insert(:note_activity) - user = insert(:user) - - {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]}) - - activities = ActivityPub.fetch_activities_for_context("2hu", %{blocking_user: user}) - assert activities == [activity_two, activity] - end - - test "doesn't return activities with filtered words" do - user = insert(:user) - user_two = insert(:user) - insert(:filter, user: user, phrase: "test", hide: true) - - {:ok, %{id: id1, data: %{"context" => context}}} = CommonAPI.post(user, %{status: "1"}) - - {:ok, %{id: id2}} = CommonAPI.post(user_two, %{status: "2", in_reply_to_status_id: id1}) - - {:ok, %{id: id3} = user_activity} = - CommonAPI.post(user, %{status: "3 test?", in_reply_to_status_id: id2}) - - {:ok, %{id: id4} = filtered_activity} = - CommonAPI.post(user_two, %{status: "4 test!", in_reply_to_status_id: id3}) - - {:ok, _} = CommonAPI.post(user, %{status: "5", in_reply_to_status_id: id4}) - - activities = - context - |> ActivityPub.fetch_activities_for_context(%{user: user}) - |> Enum.map(& &1.id) - - assert length(activities) == 4 - assert user_activity.id in activities - refute filtered_activity.id in activities - end - end - - test "doesn't return blocked activities" do - activity_one = insert(:note_activity) - activity_two = insert(:note_activity) - activity_three = insert(:note_activity) - user = insert(:user) - booster = insert(:user) - {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]}) - - activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - refute Enum.member?(activities, activity_one) - - {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) - - activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - assert Enum.member?(activities, activity_one) - - {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]}) - {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster) - %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) - activity_three = Activity.get_by_id(activity_three.id) - - activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - refute Enum.member?(activities, activity_three) - refute Enum.member?(activities, boost_activity) - assert Enum.member?(activities, activity_one) - - activities = ActivityPub.fetch_activities([], %{blocking_user: nil, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - assert Enum.member?(activities, boost_activity) - assert Enum.member?(activities, activity_one) - end - - test "doesn't return transitive interactions concerning blocked users" do - blocker = insert(:user) - blockee = insert(:user) - friend = insert(:user) - - {:ok, _user_relationship} = User.block(blocker, blockee) - - {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"}) - - {:ok, activity_two} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"}) - - {:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - - {:ok, activity_four} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"}) - - activities = ActivityPub.fetch_activities([], %{blocking_user: blocker}) - - assert Enum.member?(activities, activity_one) - refute Enum.member?(activities, activity_two) - refute Enum.member?(activities, activity_three) - refute Enum.member?(activities, activity_four) - end - - test "doesn't return announce activities with blocked users in 'to'" do - blocker = insert(:user) - blockee = insert(:user) - friend = insert(:user) - - {:ok, _user_relationship} = User.block(blocker, blockee) - - {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"}) - - {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - - {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend) - - activities = - ActivityPub.fetch_activities([], %{blocking_user: blocker}) - |> Enum.map(fn act -> act.id end) - - assert Enum.member?(activities, activity_one.id) - refute Enum.member?(activities, activity_two.id) - refute Enum.member?(activities, activity_three.id) - end - - test "doesn't return announce activities with blocked users in 'cc'" do - blocker = insert(:user) - blockee = insert(:user) - friend = insert(:user) - - {:ok, _user_relationship} = User.block(blocker, blockee) - - {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"}) - - {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - - assert object = Pleroma.Object.normalize(activity_two) - - data = %{ - "actor" => friend.ap_id, - "object" => object.data["id"], - "context" => object.data["context"], - "type" => "Announce", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [blockee.ap_id] - } - - assert {:ok, activity_three} = ActivityPub.insert(data) - - activities = - ActivityPub.fetch_activities([], %{blocking_user: blocker}) - |> Enum.map(fn act -> act.id end) - - assert Enum.member?(activities, activity_one.id) - refute Enum.member?(activities, activity_two.id) - refute Enum.member?(activities, activity_three.id) - end - - test "doesn't return activities from blocked domains" do - domain = "dogwhistle.zone" - domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"}) - note = insert(:note, %{data: %{"actor" => domain_user.ap_id}}) - activity = insert(:note_activity, %{note: note}) - user = insert(:user) - {:ok, user} = User.block_domain(user, domain) - - activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) - - refute activity in activities - - followed_user = insert(:user) - CommonAPI.follow(user, followed_user) - {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user) - - activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) - - refute repeat_activity in activities - end - - test "does return activities from followed users on blocked domains" do - domain = "meanies.social" - domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"}) - blocker = insert(:user) - - {:ok, blocker} = User.follow(blocker, domain_user) - {:ok, blocker} = User.block_domain(blocker, domain) - - assert User.following?(blocker, domain_user) - assert User.blocks_domain?(blocker, domain_user) - refute User.blocks?(blocker, domain_user) - - note = insert(:note, %{data: %{"actor" => domain_user.ap_id}}) - activity = insert(:note_activity, %{note: note}) - - activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true}) - - assert activity in activities - - # And check that if the guy we DO follow boosts someone else from their domain, - # that should be hidden - another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"}) - bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}}) - bad_activity = insert(:note_activity, %{note: bad_note}) - {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user) - - activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true}) - - refute repeat_activity in activities - end - - test "doesn't return muted activities" do - activity_one = insert(:note_activity) - activity_two = insert(:note_activity) - activity_three = insert(:note_activity) - user = insert(:user) - booster = insert(:user) - - activity_one_actor = User.get_by_ap_id(activity_one.data["actor"]) - {:ok, _user_relationships} = User.mute(user, activity_one_actor) - - activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - refute Enum.member?(activities, activity_one) - - # Calling with 'with_muted' will deliver muted activities, too. - activities = - ActivityPub.fetch_activities([], %{ - muting_user: user, - with_muted: true, - skip_preload: true - }) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - assert Enum.member?(activities, activity_one) - - {:ok, _user_mute} = User.unmute(user, activity_one_actor) - - activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - assert Enum.member?(activities, activity_one) - - activity_three_actor = User.get_by_ap_id(activity_three.data["actor"]) - {:ok, _user_relationships} = User.mute(user, activity_three_actor) - {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster) - %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) - activity_three = Activity.get_by_id(activity_three.id) - - activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - refute Enum.member?(activities, activity_three) - refute Enum.member?(activities, boost_activity) - assert Enum.member?(activities, activity_one) - - activities = ActivityPub.fetch_activities([], %{muting_user: nil, skip_preload: true}) - - assert Enum.member?(activities, activity_two) - assert Enum.member?(activities, activity_three) - assert Enum.member?(activities, boost_activity) - assert Enum.member?(activities, activity_one) - end - - test "doesn't return thread muted activities" do - user = insert(:user) - _activity_one = insert(:note_activity) - note_two = insert(:note, data: %{"context" => "suya.."}) - activity_two = insert(:note_activity, note: note_two) - - {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) - - assert [_activity_one] = ActivityPub.fetch_activities([], %{muting_user: user}) - end - - test "returns thread muted activities when with_muted is set" do - user = insert(:user) - _activity_one = insert(:note_activity) - note_two = insert(:note, data: %{"context" => "suya.."}) - activity_two = insert(:note_activity, note: note_two) - - {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) - - assert [_activity_two, _activity_one] = - ActivityPub.fetch_activities([], %{muting_user: user, with_muted: true}) - end - - test "does include announces on request" do - activity_three = insert(:note_activity) - user = insert(:user) - booster = insert(:user) - - {:ok, user} = User.follow(user, booster) - - {:ok, announce} = CommonAPI.repeat(activity_three.id, booster) - - [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)]) - - assert announce_activity.id == announce.id - end - - test "excludes reblogs on request" do - user = insert(:user) - {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user}) - {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user}) - - [activity] = ActivityPub.fetch_user_activities(user, nil, %{exclude_reblogs: true}) - - assert activity == expected_activity - end - - describe "irreversible filters" do - setup do - user = insert(:user) - user_two = insert(:user) - - insert(:filter, user: user_two, phrase: "cofe", hide: true) - insert(:filter, user: user_two, phrase: "ok boomer", hide: true) - insert(:filter, user: user_two, phrase: "test", hide: false) - - params = %{ - type: ["Create", "Announce"], - user: user_two - } - - {:ok, %{user: user, user_two: user_two, params: params}} - end - - test "it returns statuses if they don't contain exact filter words", %{ - user: user, - params: params - } do - {:ok, _} = CommonAPI.post(user, %{status: "hey"}) - {:ok, _} = CommonAPI.post(user, %{status: "got cofefe?"}) - {:ok, _} = CommonAPI.post(user, %{status: "I am not a boomer"}) - {:ok, _} = CommonAPI.post(user, %{status: "ok boomers"}) - {:ok, _} = CommonAPI.post(user, %{status: "ccofee is not a word"}) - {:ok, _} = CommonAPI.post(user, %{status: "this is a test"}) - - activities = ActivityPub.fetch_activities([], params) - - assert Enum.count(activities) == 6 - end - - test "it does not filter user's own statuses", %{user_two: user_two, params: params} do - {:ok, _} = CommonAPI.post(user_two, %{status: "Give me some cofe!"}) - {:ok, _} = CommonAPI.post(user_two, %{status: "ok boomer"}) - - activities = ActivityPub.fetch_activities([], params) - - assert Enum.count(activities) == 2 - end - - test "it excludes statuses with filter words", %{user: user, params: params} do - {:ok, _} = CommonAPI.post(user, %{status: "Give me some cofe!"}) - {:ok, _} = CommonAPI.post(user, %{status: "ok boomer"}) - {:ok, _} = CommonAPI.post(user, %{status: "is it a cOfE?"}) - {:ok, _} = CommonAPI.post(user, %{status: "cofe is all I need"}) - {:ok, _} = CommonAPI.post(user, %{status: "— ok BOOMER\n"}) - - activities = ActivityPub.fetch_activities([], params) - - assert Enum.empty?(activities) - end - - test "it returns all statuses if user does not have any filters" do - another_user = insert(:user) - {:ok, _} = CommonAPI.post(another_user, %{status: "got cofe?"}) - {:ok, _} = CommonAPI.post(another_user, %{status: "test!"}) - - activities = - ActivityPub.fetch_activities([], %{ - type: ["Create", "Announce"], - user: another_user - }) - - assert Enum.count(activities) == 2 - end - end - - describe "public fetch activities" do - test "doesn't retrieve unlisted activities" do - user = insert(:user) - - {:ok, _unlisted_activity} = CommonAPI.post(user, %{status: "yeah", visibility: "unlisted"}) - - {:ok, listed_activity} = CommonAPI.post(user, %{status: "yeah"}) - - [activity] = ActivityPub.fetch_public_activities() - - assert activity == listed_activity - end - - test "retrieves public activities" do - _activities = ActivityPub.fetch_public_activities() - - %{public: public} = ActivityBuilder.public_and_non_public() - - activities = ActivityPub.fetch_public_activities() - assert length(activities) == 1 - assert Enum.at(activities, 0) == public - end - - test "retrieves a maximum of 20 activities" do - ActivityBuilder.insert_list(10) - expected_activities = ActivityBuilder.insert_list(20) - - activities = ActivityPub.fetch_public_activities() - - assert collect_ids(activities) == collect_ids(expected_activities) - assert length(activities) == 20 - end - - test "retrieves ids starting from a since_id" do - activities = ActivityBuilder.insert_list(30) - expected_activities = ActivityBuilder.insert_list(10) - since_id = List.last(activities).id - - activities = ActivityPub.fetch_public_activities(%{since_id: since_id}) - - assert collect_ids(activities) == collect_ids(expected_activities) - assert length(activities) == 10 - end - - test "retrieves ids up to max_id" do - ActivityBuilder.insert_list(10) - expected_activities = ActivityBuilder.insert_list(20) - - %{id: max_id} = - 10 - |> ActivityBuilder.insert_list() - |> List.first() - - activities = ActivityPub.fetch_public_activities(%{max_id: max_id}) - - assert length(activities) == 20 - assert collect_ids(activities) == collect_ids(expected_activities) - end - - test "paginates via offset/limit" do - _first_part_activities = ActivityBuilder.insert_list(10) - second_part_activities = ActivityBuilder.insert_list(10) - - later_activities = ActivityBuilder.insert_list(10) - - activities = ActivityPub.fetch_public_activities(%{page: "2", page_size: "20"}, :offset) - - assert length(activities) == 20 - - assert collect_ids(activities) == - collect_ids(second_part_activities) ++ collect_ids(later_activities) - end - - test "doesn't return reblogs for users for whom reblogs have been muted" do - activity = insert(:note_activity) - user = insert(:user) - booster = insert(:user) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) - - {:ok, activity} = CommonAPI.repeat(activity.id, booster) - - activities = ActivityPub.fetch_activities([], %{muting_user: user}) - - refute Enum.any?(activities, fn %{id: id} -> id == activity.id end) - end - - test "returns reblogs for users for whom reblogs have not been muted" do - activity = insert(:note_activity) - user = insert(:user) - booster = insert(:user) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) - {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster) - - {:ok, activity} = CommonAPI.repeat(activity.id, booster) - - activities = ActivityPub.fetch_activities([], %{muting_user: user}) - - assert Enum.any?(activities, fn %{id: id} -> id == activity.id end) - end - end - - describe "uploading files" do - test "copies the file to the configured folder" do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, %Object{} = object} = ActivityPub.upload(file) - assert object.data["name"] == "an_image.jpg" - end - - test "works with base64 encoded images" do - file = %{ - img: data_uri() - } - - {:ok, %Object{}} = ActivityPub.upload(file) - end - end - - describe "fetch the latest Follow" do - test "fetches the latest Follow activity" do - %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity) - follower = Repo.get_by(User, ap_id: activity.data["actor"]) - followed = Repo.get_by(User, ap_id: activity.data["object"]) - - assert activity == Utils.fetch_latest_follow(follower, followed) - end - end - - describe "unfollowing" do - test "it reverts unfollow activity" do - follower = insert(:user) - followed = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - - with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do - assert {:error, :reverted} = ActivityPub.unfollow(follower, followed) - end - - activity = Activity.get_by_id(follow_activity.id) - assert activity.data["type"] == "Follow" - assert activity.data["actor"] == follower.ap_id - - assert activity.data["object"] == followed.ap_id - end - - test "creates an undo activity for the last follow" do - follower = insert(:user) - followed = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - {:ok, activity} = ActivityPub.unfollow(follower, followed) - - assert activity.data["type"] == "Undo" - assert activity.data["actor"] == follower.ap_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 - - test "creates an undo activity for a pending follow request" do - follower = insert(:user) - followed = insert(:user, %{locked: true}) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - {:ok, activity} = ActivityPub.unfollow(follower, followed) - - assert activity.data["type"] == "Undo" - assert activity.data["actor"] == follower.ap_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 - - describe "timeline post-processing" do - test "it filters broken threads" do - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - - {:ok, user1} = User.follow(user1, user3) - assert User.following?(user1, user3) - - {:ok, user2} = User.follow(user2, user3) - assert User.following?(user2, user3) - - {:ok, user3} = User.follow(user3, user2) - assert User.following?(user3, user2) - - {:ok, public_activity} = CommonAPI.post(user3, %{status: "hi 1"}) - - {:ok, private_activity_1} = CommonAPI.post(user3, %{status: "hi 2", visibility: "private"}) - - {:ok, private_activity_2} = - CommonAPI.post(user2, %{ - status: "hi 3", - visibility: "private", - in_reply_to_status_id: private_activity_1.id - }) - - {:ok, private_activity_3} = - CommonAPI.post(user3, %{ - status: "hi 4", - visibility: "private", - in_reply_to_status_id: private_activity_2.id - }) - - activities = - ActivityPub.fetch_activities([user1.ap_id | User.following(user1)]) - |> Enum.map(fn a -> a.id end) - - private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"]) - - assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities - - assert length(activities) == 3 - - activities = - ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{user: user1}) - |> Enum.map(fn a -> a.id end) - - assert [public_activity.id, private_activity_1.id] == activities - assert length(activities) == 2 - end - end - - describe "flag/1" do - setup do - reporter = insert(:user) - target_account = insert(:user) - content = "foobar" - {:ok, activity} = CommonAPI.post(target_account, %{status: content}) - context = Utils.generate_context_id() - - reporter_ap_id = reporter.ap_id - target_ap_id = target_account.ap_id - activity_ap_id = activity.data["id"] - - activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id) - - {:ok, - %{ - reporter: reporter, - context: context, - target_account: target_account, - reported_activity: activity, - content: content, - activity_ap_id: activity_ap_id, - activity_with_object: activity_with_object, - reporter_ap_id: reporter_ap_id, - target_ap_id: target_ap_id - }} - end - - test "it can create a Flag activity", - %{ - reporter: reporter, - context: context, - target_account: target_account, - reported_activity: reported_activity, - content: content, - activity_ap_id: activity_ap_id, - activity_with_object: activity_with_object, - reporter_ap_id: reporter_ap_id, - target_ap_id: target_ap_id - } do - assert {:ok, activity} = - ActivityPub.flag(%{ - actor: reporter, - context: context, - account: target_account, - statuses: [reported_activity], - content: content - }) - - note_obj = %{ - "type" => "Note", - "id" => activity_ap_id, - "content" => content, - "published" => activity_with_object.object.data["published"], - "actor" => - AccountView.render("show.json", %{user: target_account, skip_visibility_check: true}) - } - - assert %Activity{ - actor: ^reporter_ap_id, - data: %{ - "type" => "Flag", - "content" => ^content, - "context" => ^context, - "object" => [^target_ap_id, ^note_obj] - } - } = activity - end - - test_with_mock "strips status data from Flag, before federating it", - %{ - reporter: reporter, - context: context, - target_account: target_account, - reported_activity: reported_activity, - content: content - }, - Utils, - [:passthrough], - [] do - {:ok, activity} = - ActivityPub.flag(%{ - actor: reporter, - context: context, - account: target_account, - statuses: [reported_activity], - content: content - }) - - new_data = - put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]]) - - assert_called(Utils.maybe_federate(%{activity | data: new_data})) - 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 - - describe "fetch_follow_information_for_user" do - test "syncronizes following/followers counters" do - user = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/fuser2/followers", - following_address: "http://localhost:4001/users/fuser2/following" - ) - - {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) - assert info.follower_count == 527 - assert info.following_count == 267 - end - - test "detects hidden followers" do - mock(fn env -> - case env.url do - "http://localhost:4001/users/masto_closed/followers?page=1" -> - %Tesla.Env{status: 403, body: ""} - - _ -> - apply(HttpRequestMock, :request, [env]) - end - end) - - user = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/masto_closed/followers", - following_address: "http://localhost:4001/users/masto_closed/following" - ) - - {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) - assert follow_info.hide_followers == true - assert follow_info.hide_follows == false - end - - test "detects hidden follows" do - mock(fn env -> - case env.url do - "http://localhost:4001/users/masto_closed/following?page=1" -> - %Tesla.Env{status: 403, body: ""} - - _ -> - apply(HttpRequestMock, :request, [env]) - end - end) - - user = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/masto_closed/followers", - following_address: "http://localhost:4001/users/masto_closed/following" - ) - - {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) - assert follow_info.hide_followers == false - assert follow_info.hide_follows == true - end - - test "detects hidden follows/followers for friendica" do - user = - insert(:user, - local: false, - follower_address: "http://localhost:8080/followers/fuser3", - following_address: "http://localhost:8080/following/fuser3" - ) - - {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) - assert follow_info.hide_followers == true - assert follow_info.follower_count == 296 - assert follow_info.following_count == 32 - assert follow_info.hide_follows == true - end - - test "doesn't crash when follower and following counters are hidden" do - mock(fn env -> - case env.url do - "http://localhost:4001/users/masto_hidden_counters/following" -> - json(%{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://localhost:4001/users/masto_hidden_counters/followers" - }) - - "http://localhost:4001/users/masto_hidden_counters/following?page=1" -> - %Tesla.Env{status: 403, body: ""} - - "http://localhost:4001/users/masto_hidden_counters/followers" -> - json(%{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://localhost:4001/users/masto_hidden_counters/following" - }) - - "http://localhost:4001/users/masto_hidden_counters/followers?page=1" -> - %Tesla.Env{status: 403, body: ""} - end - end) - - user = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/masto_hidden_counters/followers", - following_address: "http://localhost:4001/users/masto_hidden_counters/following" - ) - - {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) - - assert follow_info.hide_followers == true - assert follow_info.follower_count == 0 - assert follow_info.hide_follows == true - assert follow_info.following_count == 0 - end - end - - describe "fetch_favourites/3" do - test "returns a favourite activities sorted by adds to favorite" do - user = insert(:user) - other_user = insert(:user) - user1 = insert(:user) - user2 = insert(:user) - {:ok, a1} = CommonAPI.post(user1, %{status: "bla"}) - {:ok, _a2} = CommonAPI.post(user2, %{status: "traps are happy"}) - {:ok, a3} = CommonAPI.post(user2, %{status: "Trees Are "}) - {:ok, a4} = CommonAPI.post(user2, %{status: "Agent Smith "}) - {:ok, a5} = CommonAPI.post(user1, %{status: "Red or Blue "}) - - {:ok, _} = CommonAPI.favorite(user, a4.id) - {:ok, _} = CommonAPI.favorite(other_user, a3.id) - {:ok, _} = CommonAPI.favorite(user, a3.id) - {:ok, _} = CommonAPI.favorite(other_user, a5.id) - {:ok, _} = CommonAPI.favorite(user, a5.id) - {:ok, _} = CommonAPI.favorite(other_user, a4.id) - {:ok, _} = CommonAPI.favorite(user, a1.id) - {:ok, _} = CommonAPI.favorite(other_user, a1.id) - result = ActivityPub.fetch_favourites(user) - - assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id] - - result = ActivityPub.fetch_favourites(user, %{limit: 2}) - assert Enum.map(result, & &1.id) == [a1.id, a5.id] - end - end - - describe "Move activity" do - test "create" do - %{ap_id: old_ap_id} = old_user = insert(:user) - %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) - follower = insert(:user) - follower_move_opted_out = insert(:user, allow_following_move: false) - - User.follow(follower, old_user) - User.follow(follower_move_opted_out, old_user) - - assert User.following?(follower, old_user) - assert User.following?(follower_move_opted_out, old_user) - - assert {:ok, activity} = ActivityPub.move(old_user, new_user) - - assert %Activity{ - actor: ^old_ap_id, - data: %{ - "actor" => ^old_ap_id, - "object" => ^old_ap_id, - "target" => ^new_ap_id, - "type" => "Move" - }, - local: true - } = activity - - params = %{ - "op" => "move_following", - "origin_id" => old_user.id, - "target_id" => new_user.id - } - - assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params) - - Pleroma.Workers.BackgroundWorker.perform(%Oban.Job{args: params}) - - refute User.following?(follower, old_user) - assert User.following?(follower, new_user) - - assert User.following?(follower_move_opted_out, old_user) - refute User.following?(follower_move_opted_out, new_user) - - activity = %Activity{activity | object: nil} - - assert [%Notification{activity: ^activity}] = Notification.for_user(follower) - - assert [%Notification{activity: ^activity}] = Notification.for_user(follower_move_opted_out) - end - - test "old user must be in the new user's `also_known_as` list" do - old_user = insert(:user) - new_user = insert(:user) - - assert {:error, "Target account must have the origin in `alsoKnownAs`"} = - ActivityPub.move(old_user, new_user) - end - end - - test "doesn't retrieve replies activities with exclude_replies" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "yeah"}) - - {:ok, _reply} = CommonAPI.post(user, %{status: "yeah", in_reply_to_status_id: activity.id}) - - [result] = ActivityPub.fetch_public_activities(%{exclude_replies: true}) - - assert result.id == activity.id - - assert length(ActivityPub.fetch_public_activities()) == 2 - end - - describe "replies filtering with public messages" do - setup :public_messages - - test "public timeline", %{users: %{u1: user}} do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:reply_filtering_user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert length(activities_ids) == 16 - end - - test "public timeline with reply_visibility `following`", %{ - users: %{u1: user}, - u1: u1, - u2: u2, - u3: u3, - u4: u4, - activities: activities - } do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:reply_visibility, "following") - |> Map.put(:reply_filtering_user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert length(activities_ids) == 14 - - visible_ids = - Map.values(u1) ++ Map.values(u2) ++ Map.values(u4) ++ Map.values(activities) ++ [u3[:r1]] - - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - - test "public timeline with reply_visibility `self`", %{ - users: %{u1: user}, - u1: u1, - u2: u2, - u3: u3, - u4: u4, - activities: activities - } do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:reply_visibility, "self") - |> Map.put(:reply_filtering_user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert length(activities_ids) == 10 - visible_ids = Map.values(u1) ++ [u2[:r1], u3[:r1], u4[:r1]] ++ Map.values(activities) - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - - test "home timeline", %{ - users: %{u1: user}, - activities: activities, - u1: u1, - u2: u2, - u3: u3, - u4: u4 - } do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> Map.put(:reply_filtering_user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 13 - - visible_ids = - Map.values(u1) ++ - Map.values(u3) ++ - [ - activities[:a1], - activities[:a2], - activities[:a4], - u2[:r1], - u2[:r3], - u4[:r1], - u4[:r2] - ] - - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - - test "home timeline with reply_visibility `following`", %{ - users: %{u1: user}, - activities: activities, - u1: u1, - u2: u2, - u3: u3, - u4: u4 - } do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> Map.put(:reply_visibility, "following") - |> Map.put(:reply_filtering_user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 11 - - visible_ids = - Map.values(u1) ++ - [ - activities[:a1], - activities[:a2], - activities[:a4], - u2[:r1], - u2[:r3], - u3[:r1], - u4[:r1], - u4[:r2] - ] - - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - - test "home timeline with reply_visibility `self`", %{ - users: %{u1: user}, - activities: activities, - u1: u1, - u2: u2, - u3: u3, - u4: u4 - } do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> Map.put(:reply_visibility, "self") - |> Map.put(:reply_filtering_user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 9 - - visible_ids = - Map.values(u1) ++ - [ - activities[:a1], - activities[:a2], - activities[:a4], - u2[:r1], - u3[:r1], - u4[:r1] - ] - - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - - test "filtering out announces where the user is the actor of the announced message" do - user = insert(:user) - other_user = insert(:user) - third_user = insert(:user) - User.follow(user, other_user) - - {:ok, post} = CommonAPI.post(user, %{status: "yo"}) - {:ok, other_post} = CommonAPI.post(third_user, %{status: "yo"}) - {:ok, _announce} = CommonAPI.repeat(post.id, other_user) - {:ok, _announce} = CommonAPI.repeat(post.id, third_user) - {:ok, announce} = CommonAPI.repeat(other_post.id, other_user) - - params = %{ - type: ["Announce"] - } - - results = - [user.ap_id | User.following(user)] - |> ActivityPub.fetch_activities(params) - - assert length(results) == 3 - - params = %{ - type: ["Announce"], - announce_filtering_user: user - } - - [result] = - [user.ap_id | User.following(user)] - |> ActivityPub.fetch_activities(params) - - assert result.id == announce.id - end - end - - describe "replies filtering with private messages" do - setup :private_messages - - test "public timeline", %{users: %{u1: user}} do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert activities_ids == [] - end - - test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:reply_visibility, "following") - |> Map.put(:reply_filtering_user, user) - |> Map.put(:user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert activities_ids == [] - end - - test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do - activities_ids = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:local_only, false) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:reply_visibility, "self") - |> Map.put(:reply_filtering_user, user) - |> Map.put(:user, user) - |> ActivityPub.fetch_public_activities() - |> Enum.map(& &1.id) - - assert activities_ids == [] - end - - test "home timeline", %{users: %{u1: user}} do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 12 - end - - test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> Map.put(:reply_visibility, "following") - |> Map.put(:reply_filtering_user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 12 - end - - test "home timeline with default reply_visibility `self`", %{ - users: %{u1: user}, - activities: activities, - u1: u1, - u2: u2, - u3: u3, - u4: u4 - } do - params = - %{} - |> Map.put(:type, ["Create", "Announce"]) - |> Map.put(:blocking_user, user) - |> Map.put(:muting_user, user) - |> Map.put(:user, user) - |> Map.put(:reply_visibility, "self") - |> Map.put(:reply_filtering_user, user) - - activities_ids = - ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) - |> Enum.map(& &1.id) - - assert length(activities_ids) == 10 - - visible_ids = - Map.values(u1) ++ Map.values(u4) ++ [u2[:r1], u3[:r1]] ++ Map.values(activities) - - assert Enum.all?(visible_ids, &(&1 in activities_ids)) - end - end - - defp public_messages(_) do - [u1, u2, u3, u4] = insert_list(4, :user) - {:ok, u1} = User.follow(u1, u2) - {:ok, u2} = User.follow(u2, u1) - {:ok, u1} = User.follow(u1, u4) - {:ok, u4} = User.follow(u4, u1) - - {:ok, u2} = User.follow(u2, u3) - {:ok, u3} = User.follow(u3, u2) - - {:ok, a1} = CommonAPI.post(u1, %{status: "Status"}) - - {:ok, r1_1} = - CommonAPI.post(u2, %{ - status: "@#{u1.nickname} reply from u2 to u1", - in_reply_to_status_id: a1.id - }) - - {:ok, r1_2} = - CommonAPI.post(u3, %{ - status: "@#{u1.nickname} reply from u3 to u1", - in_reply_to_status_id: a1.id - }) - - {:ok, r1_3} = - CommonAPI.post(u4, %{ - status: "@#{u1.nickname} reply from u4 to u1", - in_reply_to_status_id: a1.id - }) - - {:ok, a2} = CommonAPI.post(u2, %{status: "Status"}) - - {:ok, r2_1} = - CommonAPI.post(u1, %{ - status: "@#{u2.nickname} reply from u1 to u2", - in_reply_to_status_id: a2.id - }) - - {:ok, r2_2} = - CommonAPI.post(u3, %{ - status: "@#{u2.nickname} reply from u3 to u2", - in_reply_to_status_id: a2.id - }) - - {:ok, r2_3} = - CommonAPI.post(u4, %{ - status: "@#{u2.nickname} reply from u4 to u2", - in_reply_to_status_id: a2.id - }) - - {:ok, a3} = CommonAPI.post(u3, %{status: "Status"}) - - {:ok, r3_1} = - CommonAPI.post(u1, %{ - status: "@#{u3.nickname} reply from u1 to u3", - in_reply_to_status_id: a3.id - }) - - {:ok, r3_2} = - CommonAPI.post(u2, %{ - status: "@#{u3.nickname} reply from u2 to u3", - in_reply_to_status_id: a3.id - }) - - {:ok, r3_3} = - CommonAPI.post(u4, %{ - status: "@#{u3.nickname} reply from u4 to u3", - in_reply_to_status_id: a3.id - }) - - {:ok, a4} = CommonAPI.post(u4, %{status: "Status"}) - - {:ok, r4_1} = - CommonAPI.post(u1, %{ - status: "@#{u4.nickname} reply from u1 to u4", - in_reply_to_status_id: a4.id - }) - - {:ok, r4_2} = - CommonAPI.post(u2, %{ - status: "@#{u4.nickname} reply from u2 to u4", - in_reply_to_status_id: a4.id - }) - - {:ok, r4_3} = - CommonAPI.post(u3, %{ - status: "@#{u4.nickname} reply from u3 to u4", - in_reply_to_status_id: a4.id - }) - - {:ok, - users: %{u1: u1, u2: u2, u3: u3, u4: u4}, - activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id}, - u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id}, - u2: %{r1: r2_1.id, r2: r2_2.id, r3: r2_3.id}, - u3: %{r1: r3_1.id, r2: r3_2.id, r3: r3_3.id}, - u4: %{r1: r4_1.id, r2: r4_2.id, r3: r4_3.id}} - end - - defp private_messages(_) do - [u1, u2, u3, u4] = insert_list(4, :user) - {:ok, u1} = User.follow(u1, u2) - {:ok, u2} = User.follow(u2, u1) - {:ok, u1} = User.follow(u1, u3) - {:ok, u3} = User.follow(u3, u1) - {:ok, u1} = User.follow(u1, u4) - {:ok, u4} = User.follow(u4, u1) - - {:ok, u2} = User.follow(u2, u3) - {:ok, u3} = User.follow(u3, u2) - - {:ok, a1} = CommonAPI.post(u1, %{status: "Status", visibility: "private"}) - - {:ok, r1_1} = - CommonAPI.post(u2, %{ - status: "@#{u1.nickname} reply from u2 to u1", - in_reply_to_status_id: a1.id, - visibility: "private" - }) - - {:ok, r1_2} = - CommonAPI.post(u3, %{ - status: "@#{u1.nickname} reply from u3 to u1", - in_reply_to_status_id: a1.id, - visibility: "private" - }) - - {:ok, r1_3} = - CommonAPI.post(u4, %{ - status: "@#{u1.nickname} reply from u4 to u1", - in_reply_to_status_id: a1.id, - visibility: "private" - }) - - {:ok, a2} = CommonAPI.post(u2, %{status: "Status", visibility: "private"}) - - {:ok, r2_1} = - CommonAPI.post(u1, %{ - status: "@#{u2.nickname} reply from u1 to u2", - in_reply_to_status_id: a2.id, - visibility: "private" - }) - - {:ok, r2_2} = - CommonAPI.post(u3, %{ - status: "@#{u2.nickname} reply from u3 to u2", - in_reply_to_status_id: a2.id, - visibility: "private" - }) - - {:ok, a3} = CommonAPI.post(u3, %{status: "Status", visibility: "private"}) - - {:ok, r3_1} = - CommonAPI.post(u1, %{ - status: "@#{u3.nickname} reply from u1 to u3", - in_reply_to_status_id: a3.id, - visibility: "private" - }) - - {:ok, r3_2} = - CommonAPI.post(u2, %{ - status: "@#{u3.nickname} reply from u2 to u3", - in_reply_to_status_id: a3.id, - visibility: "private" - }) - - {:ok, a4} = CommonAPI.post(u4, %{status: "Status", visibility: "private"}) - - {:ok, r4_1} = - CommonAPI.post(u1, %{ - status: "@#{u4.nickname} reply from u1 to u4", - in_reply_to_status_id: a4.id, - visibility: "private" - }) - - {:ok, - users: %{u1: u1, u2: u2, u3: u3, u4: u4}, - activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id}, - u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id}, - u2: %{r1: r2_1.id, r2: r2_2.id}, - u3: %{r1: r3_1.id, r2: r3_2.id}, - u4: %{r1: r4_1.id}} - end - - describe "maybe_update_follow_information/1" do - setup do - clear_config([:instance, :external_user_synchronization], true) - - user = %{ - local: false, - ap_id: "https://gensokyo.2hu/users/raymoo", - following_address: "https://gensokyo.2hu/users/following", - follower_address: "https://gensokyo.2hu/users/followers", - type: "Person" - } - - %{user: user} - end - - test "logs an error when it can't fetch the info", %{user: user} do - assert capture_log(fn -> - ActivityPub.maybe_update_follow_information(user) - end) =~ "Follower/Following counter update for #{user.ap_id} failed" - end - - test "just returns the input if the user type is Application", %{ - user: user - } do - user = - user - |> Map.put(:type, "Application") - - refute capture_log(fn -> - assert ^user = ActivityPub.maybe_update_follow_information(user) - end) =~ "Follower/Following counter update for #{user.ap_id} failed" - end - - test "it just returns the input if the user has no following/follower addresses", %{ - user: user - } do - user = - user - |> Map.put(:following_address, nil) - |> Map.put(:follower_address, nil) - - refute capture_log(fn -> - assert ^user = ActivityPub.maybe_update_follow_information(user) - end) =~ "Follower/Following counter update for #{user.ap_id} failed" - end - end - - describe "global activity expiration" do - setup do: clear_config([:mrf, :policies]) - - test "creates an activity expiration for local Create activities" do - Pleroma.Config.put( - [:mrf, :policies], - Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy - ) - - {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) - {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"}) - - assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all() - end - end - - describe "handling of clashing nicknames" do - test "renames an existing user with a clashing nickname and a different ap id" do - orig_user = - insert( - :user, - local: false, - nickname: "admin@mastodon.example.org", - ap_id: "http://mastodon.example.org/users/harinezumigari" - ) - - %{ - nickname: orig_user.nickname, - ap_id: orig_user.ap_id <> "part_2" - } - |> ActivityPub.maybe_handle_clashing_nickname() - - user = User.get_by_id(orig_user.id) - - assert user.nickname == "#{orig_user.id}.admin@mastodon.example.org" - end - - test "does nothing with a clashing nickname and the same ap id" do - orig_user = - insert( - :user, - local: false, - nickname: "admin@mastodon.example.org", - ap_id: "http://mastodon.example.org/users/harinezumigari" - ) - - %{ - nickname: orig_user.nickname, - ap_id: orig_user.ap_id - } - |> ActivityPub.maybe_handle_clashing_nickname() - - user = User.get_by_id(orig_user.id) - - assert user.nickname == orig_user.nickname - end - end -end diff --git a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/web/activity_pub/mrf/activity_expiration_policy_test.exs deleted file mode 100644 index 8babf49e7..000000000 --- a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs +++ /dev/null @@ -1,77 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do - use ExUnit.Case, async: true - alias Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy - - @id Pleroma.Web.Endpoint.url() <> "/activities/cofe" - - test "adds `expires_at` property" do - assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = - ActivityExpirationPolicy.filter(%{ - "id" => @id, - "type" => "Create", - "object" => %{"type" => "Note"} - }) - - assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 - end - - test "keeps existing `expires_at` if it less than the config setting" do - expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: 1) - - assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} = - ActivityExpirationPolicy.filter(%{ - "id" => @id, - "type" => "Create", - "expires_at" => expires_at, - "object" => %{"type" => "Note"} - }) - end - - test "overwrites existing `expires_at` if it greater than the config setting" do - too_distant_future = NaiveDateTime.utc_now() |> Timex.shift(years: 2) - - assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = - ActivityExpirationPolicy.filter(%{ - "id" => @id, - "type" => "Create", - "expires_at" => too_distant_future, - "object" => %{"type" => "Note"} - }) - - assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 - end - - test "ignores remote activities" do - assert {:ok, activity} = - ActivityExpirationPolicy.filter(%{ - "id" => "https://example.com/123", - "type" => "Create", - "object" => %{"type" => "Note"} - }) - - refute Map.has_key?(activity, "expires_at") - end - - test "ignores non-Create/Note activities" do - assert {:ok, activity} = - ActivityExpirationPolicy.filter(%{ - "id" => "https://example.com/123", - "type" => "Follow" - }) - - refute Map.has_key?(activity, "expires_at") - - assert {:ok, activity} = - ActivityExpirationPolicy.filter(%{ - "id" => "https://example.com/123", - "type" => "Create", - "object" => %{"type" => "Cofe"} - }) - - refute Map.has_key?(activity, "expires_at") - end -end diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs deleted file mode 100644 index 3c795f5ac..000000000 --- a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs +++ /dev/null @@ -1,72 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do - use Pleroma.DataCase - import Pleroma.Factory - - alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy - - describe "blocking based on attributes" do - test "matches followbots by nickname" do - actor = insert(:user, %{nickname: "followbot@example.com"}) - target = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Follow", - "actor" => actor.ap_id, - "object" => target.ap_id, - "id" => "https://example.com/activities/1234" - } - - assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) - end - - test "matches followbots by display name" do - actor = insert(:user, %{name: "Federation Bot"}) - target = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Follow", - "actor" => actor.ap_id, - "object" => target.ap_id, - "id" => "https://example.com/activities/1234" - } - - assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) - end - end - - test "it allows non-followbots" do - actor = insert(:user) - target = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Follow", - "actor" => actor.ap_id, - "object" => target.ap_id, - "id" => "https://example.com/activities/1234" - } - - {:ok, _} = AntiFollowbotPolicy.filter(message) - end - - test "it gracefully handles nil display names" do - actor = insert(:user, %{name: nil}) - target = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Follow", - "actor" => actor.ap_id, - "object" => target.ap_id, - "id" => "https://example.com/activities/1234" - } - - {:ok, _} = AntiFollowbotPolicy.filter(message) - 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 deleted file mode 100644 index 6867c9853..000000000 --- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ /dev/null @@ -1,166 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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, local: false) - - assert user.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, local: false) - - assert user.note_count == 0 - - message = - @linkful_message - |> Map.put("actor", user.ap_id) - - {:reject, _} = AntiLinkSpamPolicy.filter(message) - end - - test "it allows posts with links for local users" do - user = insert(:user) - - assert user.note_count == 0 - - message = - @linkful_message - |> Map.put("actor", user.ap_id) - - {:ok, _message} = AntiLinkSpamPolicy.filter(message) - end - end - - describe "with old user" do - test "it allows posts without links" do - user = insert(:user, note_count: 1) - - assert user.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, note_count: 1) - - assert user.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, follower_count: 1) - - assert user.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, follower_count: 1) - - assert user.follower_count == 1 - - message = - @linkful_message - |> Map.put("actor", user.ap_id) - - {:ok, _message} = AntiLinkSpamPolicy.filter(message) - end - end - - describe "with unknown actors" do - setup do - Tesla.Mock.mock(fn - %{method: :get, url: "http://invalid.actor"} -> - %Tesla.Env{status: 500, body: ""} - end) - - :ok - end - - 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, 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 deleted file mode 100644 index 38ddec5bb..000000000 --- a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs +++ /dev/null @@ -1,82 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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/hellthread_policy_test.exs b/test/web/activity_pub/mrf/hellthread_policy_test.exs deleted file mode 100644 index 26f5bcdaa..000000000 --- a/test/web/activity_pub/mrf/hellthread_policy_test.exs +++ /dev/null @@ -1,92 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do - use Pleroma.DataCase - import Pleroma.Factory - - import Pleroma.Web.ActivityPub.MRF.HellthreadPolicy - - alias Pleroma.Web.CommonAPI - - setup do - user = insert(:user) - - message = %{ - "actor" => user.ap_id, - "cc" => [user.follower_address], - "type" => "Create", - "to" => [ - "https://www.w3.org/ns/activitystreams#Public", - "https://instance.tld/users/user1", - "https://instance.tld/users/user2", - "https://instance.tld/users/user3" - ], - "object" => %{ - "type" => "Note" - } - } - - [user: user, message: message] - end - - setup do: clear_config(:mrf_hellthread) - - test "doesn't die on chat messages" do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) - - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post_chat_message(user, other_user, "moin") - - assert {:ok, _} = filter(activity.data) - end - - describe "reject" do - test "rejects the message if the recipient count is above reject_threshold", %{ - message: message - } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2}) - - assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} == - filter(message) - end - - test "does not reject the message if the recipient count is below reject_threshold", %{ - message: message - } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) - - assert {:ok, ^message} = filter(message) - end - end - - describe "delist" do - test "delists the message if the recipient count is above delist_threshold", %{ - user: user, - message: message - } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) - - {:ok, message} = filter(message) - assert user.follower_address in message["to"] - assert "https://www.w3.org/ns/activitystreams#Public" in message["cc"] - end - - test "does not delist the message if the recipient count is below delist_threshold", %{ - message: message - } do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0}) - - assert {:ok, ^message} = filter(message) - end - end - - test "excludes follower collection and public URI from threshold count", %{message: message} do - Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3}) - - assert {:ok, ^message} = filter(message) - end -end diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/web/activity_pub/mrf/keyword_policy_test.exs deleted file mode 100644 index b3d0f3d90..000000000 --- a/test/web/activity_pub/mrf/keyword_policy_test.exs +++ /dev/null @@ -1,225 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy - - setup do: clear_config(:mrf_keyword) - - setup do - Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []}) - end - - describe "rejecting based on keywords" do - test "rejects if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :reject], ["pun"]) - - message = %{ - "type" => "Create", - "object" => %{ - "content" => "just a daily reminder that compLAINer is a good pun", - "summary" => "" - } - } - - assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} = - KeywordPolicy.filter(message) - end - - test "rejects if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :reject], ["pun"]) - - message = %{ - "type" => "Create", - "object" => %{ - "summary" => "just a daily reminder that compLAINer is a good pun", - "content" => "" - } - } - - assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} = - KeywordPolicy.filter(message) - end - - test "rejects if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) - - assert true == - Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> - message = %{ - "type" => "Create", - "object" => %{ - "content" => "just a daily reminder that #{content} is a good pun", - "summary" => "" - } - } - - {:reject, "[KeywordPolicy] Matches with rejected keyword"} == - KeywordPolicy.filter(message) - end) - end - - test "rejects if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/]) - - assert true == - Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> - message = %{ - "type" => "Create", - "object" => %{ - "summary" => "just a daily reminder that #{content} is a good pun", - "content" => "" - } - } - - {:reject, "[KeywordPolicy] Matches with rejected keyword"} == - KeywordPolicy.filter(message) - end) - end - end - - describe "delisting from ftl based on keywords" do - test "delists if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"]) - - message = %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "content" => "just a daily reminder that compLAINer is a good pun", - "summary" => "" - } - } - - {:ok, result} = KeywordPolicy.filter(message) - assert ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] - refute ["https://www.w3.org/ns/activitystreams#Public"] == result["to"] - end - - test "delists if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"]) - - message = %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Create", - "object" => %{ - "summary" => "just a daily reminder that compLAINer is a good pun", - "content" => "" - } - } - - {:ok, result} = KeywordPolicy.filter(message) - assert ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] - refute ["https://www.w3.org/ns/activitystreams#Public"] == result["to"] - end - - test "delists if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) - - assert true == - Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{ - "content" => "just a daily reminder that #{content} is a good pun", - "summary" => "" - } - } - - {:ok, result} = KeywordPolicy.filter(message) - - ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] and - not (["https://www.w3.org/ns/activitystreams#Public"] == result["to"]) - end) - end - - test "delists if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/]) - - assert true == - Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content -> - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{ - "summary" => "just a daily reminder that #{content} is a good pun", - "content" => "" - } - } - - {:ok, result} = KeywordPolicy.filter(message) - - ["https://www.w3.org/ns/activitystreams#Public"] == result["cc"] and - not (["https://www.w3.org/ns/activitystreams#Public"] == result["to"]) - end) - end - end - - describe "replacing keywords" do - test "replaces keyword if string matches in content" do - Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}]) - - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{"content" => "ZFS is opensource", "summary" => ""} - } - - {:ok, %{"object" => %{"content" => result}}} = KeywordPolicy.filter(message) - assert result == "ZFS is free software" - end - - test "replaces keyword if string matches in summary" do - Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}]) - - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{"summary" => "ZFS is opensource", "content" => ""} - } - - {:ok, %{"object" => %{"summary" => result}}} = KeywordPolicy.filter(message) - assert result == "ZFS is free software" - end - - test "replaces keyword if regex matches in content" do - Pleroma.Config.put([:mrf_keyword, :replace], [ - {~r/open(-|\s)?source\s?(software)?/, "free software"} - ]) - - assert true == - Enum.all?(["opensource", "open-source", "open source"], fn content -> - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{"content" => "ZFS is #{content}", "summary" => ""} - } - - {:ok, %{"object" => %{"content" => result}}} = KeywordPolicy.filter(message) - result == "ZFS is free software" - end) - end - - test "replaces keyword if regex matches in summary" do - Pleroma.Config.put([:mrf_keyword, :replace], [ - {~r/open(-|\s)?source\s?(software)?/, "free software"} - ]) - - assert true == - Enum.all?(["opensource", "open-source", "open source"], fn content -> - message = %{ - "type" => "Create", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => %{"summary" => "ZFS is #{content}", "content" => ""} - } - - {:ok, %{"object" => %{"summary" => result}}} = KeywordPolicy.filter(message) - result == "ZFS is free software" - end) - 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 deleted file mode 100644 index 313d59a66..000000000 --- a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs +++ /dev/null @@ -1,51 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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.Tests.ObanHelpers - 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) - - ObanHelpers.perform_all() - # Performing jobs which has been just enqueued - ObanHelpers.perform_all() - - 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/mention_policy_test.exs b/test/web/activity_pub/mrf/mention_policy_test.exs deleted file mode 100644 index 220309cc9..000000000 --- a/test/web/activity_pub/mrf/mention_policy_test.exs +++ /dev/null @@ -1,96 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.MRF.MentionPolicy - - setup do: clear_config(:mrf_mention) - - test "pass filter if allow list is empty" do - Pleroma.Config.delete([:mrf_mention]) - - message = %{ - "type" => "Create", - "to" => ["https://example.com/ok"], - "cc" => ["https://example.com/blocked"] - } - - assert MentionPolicy.filter(message) == {:ok, message} - end - - describe "allow" do - test "empty" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create" - } - - assert MentionPolicy.filter(message) == {:ok, message} - end - - test "to" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create", - "to" => ["https://example.com/ok"] - } - - assert MentionPolicy.filter(message) == {:ok, message} - end - - test "cc" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create", - "cc" => ["https://example.com/ok"] - } - - assert MentionPolicy.filter(message) == {:ok, message} - end - - test "both" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create", - "to" => ["https://example.com/ok"], - "cc" => ["https://example.com/ok2"] - } - - assert MentionPolicy.filter(message) == {:ok, message} - end - end - - describe "deny" do - test "to" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create", - "to" => ["https://example.com/blocked"] - } - - assert MentionPolicy.filter(message) == - {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} - end - - test "cc" do - Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]}) - - message = %{ - "type" => "Create", - "to" => ["https://example.com/ok"], - "cc" => ["https://example.com/blocked"] - } - - assert MentionPolicy.filter(message) == - {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"} - end - end -end diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/web/activity_pub/mrf/mrf_test.exs deleted file mode 100644 index a63b25423..000000000 --- a/test/web/activity_pub/mrf/mrf_test.exs +++ /dev/null @@ -1,84 +0,0 @@ -defmodule Pleroma.Web.ActivityPub.MRFTest do - use ExUnit.Case, async: true - use Pleroma.Tests.Helpers - alias Pleroma.Web.ActivityPub.MRF - - test "subdomains_regex/1" do - assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [ - ~r/^unsafe.tld$/i, - ~r/^(.*\.)*unsafe.tld$/i - ] - end - - describe "subdomain_match/2" do - test "common domains" do - regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"]) - - assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i] - - assert MRF.subdomain_match?(regexes, "unsafe.tld") - assert MRF.subdomain_match?(regexes, "unsafe2.tld") - - refute MRF.subdomain_match?(regexes, "example.com") - end - - test "wildcard domains with one subdomain" do - regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - - assert regexes == [~r/^(.*\.)*unsafe.tld$/i] - - assert MRF.subdomain_match?(regexes, "unsafe.tld") - assert MRF.subdomain_match?(regexes, "sub.unsafe.tld") - refute MRF.subdomain_match?(regexes, "anotherunsafe.tld") - refute MRF.subdomain_match?(regexes, "unsafe.tldanother") - end - - test "wildcard domains with two subdomains" do - regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - - assert regexes == [~r/^(.*\.)*unsafe.tld$/i] - - assert MRF.subdomain_match?(regexes, "unsafe.tld") - assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld") - refute MRF.subdomain_match?(regexes, "sub.anotherunsafe.tld") - refute MRF.subdomain_match?(regexes, "sub.unsafe.tldanother") - end - - test "matches are case-insensitive" do - regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"]) - - assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i] - - assert MRF.subdomain_match?(regexes, "UNSAFE.TLD") - assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD") - assert MRF.subdomain_match?(regexes, "unsafe.tld") - assert MRF.subdomain_match?(regexes, "unsafe2.tld") - - refute MRF.subdomain_match?(regexes, "EXAMPLE.COM") - refute MRF.subdomain_match?(regexes, "example.com") - end - end - - describe "describe/0" do - test "it works as expected with noop policy" do - expected = %{ - mrf_policies: ["NoOpPolicy"], - exclusions: false - } - - {:ok, ^expected} = MRF.describe() - end - - test "it works as expected with mock policy" do - clear_config([:mrf, :policies], [MRFModuleMock]) - - expected = %{ - mrf_policies: ["MRFModuleMock"], - mrf_module_mock: "some config data", - exclusions: false - } - - {:ok, ^expected} = MRF.describe() - 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 deleted file mode 100644 index 64ea61dd4..000000000 --- a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 deleted file mode 100644 index 9b39c45bd..000000000 --- a/test/web/activity_pub/mrf/normalize_markup_test.exs +++ /dev/null @@ -1,42 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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/object_age_policy_test.exs b/test/web/activity_pub/mrf/object_age_policy_test.exs deleted file mode 100644 index b0fb753bd..000000000 --- a/test/web/activity_pub/mrf/object_age_policy_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do - use Pleroma.DataCase - alias Pleroma.Config - alias Pleroma.User - alias Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy - alias Pleroma.Web.ActivityPub.Visibility - - setup do: - clear_config(:mrf_object_age, - threshold: 172_800, - actions: [:delist, :strip_followers] - ) - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - defp get_old_message do - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - end - - defp get_new_message do - old_message = get_old_message() - - new_object = - old_message - |> Map.get("object") - |> Map.put("published", DateTime.utc_now() |> DateTime.to_iso8601()) - - old_message - |> Map.put("object", new_object) - end - - describe "with reject action" do - test "it rejects an old post" do - Config.put([:mrf_object_age, :actions], [:reject]) - - data = get_old_message() - - assert match?({:reject, _}, ObjectAgePolicy.filter(data)) - end - - test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:reject]) - - data = get_new_message() - - assert match?({:ok, _}, ObjectAgePolicy.filter(data)) - end - end - - describe "with delist action" do - test "it delists an old post" do - Config.put([:mrf_object_age, :actions], [:delist]) - - data = get_old_message() - - {:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"]) - - {:ok, data} = ObjectAgePolicy.filter(data) - - assert Visibility.get_visibility(%{data: data}) == "unlisted" - end - - test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:delist]) - - data = get_new_message() - - {:ok, _user} = User.get_or_fetch_by_ap_id(data["actor"]) - - assert match?({:ok, ^data}, ObjectAgePolicy.filter(data)) - end - end - - describe "with strip_followers action" do - test "it strips followers collections from an old post" do - Config.put([:mrf_object_age, :actions], [:strip_followers]) - - data = get_old_message() - - {:ok, user} = User.get_or_fetch_by_ap_id(data["actor"]) - - {:ok, data} = ObjectAgePolicy.filter(data) - - refute user.follower_address in data["to"] - refute user.follower_address in data["cc"] - end - - test "it allows a new post" do - Config.put([:mrf_object_age, :actions], [:strip_followers]) - - data = get_new_message() - - {:ok, _u} = User.get_or_fetch_by_ap_id(data["actor"]) - - assert match?({:ok, ^data}, ObjectAgePolicy.filter(data)) - end - 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 deleted file mode 100644 index 58b46b9a2..000000000 --- a/test/web/activity_pub/mrf/reject_non_public_test.exs +++ /dev/null @@ -1,100 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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: clear_config([:mrf_rejectnonpublic]) - - 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, _} = 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, _} = RejectNonPublic.filter(message) - end - end -end diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs deleted file mode 100644 index e842d8d8d..000000000 --- a/test/web/activity_pub/mrf/simple_policy_test.exs +++ /dev/null @@ -1,479 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Config - alias Pleroma.Web.ActivityPub.MRF.SimplePolicy - - setup do: - clear_config(:mrf_simple, - media_removal: [], - media_nsfw: [], - federated_timeline_removal: [], - report_removal: [], - reject: [], - accept: [], - avatar_removal: [], - banner_removal: [], - reject_deletes: [] - ) - - describe "when :media_removal" do - test "is empty" do - Config.put([:mrf_simple, :media_removal], []) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == {:ok, media_message} - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "has a matching host" do - Config.put([:mrf_simple, :media_removal], ["remote.instance"]) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> Map.put("object", Map.delete(media_message["object"], "attachment"))} - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "match with wildcard domain" do - Config.put([:mrf_simple, :media_removal], ["*.remote.instance"]) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> Map.put("object", Map.delete(media_message["object"], "attachment"))} - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - end - - describe "when :media_nsfw" do - test "is empty" do - Config.put([:mrf_simple, :media_nsfw], []) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == {:ok, media_message} - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "has a matching host" do - Config.put([:mrf_simple, :media_nsfw], ["remote.instance"]) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> put_in(["object", "tag"], ["foo", "nsfw"]) - |> put_in(["object", "sensitive"], true)} - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "match with wildcard domain" do - Config.put([:mrf_simple, :media_nsfw], ["*.remote.instance"]) - media_message = build_media_message() - local_message = build_local_message() - - assert SimplePolicy.filter(media_message) == - {:ok, - media_message - |> put_in(["object", "tag"], ["foo", "nsfw"]) - |> put_in(["object", "sensitive"], true)} - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - end - - defp build_media_message do - %{ - "actor" => "https://remote.instance/users/bob", - "type" => "Create", - "object" => %{ - "attachment" => [%{}], - "tag" => ["foo"], - "sensitive" => false - } - } - end - - describe "when :report_removal" do - test "is empty" do - Config.put([:mrf_simple, :report_removal], []) - report_message = build_report_message() - local_message = build_local_message() - - assert SimplePolicy.filter(report_message) == {:ok, report_message} - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "has a matching host" do - Config.put([:mrf_simple, :report_removal], ["remote.instance"]) - report_message = build_report_message() - local_message = build_local_message() - - assert {:reject, _} = SimplePolicy.filter(report_message) - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "match with wildcard domain" do - Config.put([:mrf_simple, :report_removal], ["*.remote.instance"]) - report_message = build_report_message() - local_message = build_local_message() - - assert {:reject, _} = SimplePolicy.filter(report_message) - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - end - - defp build_report_message do - %{ - "actor" => "https://remote.instance/users/bob", - "type" => "Flag" - } - end - - describe "when :federated_timeline_removal" do - test "is empty" do - Config.put([:mrf_simple, :federated_timeline_removal], []) - {_, ftl_message} = build_ftl_actor_and_message() - local_message = build_local_message() - - assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "has a matching host" do - {actor, ftl_message} = build_ftl_actor_and_message() - - ftl_message_actor_host = - ftl_message - |> Map.fetch!("actor") - |> URI.parse() - |> Map.fetch!(:host) - - Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) - local_message = build_local_message() - - assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) - assert actor.follower_address in ftl_message["to"] - refute actor.follower_address in ftl_message["cc"] - refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] - assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"] - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "match with wildcard domain" do - {actor, ftl_message} = build_ftl_actor_and_message() - - ftl_message_actor_host = - ftl_message - |> Map.fetch!("actor") - |> URI.parse() - |> Map.fetch!(:host) - - Config.put([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host]) - local_message = build_local_message() - - assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) - assert actor.follower_address in ftl_message["to"] - refute actor.follower_address in ftl_message["cc"] - refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] - assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"] - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - end - - test "has a matching host but only as:Public in to" do - {_actor, ftl_message} = build_ftl_actor_and_message() - - ftl_message_actor_host = - ftl_message - |> Map.fetch!("actor") - |> URI.parse() - |> Map.fetch!(:host) - - ftl_message = Map.put(ftl_message, "cc", []) - - Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host]) - - assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message) - refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"] - assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"] - end - end - - defp build_ftl_actor_and_message do - actor = insert(:user) - - {actor, - %{ - "actor" => actor.ap_id, - "to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"], - "cc" => [actor.follower_address, "http://foo.bar/qux"] - }} - end - - describe "when :reject" do - test "is empty" do - Config.put([:mrf_simple, :reject], []) - - remote_message = build_remote_message() - - assert SimplePolicy.filter(remote_message) == {:ok, remote_message} - end - - test "activity has a matching host" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) - - remote_message = build_remote_message() - - assert {:reject, _} = SimplePolicy.filter(remote_message) - end - - test "activity matches with wildcard domain" do - Config.put([:mrf_simple, :reject], ["*.remote.instance"]) - - remote_message = build_remote_message() - - assert {:reject, _} = SimplePolicy.filter(remote_message) - end - - test "actor has a matching host" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) - - remote_user = build_remote_user() - - assert {:reject, _} = SimplePolicy.filter(remote_user) - end - end - - describe "when :accept" do - test "is empty" do - Config.put([:mrf_simple, :accept], []) - - local_message = build_local_message() - remote_message = build_remote_message() - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - assert SimplePolicy.filter(remote_message) == {:ok, remote_message} - end - - test "is not empty but activity doesn't have a matching host" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) - - local_message = build_local_message() - remote_message = build_remote_message() - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - assert {:reject, _} = SimplePolicy.filter(remote_message) - end - - test "activity has a matching host" do - Config.put([:mrf_simple, :accept], ["remote.instance"]) - - local_message = build_local_message() - remote_message = build_remote_message() - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - assert SimplePolicy.filter(remote_message) == {:ok, remote_message} - end - - test "activity matches with wildcard domain" do - Config.put([:mrf_simple, :accept], ["*.remote.instance"]) - - local_message = build_local_message() - remote_message = build_remote_message() - - assert SimplePolicy.filter(local_message) == {:ok, local_message} - assert SimplePolicy.filter(remote_message) == {:ok, remote_message} - end - - test "actor has a matching host" do - Config.put([:mrf_simple, :accept], ["remote.instance"]) - - remote_user = build_remote_user() - - assert SimplePolicy.filter(remote_user) == {:ok, remote_user} - end - end - - describe "when :avatar_removal" do - test "is empty" do - Config.put([:mrf_simple, :avatar_removal], []) - - remote_user = build_remote_user() - - assert SimplePolicy.filter(remote_user) == {:ok, remote_user} - end - - test "is not empty but it doesn't have a matching host" do - Config.put([:mrf_simple, :avatar_removal], ["non.matching.remote"]) - - remote_user = build_remote_user() - - assert SimplePolicy.filter(remote_user) == {:ok, remote_user} - end - - test "has a matching host" do - Config.put([:mrf_simple, :avatar_removal], ["remote.instance"]) - - remote_user = build_remote_user() - {:ok, filtered} = SimplePolicy.filter(remote_user) - - refute filtered["icon"] - end - - test "match with wildcard domain" do - Config.put([:mrf_simple, :avatar_removal], ["*.remote.instance"]) - - remote_user = build_remote_user() - {:ok, filtered} = SimplePolicy.filter(remote_user) - - refute filtered["icon"] - end - end - - describe "when :banner_removal" do - test "is empty" do - Config.put([:mrf_simple, :banner_removal], []) - - remote_user = build_remote_user() - - assert SimplePolicy.filter(remote_user) == {:ok, remote_user} - end - - test "is not empty but it doesn't have a matching host" do - Config.put([:mrf_simple, :banner_removal], ["non.matching.remote"]) - - remote_user = build_remote_user() - - assert SimplePolicy.filter(remote_user) == {:ok, remote_user} - end - - test "has a matching host" do - Config.put([:mrf_simple, :banner_removal], ["remote.instance"]) - - remote_user = build_remote_user() - {:ok, filtered} = SimplePolicy.filter(remote_user) - - refute filtered["image"] - end - - test "match with wildcard domain" do - Config.put([:mrf_simple, :banner_removal], ["*.remote.instance"]) - - remote_user = build_remote_user() - {:ok, filtered} = SimplePolicy.filter(remote_user) - - refute filtered["image"] - end - end - - describe "when :reject_deletes is empty" do - setup do: Config.put([:mrf_simple, :reject_deletes], []) - - test "it accepts deletions even from rejected servers" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) - - deletion_message = build_remote_deletion_message() - - assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message} - end - - test "it accepts deletions even from non-whitelisted servers" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) - - deletion_message = build_remote_deletion_message() - - assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message} - end - end - - describe "when :reject_deletes is not empty but it doesn't have a matching host" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"]) - - test "it accepts deletions even from rejected servers" do - Config.put([:mrf_simple, :reject], ["remote.instance"]) - - deletion_message = build_remote_deletion_message() - - assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message} - end - - test "it accepts deletions even from non-whitelisted servers" do - Config.put([:mrf_simple, :accept], ["non.matching.remote"]) - - deletion_message = build_remote_deletion_message() - - assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message} - end - end - - describe "when :reject_deletes has a matching host" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"]) - - test "it rejects the deletion" do - deletion_message = build_remote_deletion_message() - - assert {:reject, _} = SimplePolicy.filter(deletion_message) - end - end - - describe "when :reject_deletes match with wildcard domain" do - setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"]) - - test "it rejects the deletion" do - deletion_message = build_remote_deletion_message() - - assert {:reject, _} = SimplePolicy.filter(deletion_message) - end - end - - defp build_local_message do - %{ - "actor" => "#{Pleroma.Web.base_url()}/users/alice", - "to" => [], - "cc" => [] - } - end - - defp build_remote_message do - %{"actor" => "https://remote.instance/users/bob"} - end - - defp build_remote_user do - %{ - "id" => "https://remote.instance/users/bob", - "icon" => %{ - "url" => "http://example.com/image.jpg", - "type" => "Image" - }, - "image" => %{ - "url" => "http://example.com/image.jpg", - "type" => "Image" - }, - "type" => "Person" - } - end - - defp build_remote_deletion_message do - %{ - "type" => "Delete", - "actor" => "https://remote.instance/users/bob" - } - end -end diff --git a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/web/activity_pub/mrf/steal_emoji_policy_test.exs deleted file mode 100644 index 3f8222736..000000000 --- a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs +++ /dev/null @@ -1,68 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do - use Pleroma.DataCase - - alias Pleroma.Config - alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do - emoji_path = Path.join(Config.get([:instance, :static_dir]), "emoji/stolen") - File.rm_rf!(emoji_path) - File.mkdir!(emoji_path) - - Pleroma.Emoji.reload() - - on_exit(fn -> - File.rm_rf!(emoji_path) - end) - - :ok - end - - test "does nothing by default" do - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - - message = %{ - "type" => "Create", - "object" => %{ - "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], - "actor" => "https://example.org/users/admin" - } - } - - assert {:ok, message} == StealEmojiPolicy.filter(message) - - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - end - - test "Steals emoji on unknown shortcode from allowed remote host" do - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - refute "firedfox" in installed_emoji - - message = %{ - "type" => "Create", - "object" => %{ - "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], - "actor" => "https://example.org/users/admin" - } - } - - clear_config([:mrf_steal_emoji, :hosts], ["example.org"]) - clear_config([:mrf_steal_emoji, :size_limit], 284_468) - - assert {:ok, message} == StealEmojiPolicy.filter(message) - - installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) - assert "firedfox" in installed_emoji - end -end diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/web/activity_pub/mrf/subchain_policy_test.exs deleted file mode 100644 index fff66cb7e..000000000 --- a/test/web/activity_pub/mrf/subchain_policy_test.exs +++ /dev/null @@ -1,33 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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"} - } - setup do: clear_config([:mrf_subchain, :match_actor]) - - 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 deleted file mode 100644 index 6ff71d640..000000000 --- a/test/web/activity_pub/mrf/tag_policy_test.exs +++ /dev/null @@ -1,123 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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", "actor" => actor.ap_id} - assert {:reject, _} = 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, _} = 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 deleted file mode 100644 index 8e1ad5bc8..000000000 --- a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs +++ /dev/null @@ -1,31 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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: clear_config(:mrf_user_allowlist) - - 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 {:reject, _} = UserAllowListPolicy.filter(message) - end -end diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/web/activity_pub/mrf/vocabulary_policy_test.exs deleted file mode 100644 index 2bceb67ee..000000000 --- a/test/web/activity_pub/mrf/vocabulary_policy_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.MRF.VocabularyPolicy - - describe "accept" do - setup do: clear_config([:mrf_vocabulary, :accept]) - - test "it accepts based on parent activity type" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"]) - - message = %{ - "type" => "Like", - "object" => "whatever" - } - - {:ok, ^message} = VocabularyPolicy.filter(message) - end - - test "it accepts based on child object type" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) - - message = %{ - "type" => "Create", - "object" => %{ - "type" => "Note", - "content" => "whatever" - } - } - - {:ok, ^message} = VocabularyPolicy.filter(message) - end - - test "it does not accept disallowed child objects" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) - - message = %{ - "type" => "Create", - "object" => %{ - "type" => "Article", - "content" => "whatever" - } - } - - {:reject, _} = VocabularyPolicy.filter(message) - end - - test "it does not accept disallowed parent types" do - Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"]) - - message = %{ - "type" => "Create", - "object" => %{ - "type" => "Note", - "content" => "whatever" - } - } - - {:reject, _} = VocabularyPolicy.filter(message) - end - end - - describe "reject" do - setup do: clear_config([:mrf_vocabulary, :reject]) - - test "it rejects based on parent activity type" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) - - message = %{ - "type" => "Like", - "object" => "whatever" - } - - {:reject, _} = VocabularyPolicy.filter(message) - end - - test "it rejects based on child object type" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"]) - - message = %{ - "type" => "Create", - "object" => %{ - "type" => "Note", - "content" => "whatever" - } - } - - {:reject, _} = VocabularyPolicy.filter(message) - end - - test "it passes through objects that aren't disallowed" do - Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) - - message = %{ - "type" => "Announce", - "object" => "whatever" - } - - {:ok, ^message} = VocabularyPolicy.filter(message) - end - end -end diff --git a/test/web/activity_pub/object_validators/announce_validation_test.exs b/test/web/activity_pub/object_validators/announce_validation_test.exs deleted file mode 100644 index 623342f76..000000000 --- a/test/web/activity_pub/object_validators/announce_validation_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do - use Pleroma.DataCase - - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "announces" do - setup do - user = insert(:user) - announcer = insert(:user) - {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - - object = Object.normalize(post_activity, false) - {:ok, valid_announce, []} = Builder.announce(announcer, object) - - %{ - valid_announce: valid_announce, - user: user, - post_activity: post_activity, - announcer: announcer - } - end - - test "returns ok for a valid announce", %{valid_announce: valid_announce} do - assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, []) - end - - test "returns an error if the object can't be found", %{valid_announce: valid_announce} do - without_object = - valid_announce - |> Map.delete("object") - - {:error, cng} = ObjectValidator.validate(without_object, []) - - assert {:object, {"can't be blank", [validation: :required]}} in cng.errors - - nonexisting_object = - valid_announce - |> Map.put("object", "https://gensokyo.2hu/objects/99999999") - - {:error, cng} = ObjectValidator.validate(nonexisting_object, []) - - assert {:object, {"can't find object", []}} in cng.errors - end - - test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do - nonexisting_actor = - valid_announce - |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") - - {:error, cng} = ObjectValidator.validate(nonexisting_actor, []) - - assert {:actor, {"can't find user", []}} in cng.errors - end - - test "returns an error if the actor already announced the object", %{ - valid_announce: valid_announce, - announcer: announcer, - post_activity: post_activity - } do - _announce = CommonAPI.repeat(post_activity.id, announcer) - - {:error, cng} = ObjectValidator.validate(valid_announce, []) - - assert {:actor, {"already announced this object", []}} in cng.errors - assert {:object, {"already announced by this actor", []}} in cng.errors - end - - test "returns an error if the actor can't announce the object", %{ - announcer: announcer, - user: user - } do - {:ok, post_activity} = - CommonAPI.post(user, %{status: "a secret post", visibility: "private"}) - - object = Object.normalize(post_activity, false) - - # Another user can't announce it - {:ok, announce, []} = Builder.announce(announcer, object, public: false) - - {:error, cng} = ObjectValidator.validate(announce, []) - - assert {:actor, {"can not announce this object", []}} in cng.errors - - # The actor of the object can announce it - {:ok, announce, []} = Builder.announce(user, object, public: false) - - assert {:ok, _, _} = ObjectValidator.validate(announce, []) - - # The actor of the object can not announce it publicly - {:ok, announce, []} = Builder.announce(user, object, public: true) - - {:error, cng} = ObjectValidator.validate(announce, []) - - assert {:actor, {"can not announce this object publicly", []}} in cng.errors - end - end -end diff --git a/test/web/activity_pub/object_validators/attachment_validator_test.exs b/test/web/activity_pub/object_validators/attachment_validator_test.exs deleted file mode 100644 index 558bb3131..000000000 --- a/test/web/activity_pub/object_validators/attachment_validator_test.exs +++ /dev/null @@ -1,74 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator - - import Pleroma.Factory - - describe "attachments" do - test "works with honkerific attachments" do - attachment = %{ - "mediaType" => "", - "name" => "", - "summary" => "298p3RG7j27tfsZ9RQ.jpg", - "type" => "Document", - "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" - } - - assert {:ok, attachment} = - AttachmentValidator.cast_and_validate(attachment) - |> Ecto.Changeset.apply_action(:insert) - - assert attachment.mediaType == "application/octet-stream" - end - - test "it turns mastodon attachments into our attachments" do - attachment = %{ - "url" => - "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", - "type" => "Document", - "name" => nil, - "mediaType" => "image/jpeg" - } - - {:ok, attachment} = - AttachmentValidator.cast_and_validate(attachment) - |> Ecto.Changeset.apply_action(:insert) - - assert [ - %{ - href: - "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", - type: "Link", - mediaType: "image/jpeg" - } - ] = attachment.url - - assert attachment.mediaType == "image/jpeg" - end - - test "it handles our own uploads" do - user = insert(:user) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) - - {:ok, attachment} = - attachment.data - |> AttachmentValidator.cast_and_validate() - |> Ecto.Changeset.apply_action(:insert) - - assert attachment.mediaType == "image/jpeg" - end - end -end diff --git a/test/web/activity_pub/object_validators/block_validation_test.exs b/test/web/activity_pub/object_validators/block_validation_test.exs deleted file mode 100644 index c08d4b2e8..000000000 --- a/test/web/activity_pub/object_validators/block_validation_test.exs +++ /dev/null @@ -1,39 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidationTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - - import Pleroma.Factory - - describe "blocks" do - setup do - user = insert(:user, local: false) - blocked = insert(:user) - - {:ok, valid_block, []} = Builder.block(user, blocked) - - %{user: user, valid_block: valid_block} - end - - test "validates a basic object", %{ - valid_block: valid_block - } do - assert {:ok, _block, []} = ObjectValidator.validate(valid_block, []) - end - - test "returns an error if we don't know the blocked user", %{ - valid_block: valid_block - } do - block = - valid_block - |> Map.put("object", "https://gensokyo.2hu/users/raymoo") - - assert {:error, _cng} = ObjectValidator.validate(block, []) - end - end -end diff --git a/test/web/activity_pub/object_validators/chat_validation_test.exs b/test/web/activity_pub/object_validators/chat_validation_test.exs deleted file mode 100644 index 50bf03515..000000000 --- a/test/web/activity_pub/object_validators/chat_validation_test.exs +++ /dev/null @@ -1,211 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do - use Pleroma.DataCase - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "chat message create activities" do - test "it is invalid if the object already exists" do - user = insert(:user) - recipient = insert(:user) - {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey") - object = Object.normalize(activity, false) - - {:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id]) - - {:error, cng} = ObjectValidator.validate(create_data, []) - - assert {:object, {"The object to create already exists", []}} in cng.errors - end - - test "it is invalid if the object data has a different `to` or `actor` field" do - user = insert(:user) - recipient = insert(:user) - {:ok, object_data, _} = Builder.chat_message(recipient, user.ap_id, "Hey") - - {:ok, create_data, _} = Builder.create(user, object_data, [recipient.ap_id]) - - {:error, cng} = ObjectValidator.validate(create_data, []) - - assert {:to, {"Recipients don't match with object recipients", []}} in cng.errors - assert {:actor, {"Actor doesn't match with object actor", []}} in cng.errors - end - end - - describe "chat messages" do - setup do - clear_config([:instance, :remote_limit]) - user = insert(:user) - recipient = insert(:user, local: false) - - {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey :firefox:") - - %{user: user, recipient: recipient, valid_chat_message: valid_chat_message} - end - - test "let's through some basic html", %{user: user, recipient: recipient} do - {:ok, valid_chat_message, _} = - Builder.chat_message( - user, - recipient.ap_id, - "hey <a href='https://example.org'>example</a> <script>alert('uguu')</script>" - ) - - assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - - assert object["content"] == - "hey <a href=\"https://example.org\">example</a> alert('uguu')" - end - - test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do - assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - - assert Map.put(valid_chat_message, "attachment", nil) == object - end - - test "validates for a basic object with an attachment", %{ - valid_chat_message: valid_chat_message, - user: user - } do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) - - valid_chat_message = - valid_chat_message - |> Map.put("attachment", attachment.data) - - assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - - assert object["attachment"] - end - - test "validates for a basic object with an attachment in an array", %{ - valid_chat_message: valid_chat_message, - user: user - } do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) - - valid_chat_message = - valid_chat_message - |> Map.put("attachment", [attachment.data]) - - assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - - assert object["attachment"] - end - - test "validates for a basic object with an attachment but without content", %{ - valid_chat_message: valid_chat_message, - user: user - } do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) - - valid_chat_message = - valid_chat_message - |> Map.put("attachment", attachment.data) - |> Map.delete("content") - - assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) - - assert object["attachment"] - end - - test "does not validate if the message has no content", %{ - valid_chat_message: valid_chat_message - } do - contentless = - valid_chat_message - |> Map.delete("content") - - refute match?({:ok, _object, _meta}, ObjectValidator.validate(contentless, [])) - end - - test "does not validate if the message is longer than the remote_limit", %{ - valid_chat_message: valid_chat_message - } do - Pleroma.Config.put([:instance, :remote_limit], 2) - refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) - end - - test "does not validate if the recipient is blocking the actor", %{ - valid_chat_message: valid_chat_message, - user: user, - recipient: recipient - } do - Pleroma.User.block(recipient, user) - refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) - end - - test "does not validate if the recipient is not accepting chat messages", %{ - valid_chat_message: valid_chat_message, - recipient: recipient - } do - recipient - |> Ecto.Changeset.change(%{accepts_chat_messages: false}) - |> Pleroma.Repo.update!() - - refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) - end - - test "does not validate if the actor or the recipient is not in our system", %{ - valid_chat_message: valid_chat_message - } do - chat_message = - valid_chat_message - |> Map.put("actor", "https://raymoo.com/raymoo") - - {:error, _} = ObjectValidator.validate(chat_message, []) - - chat_message = - valid_chat_message - |> Map.put("to", ["https://raymoo.com/raymoo"]) - - {:error, _} = ObjectValidator.validate(chat_message, []) - end - - test "does not validate for a message with multiple recipients", %{ - valid_chat_message: valid_chat_message, - user: user, - recipient: recipient - } do - chat_message = - valid_chat_message - |> Map.put("to", [user.ap_id, recipient.ap_id]) - - assert {:error, _} = ObjectValidator.validate(chat_message, []) - end - - test "does not validate if it doesn't concern local users" do - user = insert(:user, local: false) - recipient = insert(:user, local: false) - - {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey") - assert {:error, _} = ObjectValidator.validate(valid_chat_message, []) - end - end -end diff --git a/test/web/activity_pub/object_validators/delete_validation_test.exs b/test/web/activity_pub/object_validators/delete_validation_test.exs deleted file mode 100644 index 42cd18298..000000000 --- a/test/web/activity_pub/object_validators/delete_validation_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidationTest do - use Pleroma.DataCase - - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "deletes" do - setup do - user = insert(:user) - {:ok, post_activity} = CommonAPI.post(user, %{status: "cancel me daddy"}) - - {:ok, valid_post_delete, _} = Builder.delete(user, post_activity.data["object"]) - {:ok, valid_user_delete, _} = Builder.delete(user, user.ap_id) - - %{user: user, valid_post_delete: valid_post_delete, valid_user_delete: valid_user_delete} - end - - test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete} do - {:ok, valid_post_delete, _} = ObjectValidator.validate(valid_post_delete, []) - - assert valid_post_delete["deleted_activity_id"] - end - - test "it is invalid if the object isn't in a list of certain types", %{ - valid_post_delete: valid_post_delete - } do - object = Object.get_by_ap_id(valid_post_delete["object"]) - - data = - object.data - |> Map.put("type", "Like") - - {:ok, _object} = - object - |> Ecto.Changeset.change(%{data: data}) - |> Object.update_and_set_cache() - - {:error, cng} = ObjectValidator.validate(valid_post_delete, []) - assert {:object, {"object not in allowed types", []}} in cng.errors - end - - test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do - assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, [])) - end - - test "it's invalid if the id is missing", %{valid_post_delete: valid_post_delete} do - no_id = - valid_post_delete - |> Map.delete("id") - - {:error, cng} = ObjectValidator.validate(no_id, []) - - assert {:id, {"can't be blank", [validation: :required]}} in cng.errors - end - - test "it's invalid if the object doesn't exist", %{valid_post_delete: valid_post_delete} do - missing_object = - valid_post_delete - |> Map.put("object", "http://does.not/exist") - - {:error, cng} = ObjectValidator.validate(missing_object, []) - - assert {:object, {"can't find object", []}} in cng.errors - end - - test "it's invalid if the actor of the object and the actor of delete are from different domains", - %{valid_post_delete: valid_post_delete} do - valid_user = insert(:user) - - valid_other_actor = - valid_post_delete - |> Map.put("actor", valid_user.ap_id) - - assert match?({:ok, _, _}, ObjectValidator.validate(valid_other_actor, [])) - - invalid_other_actor = - valid_post_delete - |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") - - {:error, cng} = ObjectValidator.validate(invalid_other_actor, []) - - assert {:actor, {"is not allowed to delete object", []}} in cng.errors - end - - test "it's valid if the actor of the object is a local superuser", - %{valid_post_delete: valid_post_delete} do - user = - insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo") - - valid_other_actor = - valid_post_delete - |> Map.put("actor", user.ap_id) - - {:ok, _, meta} = ObjectValidator.validate(valid_other_actor, []) - assert meta[:do_not_federate] - end - end -end diff --git a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs b/test/web/activity_pub/object_validators/emoji_react_validation_test.exs deleted file mode 100644 index 582e6d785..000000000 --- a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs +++ /dev/null @@ -1,53 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "EmojiReacts" do - setup do - user = insert(:user) - {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - - object = Pleroma.Object.get_by_ap_id(post_activity.data["object"]) - - {:ok, valid_emoji_react, []} = Builder.emoji_react(user, object, "👌") - - %{user: user, post_activity: post_activity, valid_emoji_react: valid_emoji_react} - end - - test "it validates a valid EmojiReact", %{valid_emoji_react: valid_emoji_react} do - assert {:ok, _, _} = ObjectValidator.validate(valid_emoji_react, []) - end - - test "it is not valid without a 'content' field", %{valid_emoji_react: valid_emoji_react} do - without_content = - valid_emoji_react - |> Map.delete("content") - - {:error, cng} = ObjectValidator.validate(without_content, []) - - refute cng.valid? - assert {:content, {"can't be blank", [validation: :required]}} in cng.errors - end - - test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do - without_emoji_content = - valid_emoji_react - |> Map.put("content", "x") - - {:error, cng} = ObjectValidator.validate(without_emoji_content, []) - - refute cng.valid? - - assert {:content, {"must be a single character emoji", []}} in cng.errors - end - end -end diff --git a/test/web/activity_pub/object_validators/follow_validation_test.exs b/test/web/activity_pub/object_validators/follow_validation_test.exs deleted file mode 100644 index 6e1378be2..000000000 --- a/test/web/activity_pub/object_validators/follow_validation_test.exs +++ /dev/null @@ -1,26 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidationTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - - import Pleroma.Factory - - describe "Follows" do - setup do - follower = insert(:user) - followed = insert(:user) - - {:ok, valid_follow, []} = Builder.follow(follower, followed) - %{follower: follower, followed: followed, valid_follow: valid_follow} - end - - test "validates a basic follow object", %{valid_follow: valid_follow} do - assert {:ok, _follow, []} = ObjectValidator.validate(valid_follow, []) - end - end -end diff --git a/test/web/activity_pub/object_validators/like_validation_test.exs b/test/web/activity_pub/object_validators/like_validation_test.exs deleted file mode 100644 index 2c033b7e2..000000000 --- a/test/web/activity_pub/object_validators/like_validation_test.exs +++ /dev/null @@ -1,113 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator - alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "likes" do - setup do - user = insert(:user) - {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - - valid_like = %{ - "to" => [user.ap_id], - "cc" => [], - "type" => "Like", - "id" => Utils.generate_activity_id(), - "object" => post_activity.data["object"], - "actor" => user.ap_id, - "context" => "a context" - } - - %{valid_like: valid_like, user: user, post_activity: post_activity} - end - - test "returns ok when called in the ObjectValidator", %{valid_like: valid_like} do - {:ok, object, _meta} = ObjectValidator.validate(valid_like, []) - - assert "id" in Map.keys(object) - end - - test "is valid for a valid object", %{valid_like: valid_like} do - assert LikeValidator.cast_and_validate(valid_like).valid? - end - - test "sets the 'to' field to the object actor if no recipients are given", %{ - valid_like: valid_like, - user: user - } do - without_recipients = - valid_like - |> Map.delete("to") - - {:ok, object, _meta} = ObjectValidator.validate(without_recipients, []) - - assert object["to"] == [user.ap_id] - end - - test "sets the context field to the context of the object if no context is given", %{ - valid_like: valid_like, - post_activity: post_activity - } do - without_context = - valid_like - |> Map.delete("context") - - {:ok, object, _meta} = ObjectValidator.validate(without_context, []) - - assert object["context"] == post_activity.data["context"] - end - - test "it errors when the actor is missing or not known", %{valid_like: valid_like} do - without_actor = Map.delete(valid_like, "actor") - - refute LikeValidator.cast_and_validate(without_actor).valid? - - with_invalid_actor = Map.put(valid_like, "actor", "invalidactor") - - refute LikeValidator.cast_and_validate(with_invalid_actor).valid? - end - - test "it errors when the object is missing or not known", %{valid_like: valid_like} do - without_object = Map.delete(valid_like, "object") - - refute LikeValidator.cast_and_validate(without_object).valid? - - with_invalid_object = Map.put(valid_like, "object", "invalidobject") - - refute LikeValidator.cast_and_validate(with_invalid_object).valid? - end - - test "it errors when the actor has already like the object", %{ - valid_like: valid_like, - user: user, - post_activity: post_activity - } do - _like = CommonAPI.favorite(user, post_activity.id) - - refute LikeValidator.cast_and_validate(valid_like).valid? - end - - test "it works when actor or object are wrapped in maps", %{valid_like: valid_like} do - wrapped_like = - valid_like - |> Map.put("actor", %{"id" => valid_like["actor"]}) - |> Map.put("object", %{"id" => valid_like["object"]}) - - validated = LikeValidator.cast_and_validate(wrapped_like) - - assert validated.valid? - - assert {:actor, valid_like["actor"]} in validated.changes - assert {:object, valid_like["object"]} in validated.changes - end - end -end diff --git a/test/web/activity_pub/object_validators/note_validator_test.exs b/test/web/activity_pub/object_validators/note_validator_test.exs deleted file mode 100644 index 30c481ffb..000000000 --- a/test/web/activity_pub/object_validators/note_validator_test.exs +++ /dev/null @@ -1,35 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator - alias Pleroma.Web.ActivityPub.Utils - - import Pleroma.Factory - - describe "Notes" do - setup do - user = insert(:user) - - note = %{ - "id" => Utils.generate_activity_id(), - "type" => "Note", - "actor" => user.ap_id, - "to" => [user.follower_address], - "cc" => [], - "content" => "Hellow this is content.", - "context" => "xxx", - "summary" => "a post" - } - - %{user: user, note: note} - end - - test "a basic note validates", %{note: note} do - %{valid?: true} = NoteValidator.cast_and_validate(note) - end - end -end diff --git a/test/web/activity_pub/object_validators/types/date_time_test.exs b/test/web/activity_pub/object_validators/types/date_time_test.exs deleted file mode 100644 index 43be8e936..000000000 --- a/test/web/activity_pub/object_validators/types/date_time_test.exs +++ /dev/null @@ -1,32 +0,0 @@ -defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do - alias Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime - use Pleroma.DataCase - - test "it validates an xsd:Datetime" do - valid_strings = [ - "2004-04-12T13:20:00", - "2004-04-12T13:20:15.5", - "2004-04-12T13:20:00-05:00", - "2004-04-12T13:20:00Z" - ] - - invalid_strings = [ - "2004-04-12T13:00", - "2004-04-1213:20:00", - "99-04-12T13:00", - "2004-04-12" - ] - - assert {:ok, "2004-04-01T12:00:00Z"} == DateTime.cast("2004-04-01T12:00:00Z") - - Enum.each(valid_strings, fn date_time -> - result = DateTime.cast(date_time) - assert {:ok, _} = result - end) - - Enum.each(invalid_strings, fn date_time -> - result = DateTime.cast(date_time) - assert :error == result - end) - end -end diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/web/activity_pub/object_validators/types/object_id_test.exs deleted file mode 100644 index e0ab76379..000000000 --- a/test/web/activity_pub/object_validators/types/object_id_test.exs +++ /dev/null @@ -1,41 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do - alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID - use Pleroma.DataCase - - @uris [ - "http://lain.com/users/lain", - "http://lain.com", - "https://lain.com/object/1" - ] - - @non_uris [ - "https://", - "rin", - 1, - :x, - %{"1" => 2} - ] - - test "it accepts http uris" do - Enum.each(@uris, fn uri -> - assert {:ok, uri} == ObjectID.cast(uri) - end) - end - - test "it accepts an object with a nested uri id" do - Enum.each(@uris, fn uri -> - assert {:ok, uri} == ObjectID.cast(%{"id" => uri}) - end) - end - - test "it rejects non-uri strings" do - Enum.each(@non_uris, fn non_uri -> - assert :error == ObjectID.cast(non_uri) - assert :error == ObjectID.cast(%{"id" => non_uri}) - end) - end -end diff --git a/test/web/activity_pub/object_validators/types/recipients_test.exs b/test/web/activity_pub/object_validators/types/recipients_test.exs deleted file mode 100644 index 053916bdd..000000000 --- a/test/web/activity_pub/object_validators/types/recipients_test.exs +++ /dev/null @@ -1,27 +0,0 @@ -defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do - alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients - use Pleroma.DataCase - - test "it asserts that all elements of the list are object ids" do - list = ["https://lain.com/users/lain", "invalid"] - - assert :error == Recipients.cast(list) - end - - test "it works with a list" do - list = ["https://lain.com/users/lain"] - assert {:ok, list} == Recipients.cast(list) - end - - test "it works with a list with whole objects" do - list = ["https://lain.com/users/lain", %{"id" => "https://gensokyo.2hu/users/raymoo"}] - resulting_list = ["https://gensokyo.2hu/users/raymoo", "https://lain.com/users/lain"] - assert {:ok, resulting_list} == Recipients.cast(list) - end - - test "it turns a single string into a list" do - recipient = "https://lain.com/users/lain" - - assert {:ok, [recipient]} == Recipients.cast(recipient) - end -end diff --git a/test/web/activity_pub/object_validators/types/safe_text_test.exs b/test/web/activity_pub/object_validators/types/safe_text_test.exs deleted file mode 100644 index 9c08606f6..000000000 --- a/test/web/activity_pub/object_validators/types/safe_text_test.exs +++ /dev/null @@ -1,30 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeTextTest do - use Pleroma.DataCase - - alias Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText - - test "it lets normal text go through" do - text = "hey how are you" - assert {:ok, text} == SafeText.cast(text) - end - - test "it removes html tags from text" do - text = "hey look xss <script>alert('foo')</script>" - assert {:ok, "hey look xss alert('foo')"} == SafeText.cast(text) - end - - test "it keeps basic html tags" do - text = "hey <a href='http://gensokyo.2hu'>look</a> xss <script>alert('foo')</script>" - - assert {:ok, "hey <a href=\"http://gensokyo.2hu\">look</a> xss alert('foo')"} == - SafeText.cast(text) - end - - test "errors for non-text" do - assert :error == SafeText.cast(1) - end -end diff --git a/test/web/activity_pub/object_validators/undo_validation_test.exs b/test/web/activity_pub/object_validators/undo_validation_test.exs deleted file mode 100644 index 75bbcc4b6..000000000 --- a/test/web/activity_pub/object_validators/undo_validation_test.exs +++ /dev/null @@ -1,53 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "Undos" do - setup do - user = insert(:user) - {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - {:ok, like} = CommonAPI.favorite(user, post_activity.id) - {:ok, valid_like_undo, []} = Builder.undo(user, like) - - %{user: user, like: like, valid_like_undo: valid_like_undo} - end - - test "it validates a basic like undo", %{valid_like_undo: valid_like_undo} do - assert {:ok, _, _} = ObjectValidator.validate(valid_like_undo, []) - end - - test "it does not validate if the actor of the undo is not the actor of the object", %{ - valid_like_undo: valid_like_undo - } do - other_user = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo") - - bad_actor = - valid_like_undo - |> Map.put("actor", other_user.ap_id) - - {:error, cng} = ObjectValidator.validate(bad_actor, []) - - assert {:actor, {"not the same as object actor", []}} in cng.errors - end - - test "it does not validate if the object is missing", %{valid_like_undo: valid_like_undo} do - missing_object = - valid_like_undo - |> Map.put("object", "https://gensokyo.2hu/objects/1") - - {:error, cng} = ObjectValidator.validate(missing_object, []) - - assert {:object, {"can't find object", []}} in cng.errors - assert length(cng.errors) == 1 - end - end -end diff --git a/test/web/activity_pub/object_validators/update_validation_test.exs b/test/web/activity_pub/object_validators/update_validation_test.exs deleted file mode 100644 index 5e80cf731..000000000 --- a/test/web/activity_pub/object_validators/update_validation_test.exs +++ /dev/null @@ -1,44 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.ObjectValidator - - import Pleroma.Factory - - describe "updates" do - setup do - user = insert(:user) - - object = %{ - "id" => user.ap_id, - "name" => "A new name", - "summary" => "A new bio" - } - - {:ok, valid_update, []} = Builder.update(user, object) - - %{user: user, valid_update: valid_update} - end - - test "validates a basic object", %{valid_update: valid_update} do - assert {:ok, _update, []} = ObjectValidator.validate(valid_update, []) - end - - test "returns an error if the object can't be updated by the actor", %{ - valid_update: valid_update - } do - other_user = insert(:user) - - update = - valid_update - |> Map.put("actor", other_user.ap_id) - - assert {:error, _cng} = ObjectValidator.validate(update, []) - end - end -end diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs deleted file mode 100644 index f2a231eaf..000000000 --- a/test/web/activity_pub/pipeline_test.exs +++ /dev/null @@ -1,179 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.PipelineTest do - use Pleroma.DataCase - - import Mock - import Pleroma.Factory - - describe "common_pipeline/2" do - setup do - clear_config([:instance, :federating], true) - :ok - end - - test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do - activity = insert(:note_activity) - object = %{"id" => "1", "type" => "Love"} - meta = [local: true, object_data: object] - - activity_with_object = %{activity | data: Map.put(activity.data, "object", object)} - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [ - handle: fn o, m -> {:ok, o, m} end, - handle_after_transaction: fn m -> m end - ] - }, - { - Pleroma.Web.Federator, - [], - [publish: fn _o -> :ok end] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - refute called(Pleroma.Web.Federator.publish(activity)) - assert_called(Pleroma.Web.Federator.publish(activity_with_object)) - end - end - - test "it goes through validation, filtering, persisting, side effects and federation for local activities" do - activity = insert(:note_activity) - meta = [local: true] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [ - handle: fn o, m -> {:ok, o, m} end, - handle_after_transaction: fn m -> m end - ] - }, - { - Pleroma.Web.Federator, - [], - [publish: fn _o -> :ok end] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - assert_called(Pleroma.Web.Federator.publish(activity)) - end - end - - test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do - activity = insert(:note_activity) - meta = [local: false] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end] - }, - { - Pleroma.Web.Federator, - [], - [] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - end - end - - test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do - clear_config([:instance, :federating], false) - - activity = insert(:note_activity) - meta = [local: true] - - with_mocks([ - {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, - { - Pleroma.Web.ActivityPub.MRF, - [], - [filter: fn o -> {:ok, o} end] - }, - { - Pleroma.Web.ActivityPub.ActivityPub, - [], - [persist: fn o, m -> {:ok, o, m} end] - }, - { - Pleroma.Web.ActivityPub.SideEffects, - [], - [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end] - }, - { - Pleroma.Web.Federator, - [], - [] - } - ]) do - assert {:ok, ^activity, ^meta} = - Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) - - assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) - assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) - assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) - end - end - end -end diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs deleted file mode 100644 index b9388b966..000000000 --- a/test/web/activity_pub/publisher_test.exs +++ /dev/null @@ -1,365 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.PublisherTest do - use Pleroma.Web.ConnCase - - import ExUnit.CaptureLog - import Pleroma.Factory - import Tesla.Mock - import Mock - - alias Pleroma.Activity - alias Pleroma.Instances - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Publisher - alias Pleroma.Web.CommonAPI - - @as_public "https://www.w3.org/ns/activitystreams#Public" - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup_all do: clear_config([:instance, :federating], true) - - describe "gather_webfinger_links/1" do - test "it returns links" do - user = insert(:user) - - expected_links = [ - %{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"}, - %{ - "href" => user.ap_id, - "rel" => "self", - "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" - }, - %{ - "rel" => "http://ostatus.org/schema/1.0/subscribe", - "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}" - } - ] - - assert expected_links == Publisher.gather_webfinger_links(user) - end - end - - describe "determine_inbox/2" do - test "it returns sharedInbox for messages involving as:Public in to" do - user = insert(:user, %{shared_inbox: "http://example.com/inbox"}) - - activity = %Activity{ - data: %{"to" => [@as_public], "cc" => [user.follower_address]} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox" - end - - test "it returns sharedInbox for messages involving as:Public in cc" do - user = insert(:user, %{shared_inbox: "http://example.com/inbox"}) - - activity = %Activity{ - data: %{"cc" => [@as_public], "to" => [user.follower_address]} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox" - end - - test "it returns sharedInbox for messages involving multiple recipients in to" do - user = insert(:user, %{shared_inbox: "http://example.com/inbox"}) - user_two = insert(:user) - user_three = insert(:user) - - activity = %Activity{ - data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox" - end - - test "it returns sharedInbox for messages involving multiple recipients in cc" do - user = insert(:user, %{shared_inbox: "http://example.com/inbox"}) - user_two = insert(:user) - user_three = insert(:user) - - activity = %Activity{ - data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox" - end - - test "it returns sharedInbox for messages involving multiple recipients in total" do - user = - insert(:user, %{ - shared_inbox: "http://example.com/inbox", - inbox: "http://example.com/personal-inbox" - }) - - user_two = insert(:user) - - activity = %Activity{ - data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox" - end - - test "it returns inbox for messages involving single recipients in total" do - user = - insert(:user, %{ - shared_inbox: "http://example.com/inbox", - inbox: "http://example.com/personal-inbox" - }) - - activity = %Activity{ - data: %{"to" => [user.ap_id], "cc" => []} - } - - assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox" - end - end - - describe "publish_one/1" do - test "publish to url with with different ports" do - inbox80 = "http://42.site/users/nick1/inbox" - inbox42 = "http://42.site:42/users/nick1/inbox" - - mock(fn - %{method: :post, url: "http://42.site:42/users/nick1/inbox"} -> - {:ok, %Tesla.Env{status: 200, body: "port 42"}} - - %{method: :post, url: "http://42.site/users/nick1/inbox"} -> - {:ok, %Tesla.Env{status: 200, body: "port 80"}} - end) - - actor = insert(:user) - - assert {:ok, %{body: "port 42"}} = - Publisher.publish_one(%{ - inbox: inbox42, - json: "{}", - actor: actor, - id: 1, - unreachable_since: true - }) - - assert {:ok, %{body: "port 80"}} = - Publisher.publish_one(%{ - inbox: inbox80, - json: "{}", - actor: actor, - id: 1, - unreachable_since: true - }) - end - - test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://200.site/users/nick1/inbox" - - assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) - assert called(Instances.set_reachable(inbox)) - end - - test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://200.site/users/nick1/inbox" - - assert {:ok, _} = - Publisher.publish_one(%{ - inbox: inbox, - json: "{}", - actor: actor, - id: 1, - unreachable_since: NaiveDateTime.utc_now() - }) - - assert called(Instances.set_reachable(inbox)) - end - - test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://200.site/users/nick1/inbox" - - assert {:ok, _} = - Publisher.publish_one(%{ - inbox: inbox, - json: "{}", - actor: actor, - id: 1, - unreachable_since: nil - }) - - refute called(Instances.set_reachable(inbox)) - end - - test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://404.site/users/nick1/inbox" - - assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) - - assert called(Instances.set_unreachable(inbox)) - end - - test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://connrefused.site/users/nick1/inbox" - - assert capture_log(fn -> - assert {:error, _} = - Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) - end) =~ "connrefused" - - assert called(Instances.set_unreachable(inbox)) - end - - test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://200.site/users/nick1/inbox" - - assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) - - refute called(Instances.set_unreachable(inbox)) - end - - test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`", - Instances, - [:passthrough], - [] do - actor = insert(:user) - inbox = "http://connrefused.site/users/nick1/inbox" - - assert capture_log(fn -> - assert {:error, _} = - Publisher.publish_one(%{ - inbox: inbox, - json: "{}", - actor: actor, - id: 1, - unreachable_since: NaiveDateTime.utc_now() - }) - end) =~ "connrefused" - - refute called(Instances.set_unreachable(inbox)) - end - end - - describe "publish/2" do - test_with_mock "publishes an activity with BCC to all relevant peers.", - Pleroma.Web.Federator.Publisher, - [:passthrough], - [] do - follower = - insert(:user, %{ - local: false, - inbox: "https://domain.com/users/nick1/inbox", - ap_enabled: true - }) - - actor = insert(:user, follower_address: follower.ap_id) - user = insert(:user) - - {:ok, _follower_one} = Pleroma.User.follow(follower, actor) - actor = refresh_record(actor) - - note_activity = - insert(:note_activity, - recipients: [follower.ap_id], - data_attrs: %{"bcc" => [user.ap_id]} - ) - - res = Publisher.publish(actor, note_activity) - assert res == :ok - - assert called( - Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ - inbox: "https://domain.com/users/nick1/inbox", - actor_id: actor.id, - id: note_activity.data["id"] - }) - ) - end - - test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.", - Pleroma.Web.Federator.Publisher, - [:passthrough], - [] do - fetcher = - insert(:user, - local: false, - inbox: "https://domain.com/users/nick1/inbox", - ap_enabled: true - ) - - another_fetcher = - insert(:user, - local: false, - inbox: "https://domain2.com/users/nick1/inbox", - ap_enabled: true - ) - - actor = insert(:user) - - note_activity = insert(:note_activity, user: actor) - object = Object.normalize(note_activity) - - activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url()) - object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) - - build_conn() - |> put_req_header("accept", "application/activity+json") - |> assign(:user, fetcher) - |> get(object_path) - |> json_response(200) - - build_conn() - |> put_req_header("accept", "application/activity+json") - |> assign(:user, another_fetcher) - |> get(activity_path) - |> json_response(200) - - {:ok, delete} = CommonAPI.delete(note_activity.id, actor) - - res = Publisher.publish(actor, delete) - assert res == :ok - - assert called( - Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ - inbox: "https://domain.com/users/nick1/inbox", - actor_id: actor.id, - id: delete.data["id"] - }) - ) - - assert called( - Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ - inbox: "https://domain2.com/users/nick1/inbox", - actor_id: actor.id, - id: delete.data["id"] - }) - ) - end - end -end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs deleted file mode 100644 index 9d657ac4f..000000000 --- a/test/web/activity_pub/relay_test.exs +++ /dev/null @@ -1,128 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.RelayTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Relay - alias Pleroma.Web.CommonAPI - - import ExUnit.CaptureLog - import Pleroma.Factory - import Mock - - test "gets an actor for the relay" do - user = Relay.get_actor() - assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay" - end - - test "relay actor is invisible" do - user = Relay.get_actor() - assert User.invisible?(user) - end - - describe "follow/1" do - test "returns errors when user not found" do - assert capture_log(fn -> - {:error, _} = Relay.follow("test-ap-id") - end) =~ "Could not decode user at fetch" - end - - test "returns activity" do - user = insert(:user) - service_actor = Relay.get_actor() - assert {:ok, %Activity{} = activity} = Relay.follow(user.ap_id) - assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" - assert user.ap_id in activity.recipients - assert activity.data["type"] == "Follow" - assert activity.data["actor"] == service_actor.ap_id - assert activity.data["object"] == user.ap_id - end - end - - describe "unfollow/1" do - test "returns errors when user not found" do - assert capture_log(fn -> - {:error, _} = Relay.unfollow("test-ap-id") - end) =~ "Could not decode user at fetch" - end - - test "returns activity" do - user = insert(:user) - service_actor = Relay.get_actor() - CommonAPI.follow(service_actor, user) - assert "#{user.ap_id}/followers" in User.following(service_actor) - assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id) - assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" - assert user.ap_id in activity.recipients - assert activity.data["type"] == "Undo" - assert activity.data["actor"] == service_actor.ap_id - assert activity.data["to"] == [user.ap_id] - refute "#{user.ap_id}/followers" in User.following(service_actor) - end - end - - describe "publish/1" do - setup do: clear_config([:instance, :federating]) - - test "returns error when activity not `Create` type" do - activity = insert(:like_activity) - assert Relay.publish(activity) == {:error, "Not implemented"} - end - - @tag capture_log: true - test "returns error when activity not public" do - activity = insert(:direct_note_activity) - assert Relay.publish(activity) == {:error, false} - end - - test "returns error when object is unknown" do - activity = - insert(:note_activity, - data: %{ - "type" => "Create", - "object" => "http://mastodon.example.org/eee/99541947525187367" - } - ) - - Tesla.Mock.mock(fn - %{method: :get, url: "http://mastodon.example.org/eee/99541947525187367"} -> - %Tesla.Env{status: 500, body: ""} - end) - - assert capture_log(fn -> - assert Relay.publish(activity) == {:error, false} - end) =~ "[error] error: false" - end - - test_with_mock "returns announce activity and publish to federate", - Pleroma.Web.Federator, - [:passthrough], - [] do - clear_config([:instance, :federating], true) - service_actor = Relay.get_actor() - note = insert(:note_activity) - assert {:ok, %Activity{} = activity} = Relay.publish(note) - assert activity.data["type"] == "Announce" - assert activity.data["actor"] == service_actor.ap_id - assert activity.data["to"] == [service_actor.follower_address] - assert called(Pleroma.Web.Federator.publish(activity)) - end - - test_with_mock "returns announce activity and not publish to federate", - Pleroma.Web.Federator, - [:passthrough], - [] do - clear_config([:instance, :federating], false) - service_actor = Relay.get_actor() - note = insert(:note_activity) - assert {:ok, %Activity{} = activity} = Relay.publish(note) - assert activity.data["type"] == "Announce" - assert activity.data["actor"] == service_actor.ap_id - refute called(Pleroma.Web.Federator.publish(activity)) - end - end -end diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs deleted file mode 100644 index 4a08eb7ee..000000000 --- a/test/web/activity_pub/side_effects_test.exs +++ /dev/null @@ -1,622 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.SideEffectsTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Builder - alias Pleroma.Web.ActivityPub.SideEffects - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - import Mock - - describe "handle_after_transaction" do - test "it streams out notifications and streams" do - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - assert [notification] = meta[:notifications] - - with_mocks([ - { - Pleroma.Web.Streamer, - [], - [ - stream: fn _, _ -> nil end - ] - }, - { - Pleroma.Web.Push, - [], - [ - send: fn _ -> nil end - ] - } - ]) do - SideEffects.handle_after_transaction(meta) - - assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) - assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) - assert called(Pleroma.Web.Push.send(notification)) - end - end - end - - describe "blocking users" do - setup do - user = insert(:user) - blocked = insert(:user) - User.follow(blocked, user) - User.follow(user, blocked) - - {:ok, block_data, []} = Builder.block(user, blocked) - {:ok, block, _meta} = ActivityPub.persist(block_data, local: true) - - %{user: user, blocked: blocked, block: block} - end - - test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do - assert User.following?(user, blocked) - assert User.following?(blocked, user) - - {:ok, _, _} = SideEffects.handle(block) - - refute User.following?(user, blocked) - refute User.following?(blocked, user) - assert User.blocks?(user, blocked) - end - - test "it blocks but does not unfollow if the relevant setting is set", %{ - user: user, - blocked: blocked, - block: block - } do - clear_config([:activitypub, :unfollow_blocked], false) - assert User.following?(user, blocked) - assert User.following?(blocked, user) - - {:ok, _, _} = SideEffects.handle(block) - - refute User.following?(user, blocked) - assert User.following?(blocked, user) - assert User.blocks?(user, blocked) - end - end - - describe "update users" do - setup do - user = insert(:user) - {:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"}) - {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) - - %{user: user, update_data: update_data, update: update} - end - - test "it updates the user", %{user: user, update: update} do - {:ok, _, _} = SideEffects.handle(update) - user = User.get_by_id(user.id) - assert user.name == "new name!" - end - - test "it uses a given changeset to update", %{user: user, update: update} do - changeset = Ecto.Changeset.change(user, %{default_scope: "direct"}) - - assert user.default_scope == "public" - {:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset) - user = User.get_by_id(user.id) - assert user.default_scope == "direct" - end - end - - describe "delete objects" do - setup do - user = insert(:user) - other_user = insert(:user) - - {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"}) - {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op}) - {:ok, favorite} = CommonAPI.favorite(user, post.id) - object = Object.normalize(post) - {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) - {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) - {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) - {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) - - %{ - user: user, - delete: delete, - post: post, - object: object, - delete_user: delete_user, - op: op, - favorite: favorite - } - end - - test "it handles object deletions", %{ - delete: delete, - post: post, - object: object, - user: user, - op: op, - favorite: favorite - } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end - - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) - refute Activity.get_by_id(favorite.id) - - user = User.get_by_id(user.id) - assert user.note_count == 0 - - object = Object.normalize(op.data["object"], false) - - assert object.data["repliesCount"] == 0 - end - - test "it handles object deletions when the object itself has been pruned", %{ - delete: delete, - post: post, - object: object, - user: user, - op: op - } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end - - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) - - user = User.get_by_id(user.id) - assert user.note_count == 0 - - object = Object.normalize(op.data["object"], false) - - assert object.data["repliesCount"] == 0 - end - - test "it handles user deletions", %{delete_user: delete, user: user} do - {:ok, _delete, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - assert User.get_cached_by_ap_id(user.ap_id).deactivated - end - end - - describe "EmojiReact objects" do - setup do - poster = insert(:user) - user = insert(:user) - - {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) - - {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌") - {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true) - - %{emoji_react: emoji_react, user: user, poster: poster} - end - - test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do - {:ok, emoji_react, _} = SideEffects.handle(emoji_react) - object = Object.get_by_ap_id(emoji_react.data["object"]) - - assert object.data["reaction_count"] == 1 - assert ["👌", [user.ap_id]] in object.data["reactions"] - end - - test "creates a notification", %{emoji_react: emoji_react, poster: poster} do - {:ok, emoji_react, _} = SideEffects.handle(emoji_react) - assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id) - end - end - - describe "delete users with confirmation pending" do - setup do - user = insert(:user, confirmation_pending: true) - {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) - {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) - {:ok, delete: delete_user, user: user} - end - - test "when activation is not required", %{delete: delete, user: user} do - clear_config([:instance, :account_activation_required], false) - {:ok, _, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - assert User.get_cached_by_id(user.id).deactivated - end - - test "when activation is required", %{delete: delete, user: user} do - clear_config([:instance, :account_activation_required], true) - {:ok, _, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - refute User.get_cached_by_id(user.id) - end - end - - describe "Undo objects" do - setup do - poster = insert(:user) - user = insert(:user) - {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) - {:ok, like} = CommonAPI.favorite(user, post.id) - {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍") - {:ok, announce} = CommonAPI.repeat(post.id, user) - {:ok, block} = CommonAPI.block(user, poster) - - {:ok, undo_data, _meta} = Builder.undo(user, like) - {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true) - - {:ok, undo_data, _meta} = Builder.undo(user, reaction) - {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true) - - {:ok, undo_data, _meta} = Builder.undo(user, announce) - {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true) - - {:ok, undo_data, _meta} = Builder.undo(user, block) - {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true) - - %{ - like_undo: like_undo, - post: post, - like: like, - reaction_undo: reaction_undo, - reaction: reaction, - announce_undo: announce_undo, - announce: announce, - block_undo: block_undo, - block: block, - poster: poster, - user: user - } - end - - test "deletes the original block", %{ - block_undo: block_undo, - block: block - } do - {:ok, _block_undo, _meta} = SideEffects.handle(block_undo) - - refute Activity.get_by_id(block.id) - end - - test "unblocks the blocked user", %{block_undo: block_undo, block: block} do - blocker = User.get_by_ap_id(block.data["actor"]) - blocked = User.get_by_ap_id(block.data["object"]) - - {:ok, _block_undo, _} = SideEffects.handle(block_undo) - refute User.blocks?(blocker, blocked) - end - - test "an announce undo removes the announce from the object", %{ - announce_undo: announce_undo, - post: post - } do - {:ok, _announce_undo, _} = SideEffects.handle(announce_undo) - - object = Object.get_by_ap_id(post.data["object"]) - - assert object.data["announcement_count"] == 0 - assert object.data["announcements"] == [] - end - - test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do - {:ok, _announce_undo, _} = SideEffects.handle(announce_undo) - refute Activity.get_by_id(announce.id) - end - - test "a reaction undo removes the reaction from the object", %{ - reaction_undo: reaction_undo, - post: post - } do - {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo) - - object = Object.get_by_ap_id(post.data["object"]) - - assert object.data["reaction_count"] == 0 - assert object.data["reactions"] == [] - end - - test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do - {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo) - refute Activity.get_by_id(reaction.id) - end - - test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do - {:ok, _like_undo, _} = SideEffects.handle(like_undo) - - object = Object.get_by_ap_id(post.data["object"]) - - assert object.data["like_count"] == 0 - assert object.data["likes"] == [] - end - - test "deletes the original like", %{like_undo: like_undo, like: like} do - {:ok, _like_undo, _} = SideEffects.handle(like_undo) - refute Activity.get_by_id(like.id) - end - end - - describe "like objects" do - setup do - poster = insert(:user) - user = insert(:user) - {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) - - {:ok, like_data, _meta} = Builder.like(user, post.object) - {:ok, like, _meta} = ActivityPub.persist(like_data, local: true) - - %{like: like, user: user, poster: poster} - end - - test "add the like to the original object", %{like: like, user: user} do - {:ok, like, _} = SideEffects.handle(like) - object = Object.get_by_ap_id(like.data["object"]) - assert object.data["like_count"] == 1 - assert user.ap_id in object.data["likes"] - end - - test "creates a notification", %{like: like, poster: poster} do - {:ok, like, _} = SideEffects.handle(like) - assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id) - end - end - - describe "creation of ChatMessages" do - test "notifies the recipient" do - author = insert(:user, local: false) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id) - end - - test "it streams the created ChatMessage" do - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - assert [_, _] = meta[:streamables] - end - - test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - with_mocks([ - { - Pleroma.Web.Streamer, - [], - [ - stream: fn _, _ -> nil end - ] - }, - { - Pleroma.Web.Push, - [], - [ - send: fn _ -> nil end - ] - } - ]) do - {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # The notification gets created - assert [notification] = meta[:notifications] - assert notification.activity_id == create_activity.id - - # But it is not sent out - refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) - refute called(Pleroma.Web.Push.send(notification)) - - # Same for the user chat stream - assert [{topics, _}, _] = meta[:streamables] - assert topics == ["user", "user:pleroma_chat"] - refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) - - chat = Chat.get(author.id, recipient.ap_id) - - [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() - - assert cm_ref.object.data["content"] == "hey" - assert cm_ref.unread == false - - chat = Chat.get(recipient.id, author.ap_id) - - [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() - - assert cm_ref.object.data["content"] == "hey" - assert cm_ref.unread == true - end - end - - test "it creates a Chat for the local users and bumps the unread count" do - author = insert(:user, local: false) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # An object is created - assert Object.get_by_ap_id(chat_message_data["id"]) - - # The remote user won't get a chat - chat = Chat.get(author.id, recipient.ap_id) - refute chat - - # The local user will get a chat - chat = Chat.get(recipient.id, author.ap_id) - assert chat - - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # Both users are local and get the chat - chat = Chat.get(author.id, recipient.ap_id) - assert chat - - chat = Chat.get(recipient.id, author.ap_id) - assert chat - end - end - - describe "announce objects" do - setup do - poster = insert(:user) - user = insert(:user) - {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) - {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"}) - - {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true) - - {:ok, private_announce_data, _meta} = - Builder.announce(user, private_post.object, public: false) - - {:ok, relay_announce_data, _meta} = - Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true) - - {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true) - {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true) - {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true) - - %{ - announce: announce, - user: user, - poster: poster, - private_announce: private_announce, - relay_announce: relay_announce - } - end - - test "adds the announce to the original object", %{announce: announce, user: user} do - {:ok, announce, _} = SideEffects.handle(announce) - object = Object.get_by_ap_id(announce.data["object"]) - assert object.data["announcement_count"] == 1 - assert user.ap_id in object.data["announcements"] - end - - test "does not add the announce to the original object if the actor is a service actor", %{ - relay_announce: announce - } do - {:ok, announce, _} = SideEffects.handle(announce) - object = Object.get_by_ap_id(announce.data["object"]) - assert object.data["announcement_count"] == nil - end - - test "creates a notification", %{announce: announce, poster: poster} do - {:ok, announce, _} = SideEffects.handle(announce) - assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id) - end - - test "it streams out the announce", %{announce: announce} do - with_mocks([ - { - Pleroma.Web.Streamer, - [], - [ - stream: fn _, _ -> nil end - ] - }, - { - Pleroma.Web.Push, - [], - [ - send: fn _ -> nil end - ] - } - ]) do - {:ok, announce, _} = SideEffects.handle(announce) - - assert called( - Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce) - ) - - assert called(Pleroma.Web.Push.send(:_)) - end - end - end -end diff --git a/test/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/web/activity_pub/transmogrifier/announce_handling_test.exs deleted file mode 100644 index e895636b5..000000000 --- a/test/web/activity_pub/transmogrifier/announce_handling_test.exs +++ /dev/null @@ -1,172 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "it works for incoming honk announces" do - user = insert(:user, ap_id: "https://honktest/u/test", local: false) - other_user = insert(:user) - {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"}) - - announce = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => "https://honktest/u/test", - "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx", - "object" => post.data["object"], - "published" => "2019-06-25T19:33:58Z", - "to" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Announce" - } - - {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce) - - object = Object.get_by_ap_id(post.data["object"]) - - assert length(object.data["announcements"]) == 1 - assert user.ap_id in object.data["announcements"] - end - - test "it works for incoming announces with actor being inlined (kroeg)" do - data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!() - - _user = insert(:user, local: false, ap_id: data["actor"]["id"]) - other_user = insert(:user) - - {:ok, post} = CommonAPI.post(other_user, %{status: "kroegeroeg"}) - - data = - data - |> put_in(["object", "id"], post.data["object"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "https://puckipedia.com/" - end - - test "it works for incoming announces, fetching the announced object" do - data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367") - - Tesla.Mock.mock(fn - %{method: :get} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")} - end) - - _user = insert(:user, local: false, ap_id: data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Announce" - - assert data["id"] == - "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - - assert data["object"] == - "http://mastodon.example.org/users/admin/statuses/99541947525187367" - - assert(Activity.get_create_by_object_ap_id(data["object"])) - end - - @tag capture_log: true - test "it works for incoming announces with an existing activity" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - - data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _user = insert(:user, local: false, ap_id: data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Announce" - - assert data["id"] == - "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - - assert data["object"] == activity.data["object"] - - assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id - end - - # Ignore inlined activities for now - @tag skip: true - test "it works for incoming announces with an inlined activity" do - data = - File.read!("test/fixtures/mastodon-announce-private.json") - |> Poison.decode!() - - _user = - insert(:user, - local: false, - ap_id: data["actor"], - follower_address: data["actor"] <> "/followers" - ) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Announce" - - assert data["id"] == - "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - - object = Object.normalize(data["object"]) - - assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368" - assert object.data["content"] == "this is a private toot" - end - - @tag capture_log: true - test "it rejects incoming announces with an inlined activity from another origin" do - Tesla.Mock.mock(fn - %{method: :get} -> %Tesla.Env{status: 404, body: ""} - end) - - data = - File.read!("test/fixtures/bogus-mastodon-announce.json") - |> Poison.decode!() - - _user = insert(:user, local: false, ap_id: data["actor"]) - - assert {:error, e} = Transmogrifier.handle_incoming(data) - end - - test "it does not clobber the addressing on announce activities" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - - data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", Object.normalize(activity).data["id"]) - |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"]) - |> Map.put("cc", []) - - _user = - insert(:user, - local: false, - ap_id: data["actor"], - follower_address: "http://mastodon.example.org/users/admin/followers" - ) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["to"] == ["http://mastodon.example.org/users/admin/followers"] - end -end diff --git a/test/web/activity_pub/transmogrifier/block_handling_test.exs b/test/web/activity_pub/transmogrifier/block_handling_test.exs deleted file mode 100644 index 71f1a0ed5..000000000 --- a/test/web/activity_pub/transmogrifier/block_handling_test.exs +++ /dev/null @@ -1,63 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - - import Pleroma.Factory - - test "it works for incoming blocks" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - blocker = insert(:user, ap_id: data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Block" - assert data["object"] == user.ap_id - assert data["actor"] == "http://mastodon.example.org/users/admin" - - assert User.blocks?(blocker, user) - end - - test "incoming blocks successfully tear down any follow relationship" do - blocker = insert(:user) - blocked = insert(:user) - - data = - File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() - |> Map.put("object", blocked.ap_id) - |> Map.put("actor", blocker.ap_id) - - {:ok, blocker} = User.follow(blocker, blocked) - {:ok, blocked} = User.follow(blocked, blocker) - - assert User.following?(blocker, blocked) - assert User.following?(blocked, blocker) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Block" - assert data["object"] == blocked.ap_id - assert data["actor"] == blocker.ap_id - - blocker = User.get_cached_by_ap_id(data["actor"]) - blocked = User.get_cached_by_ap_id(data["object"]) - - assert User.blocks?(blocker, blocked) - - refute User.following?(blocker, blocked) - refute User.following?(blocked, blocker) - end -end diff --git a/test/web/activity_pub/transmogrifier/chat_message_test.exs b/test/web/activity_pub/transmogrifier/chat_message_test.exs deleted file mode 100644 index d6736dc3e..000000000 --- a/test/web/activity_pub/transmogrifier/chat_message_test.exs +++ /dev/null @@ -1,153 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do - use Pleroma.DataCase - - import Pleroma.Factory - - alias Pleroma.Activity - alias Pleroma.Chat - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Transmogrifier - - describe "handle_incoming" do - test "handles chonks with attachment" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => "https://honk.tedunangst.com/u/tedu", - "id" => "https://honk.tedunangst.com/u/tedu/honk/x6gt8X8PcyGkQcXxzg1T", - "object" => %{ - "attachment" => [ - %{ - "mediaType" => "image/jpeg", - "name" => "298p3RG7j27tfsZ9RQ.jpg", - "summary" => "298p3RG7j27tfsZ9RQ.jpg", - "type" => "Document", - "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" - } - ], - "attributedTo" => "https://honk.tedunangst.com/u/tedu", - "content" => "", - "id" => "https://honk.tedunangst.com/u/tedu/chonk/26L4wl5yCbn4dr4y1b", - "published" => "2020-05-18T01:13:03Z", - "to" => [ - "https://dontbulling.me/users/lain" - ], - "type" => "ChatMessage" - }, - "published" => "2020-05-18T01:13:03Z", - "to" => [ - "https://dontbulling.me/users/lain" - ], - "type" => "Create" - } - - _user = insert(:user, ap_id: data["actor"]) - _user = insert(:user, ap_id: hd(data["to"])) - - assert {:ok, _activity} = Transmogrifier.handle_incoming(data) - end - - test "it rejects messages that don't contain content" do - data = - File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() - - object = - data["object"] - |> Map.delete("content") - - data = - data - |> Map.put("object", object) - - _author = - insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) - - _recipient = - insert(:user, - ap_id: List.first(data["to"]), - local: true, - last_refreshed_at: DateTime.utc_now() - ) - - {:error, _} = Transmogrifier.handle_incoming(data) - end - - test "it rejects messages that don't concern local users" do - data = - File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() - - _author = - insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) - - _recipient = - insert(:user, - ap_id: List.first(data["to"]), - local: false, - last_refreshed_at: DateTime.utc_now() - ) - - {:error, _} = Transmogrifier.handle_incoming(data) - end - - test "it rejects messages where the `to` field of activity and object don't match" do - data = - File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() - - author = insert(:user, ap_id: data["actor"]) - _recipient = insert(:user, ap_id: List.first(data["to"])) - - data = - data - |> Map.put("to", author.ap_id) - - assert match?({:error, _}, Transmogrifier.handle_incoming(data)) - refute Object.get_by_ap_id(data["object"]["id"]) - end - - test "it fetches the actor if they aren't in our system" do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - - data = - File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() - |> Map.put("actor", "http://mastodon.example.org/users/admin") - |> put_in(["object", "actor"], "http://mastodon.example.org/users/admin") - - _recipient = insert(:user, ap_id: List.first(data["to"]), local: true) - - {:ok, %Activity{} = _activity} = Transmogrifier.handle_incoming(data) - end - - test "it inserts it and creates a chat" do - data = - File.read!("test/fixtures/create-chat-message.json") - |> Poison.decode!() - - author = - insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) - - recipient = insert(:user, ap_id: List.first(data["to"]), local: true) - - {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) - assert activity.local == false - - assert activity.actor == author.ap_id - assert activity.recipients == [recipient.ap_id, author.ap_id] - - %Object{} = object = Object.get_by_ap_id(activity.data["object"]) - - assert object - assert object.data["content"] == "You expected a cute girl? Too bad. alert('XSS')" - assert match?(%{"firefox" => _}, object.data["emoji"]) - - refute Chat.get(author.id, recipient.ap_id) - assert Chat.get(recipient.id, author.ap_id) - end - end -end diff --git a/test/web/activity_pub/transmogrifier/delete_handling_test.exs b/test/web/activity_pub/transmogrifier/delete_handling_test.exs deleted file mode 100644 index c9a53918c..000000000 --- a/test/web/activity_pub/transmogrifier/delete_handling_test.exs +++ /dev/null @@ -1,114 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - - import Pleroma.Factory - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - test "it works for incoming deletes" do - activity = insert(:note_activity) - deleting_user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() - |> Map.put("actor", deleting_user.ap_id) - |> put_in(["object", "id"], activity.data["object"]) - - {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} = - Transmogrifier.handle_incoming(data) - - assert id == data["id"] - - # We delete the Create activity because we base our timelines on it. - # This should be changed after we unify objects and activities - refute Activity.get_by_id(activity.id) - assert actor == deleting_user.ap_id - - # Objects are replaced by a tombstone object. - object = Object.normalize(activity.data["object"]) - assert object.data["type"] == "Tombstone" - end - - test "it works for incoming when the object has been pruned" do - activity = insert(:note_activity) - - {:ok, object} = - Object.normalize(activity.data["object"]) - |> Repo.delete() - - Cachex.del(:object_cache, "object:#{object.data["id"]}") - - deleting_user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() - |> Map.put("actor", deleting_user.ap_id) - |> put_in(["object", "id"], activity.data["object"]) - - {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} = - Transmogrifier.handle_incoming(data) - - assert id == data["id"] - - # We delete the Create activity because we base our timelines on it. - # This should be changed after we unify objects and activities - refute Activity.get_by_id(activity.id) - assert actor == deleting_user.ap_id - end - - test "it fails for incoming deletes with spoofed origin" do - activity = insert(:note_activity) - %{ap_id: ap_id} = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo") - - data = - File.read!("test/fixtures/mastodon-delete.json") - |> Poison.decode!() - |> Map.put("actor", ap_id) - |> put_in(["object", "id"], activity.data["object"]) - - assert match?({:error, _}, Transmogrifier.handle_incoming(data)) - end - - @tag capture_log: true - 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) - ObanHelpers.perform_all() - - assert User.get_cached_by_ap_id(ap_id).deactivated - 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 match?({:error, _}, Transmogrifier.handle_incoming(data)) - - assert User.get_cached_by_ap_id(ap_id) - end -end diff --git a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs deleted file mode 100644 index 0fb056b50..000000000 --- a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs +++ /dev/null @@ -1,61 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "it works for incoming emoji reactions" do - user = insert(:user) - other_user = insert(:user, local: false) - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - - data = - File.read!("test/fixtures/emoji-reaction.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - |> Map.put("actor", other_user.ap_id) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == other_user.ap_id - assert data["type"] == "EmojiReact" - assert data["id"] == "http://mastodon.example.org/users/admin#reactions/2" - assert data["object"] == activity.data["object"] - assert data["content"] == "👌" - - object = Object.get_by_ap_id(data["object"]) - - assert object.data["reaction_count"] == 1 - assert match?([["👌", _]], object.data["reactions"]) - end - - test "it reject invalid emoji reactions" do - user = insert(:user) - other_user = insert(:user, local: false) - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - - data = - File.read!("test/fixtures/emoji-reaction-too-long.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - |> Map.put("actor", other_user.ap_id) - - assert {:error, _} = Transmogrifier.handle_incoming(data) - - data = - File.read!("test/fixtures/emoji-reaction-no-emoji.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - |> Map.put("actor", other_user.ap_id) - - assert {:error, _} = Transmogrifier.handle_incoming(data) - end -end diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs deleted file mode 100644 index 17e764ca1..000000000 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ /dev/null @@ -1,189 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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.Notification - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.ActivityPub.Utils - - import Pleroma.Factory - import Ecto.Query - import Mock - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - describe "handle_incoming" do - setup do: clear_config([:user, :deny_follow_blocked]) - - test "it works for osada follow request" do - user = insert(:user) - - data = - File.read!("test/fixtures/osada-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"] == "https://apfed.club/channel/indio" - assert data["type"] == "Follow" - assert data["id"] == "https://apfed.club/follow/9" - - 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 "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) - - [notification] = Notification.for_user(user) - assert notification.type == "follow" - end - - test "with locked accounts, it does create a Follow, but not an Accept" do - user = insert(:user, 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 Enum.empty?(accepts) - - [notification] = Notification.for_user(user) - assert notification.type == "follow_request" - 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_relationship} = 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 rejects incoming follow requests if the following errors for some reason" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - with_mock Pleroma.User, [:passthrough], follow: fn _, _, _ -> {:error, :testing} end do - {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) - - %Activity{} = activity = Activity.get_by_ap_id(id) - - assert activity.data["state"] == "reject" - end - 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/like_handling_test.exs b/test/web/activity_pub/transmogrifier/like_handling_test.exs deleted file mode 100644 index 53fe1d550..000000000 --- a/test/web/activity_pub/transmogrifier/like_handling_test.exs +++ /dev/null @@ -1,78 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "it works for incoming likes" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - - data = - File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _actor = insert(:user, ap_id: data["actor"], local: false) - - {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) - - refute Enum.empty?(activity.recipients) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Like" - assert data["id"] == "http://mastodon.example.org/users/admin#likes/2" - assert data["object"] == activity.data["object"] - end - - test "it works for incoming misskey likes, turning them into EmojiReacts" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - - data = - File.read!("test/fixtures/misskey-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _actor = insert(:user, ap_id: data["actor"], local: false) - - {:ok, %Activity{data: activity_data, local: false}} = Transmogrifier.handle_incoming(data) - - assert activity_data["actor"] == data["actor"] - assert activity_data["type"] == "EmojiReact" - assert activity_data["id"] == data["id"] - assert activity_data["object"] == activity.data["object"] - assert activity_data["content"] == "🍮" - end - - test "it works for incoming misskey likes that contain unicode emojis, turning them into EmojiReacts" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - - data = - File.read!("test/fixtures/misskey-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - |> Map.put("_misskey_reaction", "⭐") - - _actor = insert(:user, ap_id: data["actor"], local: false) - - {:ok, %Activity{data: activity_data, local: false}} = Transmogrifier.handle_incoming(data) - - assert activity_data["actor"] == data["actor"] - assert activity_data["type"] == "EmojiReact" - assert activity_data["id"] == data["id"] - assert activity_data["object"] == activity.data["object"] - assert activity_data["content"] == "⭐" - end -end diff --git a/test/web/activity_pub/transmogrifier/undo_handling_test.exs b/test/web/activity_pub/transmogrifier/undo_handling_test.exs deleted file mode 100644 index 01dd6c370..000000000 --- a/test/web/activity_pub/transmogrifier/undo_handling_test.exs +++ /dev/null @@ -1,185 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "it works for incoming emoji reaction undos" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) - {:ok, reaction_activity} = CommonAPI.react_with_emoji(activity.id, user, "👌") - - data = - File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() - |> Map.put("object", reaction_activity.data["id"]) - |> Map.put("actor", user.ap_id) - - {:ok, activity} = Transmogrifier.handle_incoming(data) - - assert activity.actor == user.ap_id - assert activity.data["id"] == data["id"] - assert activity.data["type"] == "Undo" - end - - test "it returns an error for incoming unlikes wihout a like activity" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"}) - - data = - File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - assert Transmogrifier.handle_incoming(data) == :error - end - - test "it works for incoming unlikes with an existing like activity" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"}) - - like_data = - File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _liker = insert(:user, ap_id: like_data["actor"], local: false) - - {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data) - - data = - File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() - |> Map.put("object", like_data) - |> Map.put("actor", like_data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Undo" - assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo" - assert data["object"] == "http://mastodon.example.org/users/admin#likes/2" - - note = Object.get_by_ap_id(like_data["object"]) - assert note.data["like_count"] == 0 - assert note.data["likes"] == [] - end - - test "it works for incoming unlikes with an existing like activity and a compact object" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "leave a like pls"}) - - like_data = - File.read!("test/fixtures/mastodon-like.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _liker = insert(:user, ap_id: like_data["actor"], local: false) - - {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data) - - data = - File.read!("test/fixtures/mastodon-undo-like.json") - |> Poison.decode!() - |> Map.put("object", like_data["id"]) - |> Map.put("actor", like_data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["actor"] == "http://mastodon.example.org/users/admin" - assert data["type"] == "Undo" - assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo" - assert data["object"] == "http://mastodon.example.org/users/admin#likes/2" - end - - test "it works for incoming unannounces with an existing notice" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - - announce_data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - - _announcer = insert(:user, ap_id: announce_data["actor"], local: false) - - {:ok, %Activity{data: announce_data, local: false}} = - Transmogrifier.handle_incoming(announce_data) - - data = - File.read!("test/fixtures/mastodon-undo-announce.json") - |> Poison.decode!() - |> Map.put("object", announce_data) - |> Map.put("actor", announce_data["actor"]) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Undo" - - assert data["object"] == - "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - end - - test "it works for incomming unfollows with an existing follow" do - user = insert(:user) - - follow_data = - File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - _follower = insert(:user, ap_id: follow_data["actor"], local: false) - - {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data) - - data = - File.read!("test/fixtures/mastodon-unfollow-activity.json") - |> Poison.decode!() - |> Map.put("object", follow_data) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Undo" - assert data["object"]["type"] == "Follow" - assert data["object"]["object"] == user.ap_id - assert data["actor"] == "http://mastodon.example.org/users/admin" - - refute User.following?(User.get_cached_by_ap_id(data["actor"]), user) - end - - test "it works for incoming unblocks with an existing block" do - user = insert(:user) - - block_data = - File.read!("test/fixtures/mastodon-block-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - _blocker = insert(:user, ap_id: block_data["actor"], local: false) - - {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data) - - data = - File.read!("test/fixtures/mastodon-unblock-activity.json") - |> Poison.decode!() - |> Map.put("object", block_data) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - assert data["type"] == "Undo" - assert data["object"] == block_data["id"] - - blocker = User.get_cached_by_ap_id(data["actor"]) - - refute User.blocks?(blocker, user) - end -end diff --git a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs b/test/web/activity_pub/transmogrifier/user_update_handling_test.exs deleted file mode 100644 index 64636656c..000000000 --- a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs +++ /dev/null @@ -1,159 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - - import Pleroma.Factory - - test "it works for incoming update activities" do - user = insert(:user, local: false) - - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - - object = - update_data["object"] - |> Map.put("actor", user.ap_id) - |> Map.put("id", user.ap_id) - - update_data = - update_data - |> Map.put("actor", user.ap_id) - |> Map.put("object", object) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) - - assert data["id"] == update_data["id"] - - user = User.get_cached_by_ap_id(data["actor"]) - assert user.name == "gargle" - - assert user.avatar["url"] == [ - %{ - "href" => - "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" - } - ] - - assert user.banner["url"] == [ - %{ - "href" => - "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" - } - ] - - assert user.bio == "<p>Some bio</p>" - end - - test "it works with alsoKnownAs" do - %{ap_id: actor} = insert(:user, local: false) - - assert User.get_cached_by_ap_id(actor).also_known_as == [] - - {:ok, _activity} = - "test/fixtures/mastodon-update.json" - |> File.read!() - |> Poison.decode!() - |> Map.put("actor", actor) - |> Map.update!("object", fn object -> - object - |> Map.put("actor", actor) - |> Map.put("id", actor) - |> Map.put("alsoKnownAs", [ - "http://mastodon.example.org/users/foo", - "http://example.org/users/bar" - ]) - end) - |> Transmogrifier.handle_incoming() - - assert User.get_cached_by_ap_id(actor).also_known_as == [ - "http://mastodon.example.org/users/foo", - "http://example.org/users/bar" - ] - end - - test "it works with custom profile fields" do - user = insert(:user, local: false) - - assert user.fields == [] - - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - - object = - update_data["object"] - |> Map.put("actor", user.ap_id) - |> Map.put("id", user.ap_id) - - update_data = - update_data - |> Map.put("actor", user.ap_id) - |> Map.put("object", object) - - {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.fields == [ - %{"name" => "foo", "value" => "updated"}, - %{"name" => "foo1", "value" => "updated"} - ] - - Pleroma.Config.put([:instance, :max_remote_account_fields], 2) - - update_data = - update_data - |> put_in(["object", "attachment"], [ - %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, - %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"}, - %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"} - ]) - |> Map.put("id", update_data["id"] <> ".") - - {:ok, _} = Transmogrifier.handle_incoming(update_data) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.fields == [ - %{"name" => "foo", "value" => "updated"}, - %{"name" => "foo1", "value" => "updated"} - ] - - update_data = - update_data - |> put_in(["object", "attachment"], []) - |> Map.put("id", update_data["id"] <> ".") - - {:ok, _} = Transmogrifier.handle_incoming(update_data) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert user.fields == [] - end - - test "it works for incoming update activities which lock the account" do - user = insert(:user, local: false) - - update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - - object = - update_data["object"] - |> Map.put("actor", user.ap_id) - |> Map.put("id", user.ap_id) - |> Map.put("manuallyApprovesFollowers", true) - - update_data = - update_data - |> Map.put("actor", user.ap_id) - |> Map.put("object", object) - - {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data) - - user = User.get_cached_by_ap_id(user.ap_id) - assert user.locked == true - end -end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs deleted file mode 100644 index 7d33feaf2..000000000 --- a/test/web/activity_pub/transmogrifier_test.exs +++ /dev/null @@ -1,1654 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Object.Fetcher - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.CommonAPI - - import Mock - import Pleroma.Factory - import ExUnit.CaptureLog - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance, :max_remote_account_fields]) - - describe "handle_incoming" do - test "it works for incoming notices with tag not being an array (kroeg)" do - data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["emoji"] == %{ - "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png" - } - - data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert "test" in object.data["tag"] - end - - test "it works for incoming notices with url not being a string (prismo)" do - data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["url"] == "https://prismo.news/posts/83" - end - - test "it cleans up incoming notices which are not really DMs" do - user = insert(:user) - other_user = insert(:user) - - to = [user.ap_id, other_user.ap_id] - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("to", to) - |> Map.put("cc", []) - - object = - data["object"] - |> Map.put("to", to) - |> Map.put("cc", []) - - data = Map.put(data, "object", object) - - {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert data["to"] == [] - assert data["cc"] == to - - object_data = Object.normalize(activity).data - - assert object_data["to"] == [] - assert object_data["cc"] == to - end - - test "it ignores an incoming notice if we already have it" do - activity = insert(:note_activity) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("object", Object.normalize(activity).data) - - {:ok, returned_activity} = Transmogrifier.handle_incoming(data) - - assert activity == returned_activity - end - - @tag capture_log: true - test "it fetches reply-to activities if we don't have them" 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) - {:ok, returned_activity} = Transmogrifier.handle_incoming(data) - returned_object = Object.normalize(returned_activity, false) - - assert activity = - 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 - - test "it does not fetch reply-to activities beyond max replies depth limit" 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_thread_distance?: 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) =~ "[warn] 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!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["id"] == - "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity" - - assert data["context"] == - "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" - - assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - - assert data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" - ] - - assert data["actor"] == "http://mastodon.example.org/users/admin" - - object_data = Object.normalize(data["object"]).data - - assert object_data["id"] == - "http://mastodon.example.org/users/admin/statuses/99512778738411822" - - assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"] - - assert object_data["cc"] == [ - "http://mastodon.example.org/users/admin/followers", - "http://localtesting.pleroma.lol/users/lain" - ] - - assert object_data["actor"] == "http://mastodon.example.org/users/admin" - assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin" - - assert object_data["context"] == - "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation" - - assert object_data["sensitive"] == true - - user = User.get_cached_by_ap_id(object_data["actor"]) - - assert user.note_count == 1 - end - - test "it works for incoming notices with hashtags" do - data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - 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 works for incoming listens" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Listen", - "id" => "http://mastodon.example.org/users/admin/listens/1234/activity", - "actor" => "http://mastodon.example.org/users/admin", - "object" => %{ - "type" => "Audio", - "id" => "http://mastodon.example.org/users/admin/listens/1234", - "attributedTo" => "http://mastodon.example.org/users/admin", - "title" => "lain radio episode 1", - "artist" => "lain", - "album" => "lain radio", - "length" => 180_000 - } - } - - {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - - object = Object.normalize(activity) - - assert object.data["title"] == "lain radio episode 1" - assert object.data["artist"] == "lain" - assert object.data["album"] == "lain radio" - assert object.data["length"] == 180_000 - 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!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["content"] == - "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>" - end - - test "it works for incoming notices with to/cc not being an array (kroeg)" do - data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - object = Object.normalize(data["object"]) - - assert object.data["content"] == - "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>" - end - - test "it ensures that as:Public activities make it to their followers collection" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("actor", user.ap_id) - |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) - |> Map.put("cc", []) - - object = - data["object"] - |> 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) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["cc"] == [User.ap_followers(user)] - end - - test "it ensures that address fields become lists" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - |> Map.put("actor", user.ap_id) - |> Map.put("to", nil) - |> Map.put("cc", nil) - - object = - data["object"] - |> 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) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert !is_nil(data["to"]) - assert !is_nil(data["cc"]) - end - - test "it strips internal likes" do - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - likes = %{ - "first" => - "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", - "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", - "totalItems" => 3, - "type" => "OrderedCollection" - } - - object = Map.put(data["object"], "likes", likes) - data = Map.put(data, "object", object) - - {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data) - - refute Map.has_key?(object.data, "likes") - end - - test "it strips internal reactions" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢") - - %{object: object} = Activity.get_by_id_with_object(activity.id) - assert Map.has_key?(object.data, "reactions") - assert Map.has_key?(object.data, "reaction_count") - - object_data = Transmogrifier.strip_internal_fields(object.data) - refute Map.has_key?(object_data, "reactions") - refute Map.has_key?(object_data, "reaction_count") - end - - test "it works for incomming unfollows with an existing follow" do - user = insert(:user) - - follow_data = - File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - - {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data) - - data = - File.read!("test/fixtures/mastodon-unfollow-activity.json") - |> Poison.decode!() - |> Map.put("object", follow_data) - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - assert data["type"] == "Undo" - assert data["object"]["type"] == "Follow" - assert data["object"]["object"] == user.ap_id - assert data["actor"] == "http://mastodon.example.org/users/admin" - - refute User.following?(User.get_cached_by_ap_id(data["actor"]), user) - end - - test "it works for incoming follows to locked account" do - pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin") - user = insert(:user, 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["type"] == "Follow" - assert data["object"] == user.ap_id - assert data["state"] == "pending" - assert data["actor"] == "http://mastodon.example.org/users/admin" - - assert [^pending_follower] = User.get_follow_requests(user) - end - - test "it works for incoming accepts which were pre-accepted" do - follower = insert(:user) - followed = insert(:user) - - {:ok, follower} = User.follow(follower, followed) - assert User.following?(follower, followed) == true - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - - accept_data = - File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - - object = - accept_data["object"] - |> Map.put("actor", follower.ap_id) - |> Map.put("id", follow_activity.data["id"]) - - accept_data = Map.put(accept_data, "object", object) - - {:ok, activity} = Transmogrifier.handle_incoming(accept_data) - refute activity.local - - assert activity.data["object"] == follow_activity.data["id"] - - assert activity.data["id"] == accept_data["id"] - - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, followed) == true - end - - test "it works for incoming accepts which were orphaned" do - follower = insert(:user) - followed = insert(:user, locked: true) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - - accept_data = - File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - - accept_data = - Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id)) - - {:ok, activity} = Transmogrifier.handle_incoming(accept_data) - assert activity.data["object"] == follow_activity.data["id"] - - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, followed) == true - end - - test "it works for incoming accepts which are referenced by IRI only" do - follower = insert(:user) - followed = insert(:user, locked: true) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - - accept_data = - File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - |> Map.put("object", follow_activity.data["id"]) - - {:ok, activity} = Transmogrifier.handle_incoming(accept_data) - assert activity.data["object"] == follow_activity.data["id"] - - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, followed) == true - - follower = User.get_by_id(follower.id) - assert follower.following_count == 1 - - followed = User.get_by_id(followed.id) - assert followed.follower_count == 1 - end - - test "it fails for incoming accepts which cannot be correlated" do - follower = insert(:user) - followed = insert(:user, locked: true) - - accept_data = - File.read!("test/fixtures/mastodon-accept-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - - accept_data = - Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id)) - - :error = Transmogrifier.handle_incoming(accept_data) - - follower = User.get_cached_by_id(follower.id) - - refute User.following?(follower, followed) == true - end - - test "it fails for incoming rejects which cannot be correlated" do - follower = insert(:user) - followed = insert(:user, locked: true) - - accept_data = - File.read!("test/fixtures/mastodon-reject-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - - accept_data = - Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id)) - - :error = Transmogrifier.handle_incoming(accept_data) - - follower = User.get_cached_by_id(follower.id) - - refute User.following?(follower, followed) == true - end - - test "it works for incoming rejects which are orphaned" do - follower = insert(:user) - followed = insert(:user, locked: true) - - {:ok, follower} = User.follow(follower, followed) - {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, followed) - - assert User.following?(follower, followed) == true - - reject_data = - File.read!("test/fixtures/mastodon-reject-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - - reject_data = - Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id)) - - {:ok, activity} = Transmogrifier.handle_incoming(reject_data) - refute activity.local - assert activity.data["id"] == reject_data["id"] - - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, followed) == false - end - - test "it works for incoming rejects which are referenced by IRI only" do - follower = insert(:user) - followed = insert(:user, locked: true) - - {:ok, follower} = User.follow(follower, followed) - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) - - assert User.following?(follower, followed) == true - - reject_data = - File.read!("test/fixtures/mastodon-reject-activity.json") - |> Poison.decode!() - |> Map.put("actor", followed.ap_id) - |> Map.put("object", follow_activity.data["id"]) - - {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data) - - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, followed) == false - end - - test "it rejects activities without a valid ID" do - user = insert(:user) - - data = - File.read!("test/fixtures/mastodon-follow-activity.json") - |> Poison.decode!() - |> Map.put("object", user.ap_id) - |> Map.put("id", "") - - :error = Transmogrifier.handle_incoming(data) - end - - test "skip converting the content when it is nil" do - object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe" - - {:ok, object} = Fetcher.fetch_and_contain_remote_object_from_id(object_id) - - result = - Pleroma.Web.ActivityPub.Transmogrifier.fix_object(Map.merge(object, %{"content" => nil})) - - assert result["content"] == nil - end - - test "it converts content of object to html" do - object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe" - - {:ok, %{"content" => content_markdown}} = - Fetcher.fetch_and_contain_remote_object_from_id(object_id) - - {:ok, %Pleroma.Object{data: %{"content" => content}} = object} = - Fetcher.fetch_object_from_id(object_id) - - assert content_markdown == - "Support this and our other Michigan!/usr/group videos and meetings. Learn more at http://mug.org/membership\n\nTwenty Years in Jail: FreeBSD's Jails, Then and Now\n\nJails started as a limited virtualization system, but over the last two years they've..." - - assert content == - "<p>Support this and our other Michigan!/usr/group videos and meetings. Learn more at <a href=\"http://mug.org/membership\">http://mug.org/membership</a></p><p>Twenty Years in Jail: FreeBSD’s Jails, Then and Now</p><p>Jails started as a limited virtualization system, but over the last two years they’ve…</p>" - - assert object.data["mediaType"] == "text/html" - end - - test "it remaps video URLs as attachments if necessary" do - {:ok, object} = - Fetcher.fetch_object_from_id( - "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" - ) - - assert object.data["url"] == - "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" - - assert object.data["attachment"] == [ - %{ - "type" => "Link", - "mediaType" => "video/mp4", - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4" - } - ] - } - ] - - {:ok, object} = - Fetcher.fetch_object_from_id( - "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" - ) - - assert object.data["attachment"] == [ - %{ - "type" => "Link", - "mediaType" => "video/mp4", - "url" => [ - %{ - "href" => - "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", - "mediaType" => "video/mp4" - } - ] - } - ] - - assert object.data["url"] == - "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" - end - - test "it accepts Flag activities" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "test post"}) - object = Object.normalize(activity) - - note_obj = %{ - "type" => "Note", - "id" => activity.data["id"], - "content" => "test post", - "published" => object.data["published"], - "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - } - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "cc" => [user.ap_id], - "object" => [user.ap_id, activity.data["id"]], - "type" => "Flag", - "content" => "blocked AND reported!!!", - "actor" => other_user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert activity.data["object"] == [user.ap_id, note_obj] - assert activity.data["content"] == "blocked AND reported!!!" - assert activity.data["actor"] == other_user.ap_id - assert activity.data["cc"] == [user.ap_id] - end - - test "it correctly processes messages with non-array to field" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"] - end - - test "it correctly processes messages with non-array cc field" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] - end - - test "it correctly processes messages with weirdness in address fields" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => [nil, user.follower_address], - "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]], - "type" => "Create", - "object" => %{ - "content" => "…", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"] - assert [user.follower_address] == activity.data["to"] - end - - test "it accepts Move activities" do - old_user = insert(:user) - new_user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Move", - "actor" => old_user.ap_id, - "object" => old_user.ap_id, - "target" => new_user.ap_id - } - - assert :error = Transmogrifier.handle_incoming(message) - - {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]}) - - assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message) - assert activity.actor == old_user.ap_id - assert activity.data["actor"] == old_user.ap_id - assert activity.data["object"] == old_user.ap_id - assert activity.data["target"] == new_user.ap_id - assert activity.data["type"] == "Move" - end - end - - describe "`handle_incoming/2`, Mastodon format `replies` handling" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 5) - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - data = - "test/fixtures/mastodon-post-activity.json" - |> File.read!() - |> Poison.decode!() - - items = get_in(data, ["object", "replies", "first", "items"]) - assert length(items) > 0 - - %{data: data, items: items} - end - - test "schedules background fetching of `replies` items if max thread depth limit allows", %{ - data: data, - items: items - } do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10) - - {:ok, _activity} = Transmogrifier.handle_incoming(data) - - for id <- items do - job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} - assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) - end - end - - test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", - %{data: data} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - {:ok, _activity} = Transmogrifier.handle_incoming(data) - - assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] - end - end - - describe "`handle_incoming/2`, Pleroma format `replies` handling" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 5) - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "post1"}) - - {:ok, reply1} = - CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id}) - - {:ok, reply2} = - CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id}) - - replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end) - - {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data) - - Repo.delete(activity.object) - Repo.delete(activity) - - %{federation_output: federation_output, replies_uris: replies_uris} - end - - test "schedules background fetching of `replies` items if max thread depth limit allows", %{ - federation_output: federation_output, - replies_uris: replies_uris - } do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 1) - - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) - - for id <- replies_uris do - job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1} - assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args) - end - end - - test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows", - %{federation_output: federation_output} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - {:ok, _activity} = Transmogrifier.handle_incoming(federation_output) - - assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == [] - end - end - - describe "prepare outgoing" do - test "it inlines private announced objects" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) - - {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) - - {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) - - assert modified["object"]["content"] == "hey" - assert modified["object"]["actor"] == modified["object"]["attributedTo"] - end - - test "it turns mentions into tags" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"}) - - with_mock Pleroma.Notification, - get_notified_from_activity: fn _, _ -> [] end do - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - object = modified["object"] - - expected_mention = %{ - "href" => other_user.ap_id, - "name" => "@#{other_user.nickname}", - "type" => "Mention" - } - - expected_tag = %{ - "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", - "type" => "Hashtag", - "name" => "#2hu" - } - - refute called(Pleroma.Notification.get_notified_from_activity(:_, :_)) - assert Enum.member?(object["tag"], expected_tag) - assert Enum.member?(object["tag"], expected_mention) - end - end - - test "it adds the sensitive property" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["sensitive"] - end - - test "it adds the json-ld context and the conversation property" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["@context"] == - Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"] - - assert modified["object"]["conversation"] == modified["context"] - end - - test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["actor"] == modified["object"]["attributedTo"] - end - - test "it strips internal hashtag data" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"}) - - expected_tag = %{ - "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", - "type" => "Hashtag", - "name" => "#2hu" - } - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["tag"] == [expected_tag] - end - - test "it strips internal fields" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#2hu :firefox:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert length(modified["object"]["tag"]) == 2 - - assert is_nil(modified["object"]["emoji"]) - assert is_nil(modified["object"]["like_count"]) - assert is_nil(modified["object"]["announcements"]) - assert is_nil(modified["object"]["announcement_count"]) - assert is_nil(modified["object"]["context_id"]) - end - - test "it strips internal fields of article" do - activity = insert(:article_activity) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert length(modified["object"]["tag"]) == 2 - - assert is_nil(modified["object"]["emoji"]) - assert is_nil(modified["object"]["like_count"]) - assert is_nil(modified["object"]["announcements"]) - assert is_nil(modified["object"]["announcement_count"]) - assert is_nil(modified["object"]["context_id"]) - assert is_nil(modified["object"]["likes"]) - end - - test "the directMessage flag is present" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["directMessage"] == false - - {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"}) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["directMessage"] == false - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "@#{other_user.nickname} :moominmamma:", - visibility: "direct" - }) - - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - 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 - - test "it can handle Listen activities" do - listen_activity = insert(:listen) - - {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) - - assert modified["type"] == "Listen" - - user = insert(:user) - - {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"}) - - {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data) - end - end - - describe "user upgrade" do - test "it upgrades a user to activitypub" do - user = - insert(:user, %{ - nickname: "rye@niu.moe", - local: false, - ap_id: "https://niu.moe/users/rye", - follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"}) - }) - - user_two = insert(:user) - Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept) - - {:ok, activity} = CommonAPI.post(user, %{status: "test"}) - {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"}) - assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients - - user = User.get_cached_by_id(user.id) - assert user.note_count == 1 - - {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") - ObanHelpers.perform_all() - - assert user.ap_enabled - assert user.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.note_count == 1 - - activity = Activity.get_by_id(activity.id) - assert user.follower_address in activity.recipients - - assert %{ - "url" => [ - %{ - "href" => - "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" - } - ] - } = user.avatar - - assert %{ - "url" => [ - %{ - "href" => - "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" - } - ] - } = user.banner - - refute "..." in activity.recipients - - unrelated_activity = Activity.get_by_id(unrelated_activity.id) - refute user.follower_address in unrelated_activity.recipients - - user_two = User.get_cached_by_id(user_two.id) - assert User.following?(user_two, user) - refute "..." in User.following(user_two) - end - end - - describe "actor rewriting" do - test "it fixes the actor URL property to be a proper URI" do - data = %{ - "url" => %{"href" => "http://example.com"} - } - - rewritten = Transmogrifier.maybe_fix_user_object(data) - assert rewritten["url"] == "http://example.com" - end - end - - describe "actor origin containment" do - test "it rejects activities which reference objects with bogus origins" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - - test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity2.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - - test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do - data = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "id" => "http://mastodon.example.org/users/admin/activities/1234", - "actor" => "http://mastodon.example.org/users/admin", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "object" => "https://info.pleroma.site/activity3.json", - "type" => "Announce" - } - - assert capture_log(fn -> - {:error, _} = Transmogrifier.handle_incoming(data) - end) =~ "Object containment failed" - end - end - - describe "reserialization" do - test "successfully reserializes a message with inReplyTo == nil" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Note", - "content" => "Hi", - "inReplyTo" => nil, - "attributedTo" => user.ap_id - }, - "actor" => user.ap_id - } - - {:ok, activity} = Transmogrifier.handle_incoming(message) - - {:ok, _} = Transmogrifier.prepare_outgoing(activity.data) - end - - test "successfully reserializes a message with AS2 objects in IR" do - user = insert(:user) - - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Create", - "object" => %{ - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "cc" => [], - "type" => "Note", - "content" => "Hi", - "inReplyTo" => nil, - "attributedTo" => user.ap_id, - "tag" => [ - %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"}, - %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"} - ] - }, - "actor" => user.ap_id - } - - {:ok, activity} = Transmogrifier.handle_incoming(message) - - {: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 - - describe "fix_summary/1" do - test "returns fixed object" do - assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""} - assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"} - assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""} - end - end - - describe "fix_in_reply_to/2" do - setup do: clear_config([:instance, :federation_incoming_replies_max_depth]) - - setup do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - [data: data] - end - - test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do - assert Transmogrifier.fix_in_reply_to(data) == data - end - - test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) - - object_with_reply = - Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873") - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873" - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = - Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"}) - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"} - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = - Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"]) - - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"] - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - object_with_reply = Map.put(data["object"], "inReplyTo", []) - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - assert modified_object["inReplyTo"] == [] - assert modified_object["inReplyToAtomUri"] == "" - end - - @tag capture_log: true - test "returns modified object when allowed incoming reply", %{data: data} do - object_with_reply = - Map.put( - data["object"], - "inReplyTo", - "https://shitposter.club/notice/2827873" - ) - - Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5) - modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) - - assert modified_object["inReplyTo"] == - "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" - - assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - assert modified_object["context"] == - "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" - end - end - - describe "fix_url/1" do - test "fixes data for object when url is map" do - object = %{ - "url" => %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - } - } - - assert Transmogrifier.fix_url(object) == %{ - "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - } - end - - test "fixes data for video object" do - object = %{ - "type" => "Video", - "url" => [ - %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" - }, - %{ - "type" => "Link", - "mimeType" => "video/mp4", - "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d1630e3" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d16377-42" - } - ] - } - - assert Transmogrifier.fix_url(object) == %{ - "attachment" => [ - %{ - "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mimeType" => "video/mp4", - "type" => "Link" - } - ], - "type" => "Video", - "url" => "https://peertube.-2d4c2d1630e3" - } - end - - test "fixes url for not Video object" do - object = %{ - "type" => "Text", - "url" => [ - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d1630e3" - }, - %{ - "type" => "Link", - "mimeType" => "text/html", - "href" => "https://peertube.-2d4c2d16377-42" - } - ] - } - - assert Transmogrifier.fix_url(object) == %{ - "type" => "Text", - "url" => "https://peertube.-2d4c2d1630e3" - } - - assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{ - "type" => "Text", - "url" => "" - } - end - - test "retunrs not modified object" do - assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} - end - end - - describe "get_obj_helper/2" do - test "returns nil when cannot normalize object" do - assert capture_log(fn -> - refute Transmogrifier.get_obj_helper("test-obj-id") - end) =~ "Unsupported URI scheme" - end - - @tag capture_log: true - test "returns {:ok, %Object{}} for success case" do - assert {:ok, %Object{}} = - Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873") - end - end - - describe "fix_attachments/1" do - test "returns not modified object" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.fix_attachments(data) == data - end - - test "returns modified object when attachment is map" do - assert Transmogrifier.fix_attachments(%{ - "attachment" => %{ - "mediaType" => "video/mp4", - "url" => "https://peertube.moe/stat-480.mp4" - } - }) == %{ - "attachment" => [ - %{ - "mediaType" => "video/mp4", - "url" => [ - %{"href" => "https://peertube.moe/stat-480.mp4", "mediaType" => "video/mp4"} - ] - } - ] - } - end - - test "returns modified object when attachment is list" do - assert Transmogrifier.fix_attachments(%{ - "attachment" => [ - %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"}, - %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"} - ] - }) == %{ - "attachment" => [ - %{ - "mediaType" => "video/mp4", - "url" => [ - %{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"} - ] - }, - %{ - "mediaType" => "video/mp4", - "url" => [ - %{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"} - ] - } - ] - } - end - end - - describe "fix_emoji/1" do - test "returns not modified object when object not contains tags" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.fix_emoji(data) == data - end - - test "returns object with emoji when object contains list tags" do - assert Transmogrifier.fix_emoji(%{ - "tag" => [ - %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}, - %{"type" => "Hashtag"} - ] - }) == %{ - "emoji" => %{"bib" => "/test"}, - "tag" => [ - %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}, - %{"type" => "Hashtag"} - ] - } - end - - test "returns object with emoji when object contains map tag" do - assert Transmogrifier.fix_emoji(%{ - "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}} - }) == %{ - "emoji" => %{"bib" => "/test"}, - "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"} - } - end - end - - describe "set_replies/1" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 2) - - test "returns unmodified object if activity doesn't have self-replies" do - data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) - assert Transmogrifier.set_replies(data) == data - end - - test "sets `replies` collection with a limited number of self-replies" do - [user, another_user] = insert_list(2, :user) - - {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"}) - - {:ok, %{id: id2} = self_reply1} = - CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1}) - - {:ok, self_reply2} = - CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1}) - - # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2 - {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1}) - - {:ok, _} = - CommonAPI.post(user, %{ - status: "self-reply to self-reply", - in_reply_to_status_id: id2 - }) - - {:ok, _} = - CommonAPI.post(another_user, %{ - status: "another user's reply", - in_reply_to_status_id: id1 - }) - - object = Object.normalize(activity) - replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end) - - assert %{"type" => "Collection", "items" => ^replies_uris} = - Transmogrifier.set_replies(object.data)["replies"] - end - end - - test "take_emoji_tags/1" do - user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}}) - - assert Transmogrifier.take_emoji_tags(user) == [ - %{ - "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"}, - "id" => "https://example.org/firefox.png", - "name" => ":firefox:", - "type" => "Emoji", - "updated" => "1970-01-01T00:00:00Z" - } - ] - end -end diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs deleted file mode 100644 index d50213545..000000000 --- a/test/web/activity_pub/utils_test.exs +++ /dev/null @@ -1,548 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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.Utils - alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - require Pleroma.Constants - - describe "fetch the latest Follow" do - test "fetches the latest Follow activity" do - %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity) - follower = User.get_cached_by_ap_id(activity.data["actor"]) - followed = User.get_cached_by_ap_id(activity.data["object"]) - - assert activity == Utils.fetch_latest_follow(follower, followed) - end - end - - describe "determine_explicit_mentions()" do - test "works with an object that has mentions" do - object = %{ - "tag" => [ - %{ - "type" => "Mention", - "href" => "https://example.com/~alyssa", - "name" => "Alyssa P. Hacker" - } - ] - } - - assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] - end - - test "works with an object that does not have mentions" do - object = %{ - "tag" => [ - %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"} - ] - } - - assert Utils.determine_explicit_mentions(object) == [] - end - - test "works with an object that has mentions and other tags" do - object = %{ - "tag" => [ - %{ - "type" => "Mention", - "href" => "https://example.com/~alyssa", - "name" => "Alyssa P. Hacker" - }, - %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"} - ] - } - - assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] - end - - test "works with an object that has no tags" do - object = %{} - - assert Utils.determine_explicit_mentions(object) == [] - end - - test "works with an object that has only IR tags" do - object = %{"tag" => ["2hu"]} - - assert Utils.determine_explicit_mentions(object) == [] - end - - test "works with an object has tags as map" do - object = %{ - "tag" => %{ - "type" => "Mention", - "href" => "https://example.com/~alyssa", - "name" => "Alyssa P. Hacker" - } - } - - assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] - end - end - - describe "make_like_data" do - setup do - user = insert(:user) - other_user = insert(:user) - third_user = insert(:user) - [user: user, other_user: other_user, third_user: third_user] - end - - test "addresses actor's follower address if the activity is public", %{ - user: user, - other_user: other_user, - third_user: third_user - } do - expected_to = Enum.sort([user.ap_id, other_user.follower_address]) - expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id]) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: - "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?" - }) - - %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil) - assert Enum.sort(to) == expected_to - assert Enum.sort(cc) == expected_cc - end - - test "does not adress actor's follower address if the activity is not public", %{ - user: user, - other_user: other_user, - third_user: third_user - } do - expected_to = Enum.sort([user.ap_id]) - expected_cc = [third_user.ap_id] - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!", - visibility: "private" - }) - - %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil) - assert Enum.sort(to) == expected_to - assert Enum.sort(cc) == expected_cc - end - end - - test "make_json_ld_header/0" do - assert Utils.make_json_ld_header() == %{ - "@context" => [ - "https://www.w3.org/ns/activitystreams", - "http://localhost:4001/schemas/litepub-0.1.jsonld", - %{ - "@language" => "und" - } - ] - } - 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]) - {:ok, _activity} = CommonAPI.favorite(user, activity.id) - [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, locked: true) - follower = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.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 refresh_record(follow_activity).data["state"] == "accept" - assert refresh_record(follow_activity_two).data["state"] == "accept" - end - end - - describe "update_follow_state/2" do - test "updates the state of the given follow activity" do - user = insert(:user, locked: true) - follower = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.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 refresh_record(follow_activity).data["state"] == "pending" - assert refresh_record(follow_activity_two).data["state"] == "reject" - end - end - - describe "update_element_in_object/3" do - test "updates likes" do - user = insert(:user) - activity = insert(:note_activity) - object = Object.normalize(activity) - - assert {:ok, updated_object} = - Utils.update_element_in_object( - "like", - [user.ap_id], - object - ) - - assert updated_object.data["likes"] == [user.ap_id] - assert updated_object.data["like_count"] == 1 - end - end - - describe "add_like_to_object/2" do - test "add actor to likes" do - user = insert(:user) - user2 = insert(:user) - object = insert(:note) - - assert {:ok, updated_object} = - Utils.add_like_to_object( - %Activity{data: %{"actor" => user.ap_id}}, - object - ) - - assert updated_object.data["likes"] == [user.ap_id] - assert updated_object.data["like_count"] == 1 - - assert {:ok, updated_object2} = - Utils.add_like_to_object( - %Activity{data: %{"actor" => user2.ap_id}}, - updated_object - ) - - assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id] - assert updated_object2.data["like_count"] == 2 - end - end - - describe "remove_like_from_object/2" do - test "removes ap_id from likes" do - user = insert(:user) - user2 = insert(:user) - object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2}) - - assert {:ok, updated_object} = - Utils.remove_like_from_object( - %Activity{data: %{"actor" => user.ap_id}}, - object - ) - - assert updated_object.data["likes"] == [user2.ap_id] - assert updated_object.data["like_count"] == 1 - end - end - - describe "get_existing_like/2" do - test "fetches existing like" do - note_activity = insert(:note_activity) - assert object = Object.normalize(note_activity) - - user = insert(:user) - refute Utils.get_existing_like(user.ap_id, object) - {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id) - - assert ^like_activity = Utils.get_existing_like(user.ap_id, object) - end - end - - describe "get_get_existing_announce/2" do - test "returns nil if announce not found" do - actor = insert(:user) - refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}}) - end - - test "fetches existing announce" do - note_activity = insert(:note_activity) - assert object = Object.normalize(note_activity) - actor = insert(:user) - - {:ok, announce} = CommonAPI.repeat(note_activity.id, actor) - assert Utils.get_existing_announce(actor.ap_id, object) == announce - end - end - - describe "fetch_latest_block/2" do - test "fetches last block activities" do - user1 = insert(:user) - user2 = insert(:user) - - assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) - assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) - assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2) - - assert Utils.fetch_latest_block(user1, user2) == activity - end - end - - describe "recipient_in_message/3" do - test "returns true when recipient in `to`" do - recipient = insert(:user) - actor = insert(:user) - assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id}) - - assert Utils.recipient_in_message( - recipient, - actor, - %{"to" => [recipient.ap_id], "cc" => ""} - ) - end - - test "returns true when recipient in `cc`" do - recipient = insert(:user) - actor = insert(:user) - assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id}) - - assert Utils.recipient_in_message( - recipient, - actor, - %{"cc" => [recipient.ap_id], "to" => ""} - ) - end - - test "returns true when recipient in `bto`" do - recipient = insert(:user) - actor = insert(:user) - assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id}) - - assert Utils.recipient_in_message( - recipient, - actor, - %{"bcc" => "", "bto" => [recipient.ap_id]} - ) - end - - test "returns true when recipient in `bcc`" do - recipient = insert(:user) - actor = insert(:user) - assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id}) - - assert Utils.recipient_in_message( - recipient, - actor, - %{"bto" => "", "bcc" => [recipient.ap_id]} - ) - end - - test "returns true when message without addresses fields" do - recipient = insert(:user) - actor = insert(:user) - assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id}) - - assert Utils.recipient_in_message( - recipient, - actor, - %{"btod" => "", "bccc" => [recipient.ap_id]} - ) - end - - test "returns false" do - recipient = insert(:user) - actor = insert(:user) - refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"}) - end - end - - describe "lazy_put_activity_defaults/2" do - test "returns map with id and published data" do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]}) - assert res["context"] == object.data["id"] - assert res["context_id"] == object.id - assert res["id"] - assert res["published"] - end - - test "returns map with fake id and published data" do - assert %{ - "context" => "pleroma:fakecontext", - "context_id" => -1, - "id" => "pleroma:fakeid", - "published" => _ - } = Utils.lazy_put_activity_defaults(%{}, true) - end - - test "returns activity data with object" do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - - res = - Utils.lazy_put_activity_defaults(%{ - "context" => object.data["id"], - "object" => %{} - }) - - assert res["context"] == object.data["id"] - assert res["context_id"] == object.id - assert res["id"] - assert res["published"] - assert res["object"]["id"] - assert res["object"]["published"] - assert res["object"]["context"] == object.data["id"] - assert res["object"]["context_id"] == object.id - end - end - - describe "make_flag_data" do - test "returns empty map when params is invalid" do - assert Utils.make_flag_data(%{}, %{}) == %{} - end - - test "returns map with Flag object" do - reporter = insert(:user) - target_account = insert(:user) - {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"}) - context = Utils.generate_context_id() - content = "foobar" - - target_ap_id = target_account.ap_id - activity_ap_id = activity.data["id"] - - res = - Utils.make_flag_data( - %{ - actor: reporter, - context: context, - account: target_account, - statuses: [%{"id" => activity.data["id"]}], - content: content - }, - %{} - ) - - note_obj = %{ - "type" => "Note", - "id" => activity_ap_id, - "content" => content, - "published" => activity.object.data["published"], - "actor" => - AccountView.render("show.json", %{user: target_account, skip_visibility_check: true}) - } - - assert %{ - "type" => "Flag", - "content" => ^content, - "context" => ^context, - "object" => [^target_ap_id, ^note_obj], - "state" => "open" - } = res - end - end - - describe "add_announce_to_object/2" do - test "adds actor to announcement" do - user = insert(:user) - object = insert(:note) - - activity = - insert(:note_activity, - data: %{ - "actor" => user.ap_id, - "cc" => [Pleroma.Constants.as_public()] - } - ) - - assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object) - assert updated_object.data["announcements"] == [user.ap_id] - assert updated_object.data["announcement_count"] == 1 - end - end - - describe "remove_announce_from_object/2" do - test "removes actor from announcements" do - user = insert(:user) - user2 = insert(:user) - - object = - insert(:note, - data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2} - ) - - activity = insert(:note_activity, data: %{"actor" => user.ap_id}) - - assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object) - assert updated_object.data["announcements"] == [user2.ap_id] - assert updated_object.data["announcement_count"] == 1 - end - end - - describe "get_cached_emoji_reactions/1" do - test "returns the data or an emtpy list" do - object = insert(:note) - assert Utils.get_cached_emoji_reactions(object) == [] - - object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]}) - assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]] - - object = insert(:note, data: %{"reactions" => %{}}) - assert Utils.get_cached_emoji_reactions(object) == [] - 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 deleted file mode 100644 index f0389845d..000000000 --- a/test/web/activity_pub/views/object_view_test.exs +++ /dev/null @@ -1,84 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 - - test "renders a note object" do - note = insert(:note) - - result = ObjectView.render("object.json", %{object: note}) - - assert result["id"] == note.data["id"] - assert result["to"] == note.data["to"] - assert result["content"] == note.data["content"] - assert result["type"] == "Note" - assert result["@context"] - end - - 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"] == object.data["content"] - assert result["type"] == "Create" - assert result["@context"] - end - - describe "note activity's `replies` collection rendering" do - setup do: clear_config([:activitypub, :note_replies_output_limit], 5) - - test "renders `replies` collection for a note activity" do - user = insert(:user) - activity = insert(:note_activity, user: user) - - {:ok, self_reply1} = - CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: activity.id}) - - replies_uris = [self_reply1.object.data["id"]] - result = ObjectView.render("object.json", %{object: refresh_record(activity)}) - - assert %{"type" => "Collection", "items" => ^replies_uris} = - get_in(result, ["object", "replies"]) - end - end - - test "renders a like activity" do - note = insert(:note_activity) - object = Object.normalize(note) - user = insert(:user) - - {:ok, like_activity} = CommonAPI.favorite(user, note.id) - - result = ObjectView.render("object.json", %{object: like_activity}) - - assert result["id"] == like_activity.data["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) - - result = ObjectView.render("object.json", %{object: announce_activity}) - - assert result["id"] == announce_activity.data["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 deleted file mode 100644 index 98c7c9d09..000000000 --- a/test/web/activity_pub/views/user_view_test.exs +++ /dev/null @@ -1,180 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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) - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - - assert result["id"] == user.ap_id - assert result["preferredUsername"] == user.nickname - - assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY") - end - - test "Renders profile fields" do - fields = [ - %{"name" => "foo", "value" => "bar"} - ] - - {:ok, user} = - insert(:user) - |> User.update_changeset(%{fields: fields}) - |> User.update_and_set_cache() - - assert %{ - "attachment" => [%{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}] - } = UserView.render("user.json", %{user: user}) - end - - test "Renders with emoji tags" do - user = insert(:user, emoji: %{"bib" => "/test"}) - - assert %{ - "tag" => [ - %{ - "icon" => %{"type" => "Image", "url" => "/test"}, - "id" => "/test", - "name" => ":bib:", - "type" => "Emoji", - "updated" => "1970-01-01T00:00:00Z" - } - ] - } = UserView.render("user.json", %{user: user}) - end - - test "Does not add an avatar image if the user hasn't set one" do - user = insert(:user) - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - refute result["icon"] - refute result["image"] - - user = - insert(:user, - avatar: %{"url" => [%{"href" => "https://someurl"}]}, - banner: %{"url" => [%{"href" => "https://somebanner"}]} - ) - - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - assert result["icon"]["url"] == "https://someurl" - assert result["image"]["url"] == "https://somebanner" - end - - test "renders an invisible user with the invisible property set to true" do - user = insert(:user, invisible: true) - - assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) - end - - describe "endpoints" do - test "local users have a usable endpoints structure" do - user = insert(:user) - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - - assert result["id"] == user.ap_id - - %{ - "sharedInbox" => _, - "oauthAuthorizationEndpoint" => _, - "oauthRegistrationEndpoint" => _, - "oauthTokenEndpoint" => _ - } = result["endpoints"] - end - - test "remote users have an empty endpoints structure" do - user = insert(:user, local: false) - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - - assert result["id"] == user.ap_id - assert result["endpoints"] == %{} - end - - test "instance users do not expose oAuth endpoints" do - user = insert(:user, nickname: nil, local: true) - {:ok, user} = User.ensure_keys_present(user) - - result = UserView.render("user.json", %{user: user}) - - refute result["endpoints"]["oauthAuthorizationEndpoint"] - refute result["endpoints"]["oauthRegistrationEndpoint"] - 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}) - user = Map.merge(user, %{hide_followers_count: true, hide_followers: true}) - refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems") - end - - test "sets correct totalItems when followers are hidden but the follower counter is not" 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}) - user = Map.merge(user, %{hide_followers_count: false, hide_followers: true}) - assert %{"totalItems" => 1} = 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}) - user = Map.merge(user, %{hide_follows_count: true, hide_follows: true}) - assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user}) - end - - test "sets correct totalItems when follows are hidden but the follow counter is not" 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}) - user = Map.merge(user, %{hide_follows_count: false, hide_follows: true}) - assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) - end - end - - describe "acceptsChatMessages" do - test "it returns this value if it is set" do - true_user = insert(:user, accepts_chat_messages: true) - false_user = insert(:user, accepts_chat_messages: false) - nil_user = insert(:user, accepts_chat_messages: nil) - - assert %{"capabilities" => %{"acceptsChatMessages" => true}} = - UserView.render("user.json", user: true_user) - - assert %{"capabilities" => %{"acceptsChatMessages" => false}} = - UserView.render("user.json", user: false_user) - - refute Map.has_key?( - UserView.render("user.json", user: nil_user)["capabilities"], - "acceptsChatMessages" - ) - end - end -end diff --git a/test/web/activity_pub/visibilty_test.exs b/test/web/activity_pub/visibilty_test.exs deleted file mode 100644 index 8e9354c65..000000000 --- a/test/web/activity_pub/visibilty_test.exs +++ /dev/null @@ -1,230 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 - - setup do - user = insert(:user) - mentioned = insert(:user) - 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"}) - - {:ok, private} = - CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "private"}) - - {:ok, direct} = - CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "direct"}) - - {: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, - direct: direct, - unlisted: unlisted, - user: user, - mentioned: mentioned, - following: following, - unrelated: unrelated, - list: list - } - end - - 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, - 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, - 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?", %{ - public: public, - private: private, - direct: direct, - unlisted: unlisted, - user: user, - mentioned: mentioned, - following: following, - unrelated: unrelated, - list: list - } do - # All visible to author - - assert Visibility.visible_for_user?(public, user) - 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 - - assert Visibility.visible_for_user?(public, mentioned) - 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 - - assert Visibility.visible_for_user?(public, following) - 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 - - assert Visibility.visible_for_user?(public, unrelated) - 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", - %{ - direct: direct, - user: user - } do - Repo.delete(user) - Cachex.clear(:user_cache) - refute Visibility.is_private?(direct) - end - - test "get_visibility", %{ - public: public, - private: private, - direct: direct, - 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) - Pleroma.User.follow(user, author) - - 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/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs deleted file mode 100644 index 6082441ee..000000000 --- a/test/web/admin_api/controllers/admin_api_controller_test.exs +++ /dev/null @@ -1,1786 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do - use Pleroma.Web.ConnCase - use Oban.Testing, repo: Pleroma.Repo - - import ExUnit.CaptureLog - import Mock - import Pleroma.Factory - import Swoosh.TestAssertions - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.HTML - alias Pleroma.MFA - alias Pleroma.ModerationLog - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web - alias Pleroma.Web.ActivityPub.Relay - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MediaProxy - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - - :ok - end - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - test "with valid `admin_token` query parameter, skips OAuth scopes check" do - clear_config([:admin_token], "password123") - - user = insert(:user) - - conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123") - - assert json_response(conn, 200) - end - - describe "with [:auth, :enforce_oauth_admin_scope_usage]," do - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true) - - test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", - %{admin: admin} do - user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" - - good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) - good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) - - bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) - bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) - bad_token3 = nil - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, 200) - end - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, nil) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - - for bad_token <- [bad_token1, bad_token2, bad_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, bad_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - end - end - - describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) - - test "GET /api/pleroma/admin/users/:nickname requires " <> - "read:accounts or admin:read:accounts or broader scope", - %{admin: admin} do - user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" - - good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) - good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) - good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) - good_token5 = insert(:oauth_token, user: admin, scopes: ["read"]) - - good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5] - - bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"]) - bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) - bad_token3 = nil - - for good_token <- good_tokens do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, 200) - end - - for good_token <- good_tokens do - conn = - build_conn() - |> assign(:user, nil) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - - for bad_token <- [bad_token1, bad_token2, bad_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, bad_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - end - end - - describe "DELETE /api/pleroma/admin/users" do - test "single user", %{admin: admin, conn: conn} do - user = insert(:user) - clear_config([:instance, :federating], true) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}") - - ObanHelpers.perform_all() - - assert User.get_by_nickname(user.nickname).deactivated - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted users: @#{user.nickname}" - - assert json_response(conn, 200) == [user.nickname] - - assert called(Pleroma.Web.Federator.publish(:_)) - end - end - - test "multiple users", %{admin: admin, conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}" - - response = json_response(conn, 200) - assert response -- [user_one.nickname, user_two.nickname] == [] - end - end - - describe "/api/pleroma/admin/users" do - test "Create", %{conn: conn} do - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "lain", - "email" => "lain@example.org", - "password" => "test" - }, - %{ - "nickname" => "lain2", - "email" => "lain2@example.org", - "password" => "test" - } - ] - }) - - response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type")) - assert response == ["success", "success"] - - log_entry = Repo.one(ModerationLog) - - assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == [] - end - - test "Cannot create user with existing email", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "lain", - "email" => user.email, - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => user.email, - "nickname" => "lain" - }, - "error" => "email has already been taken", - "type" => "error" - } - ] - end - - test "Cannot create user with existing nickname", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => user.nickname, - "email" => "someuser@plerama.social", - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => "someuser@plerama.social", - "nickname" => user.nickname - }, - "error" => "nickname has already been taken", - "type" => "error" - } - ] - end - - test "Multiple user creation works in transaction", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users", %{ - "users" => [ - %{ - "nickname" => "newuser", - "email" => "newuser@pleroma.social", - "password" => "test" - }, - %{ - "nickname" => "lain", - "email" => user.email, - "password" => "test" - } - ] - }) - - assert json_response(conn, 409) == [ - %{ - "code" => 409, - "data" => %{ - "email" => user.email, - "nickname" => "lain" - }, - "error" => "email has already been taken", - "type" => "error" - }, - %{ - "code" => 409, - "data" => %{ - "email" => "newuser@pleroma.social", - "nickname" => "newuser" - }, - "error" => "", - "type" => "error" - } - ] - - assert User.get_by_nickname("newuser") === nil - end - end - - describe "/api/pleroma/admin/users/:nickname" do - test "Show", %{conn: conn} do - user = insert(:user) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") - - expected = %{ - "deactivated" => false, - "id" => to_string(user.id), - "local" => true, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - - assert expected == json_response(conn, 200) - end - - test "when the user doesn't exist", %{conn: conn} do - user = build(:user) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") - - assert %{"error" => "Not found"} == json_response(conn, 404) - end - end - - describe "/api/pleroma/admin/users/follow" do - test "allows to force-follow another user", %{admin: admin, conn: conn} do - user = insert(:user) - follower = insert(:user) - - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/follow", %{ - "follower" => follower.nickname, - "followed" => user.nickname - }) - - user = User.get_cached_by_id(user.id) - follower = User.get_cached_by_id(follower.id) - - assert User.following?(follower, user) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}" - end - end - - describe "/api/pleroma/admin/users/unfollow" do - test "allows to force-unfollow another user", %{admin: admin, conn: conn} do - user = insert(:user) - follower = insert(:user) - - User.follow(follower, user) - - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/unfollow", %{ - "follower" => follower.nickname, - "followed" => user.nickname - }) - - user = User.get_cached_by_id(user.id) - follower = User.get_cached_by_id(follower.id) - - refute User.following?(follower, user) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}" - end - end - - describe "PUT /api/pleroma/admin/users/tag" do - setup %{conn: conn} do - user1 = insert(:user, %{tags: ["x"]}) - user2 = insert(:user, %{tags: ["y"]}) - user3 = insert(:user, %{tags: ["unchanged"]}) - - conn = - conn - |> put_req_header("accept", "application/json") - |> put( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=foo&tags[]=bar" - ) - - %{conn: conn, user1: user1, user2: user2, user3: user3} - end - - test "it appends specified tags to users with specified nicknames", %{ - conn: conn, - admin: admin, - user1: user1, - user2: user2 - } do - assert json_response(conn, :no_content) - assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"] - assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"] - - log_entry = Repo.one(ModerationLog) - - users = - [user1.nickname, user2.nickname] - |> Enum.map(&"@#{&1}") - |> Enum.join(", ") - - tags = ["foo", "bar"] |> Enum.join(", ") - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} added tags: #{tags} to users: #{users}" - end - - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do - assert json_response(conn, :no_content) - assert User.get_cached_by_id(user3.id).tags == ["unchanged"] - end - end - - describe "DELETE /api/pleroma/admin/users/tag" do - setup %{conn: conn} do - user1 = insert(:user, %{tags: ["x"]}) - user2 = insert(:user, %{tags: ["y", "z"]}) - user3 = insert(:user, %{tags: ["unchanged"]}) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=x&tags[]=z" - ) - - %{conn: conn, user1: user1, user2: user2, user3: user3} - end - - test "it removes specified tags from users with specified nicknames", %{ - conn: conn, - admin: admin, - user1: user1, - user2: user2 - } do - assert json_response(conn, :no_content) - assert User.get_cached_by_id(user1.id).tags == [] - assert User.get_cached_by_id(user2.id).tags == ["y"] - - log_entry = Repo.one(ModerationLog) - - users = - [user1.nickname, user2.nickname] - |> Enum.map(&"@#{&1}") - |> Enum.join(", ") - - tags = ["x", "z"] |> Enum.join(", ") - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} removed tags: #{tags} from users: #{users}" - end - - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do - assert json_response(conn, :no_content) - assert User.get_cached_by_id(user3.id).tags == ["unchanged"] - end - end - - describe "/api/pleroma/admin/users/:nickname/permission_group" do - test "GET is giving user_info", %{admin: admin, conn: conn} do - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/") - - assert json_response(conn, 200) == %{ - "is_admin" => true, - "is_moderator" => false - } - end - - test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") - - assert json_response(conn, 200) == %{ - "is_admin" => true - } - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{user.nickname} admin" - end - - test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> post("/api/pleroma/admin/users/permission_group/admin", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - assert json_response(conn, 200) == %{"is_admin" => true} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin" - end - - test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do - user = insert(:user, is_admin: true) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin") - - assert json_response(conn, 200) == %{"is_admin" => false} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} revoked admin role from @#{user.nickname}" - end - - test "/:right DELETE, can remove from a permission group (multiple)", %{ - admin: admin, - conn: conn - } do - user_one = insert(:user, is_admin: true) - user_two = insert(:user, is_admin: true) - - conn = - conn - |> put_req_header("accept", "application/json") - |> delete("/api/pleroma/admin/users/permission_group/admin", %{ - nicknames: [user_one.nickname, user_two.nickname] - }) - - assert json_response(conn, 200) == %{"is_admin" => false} - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{ - user_two.nickname - }" - end - end - - test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") - - resp = json_response(conn, 200) - - assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) - end - - describe "GET /api/pleroma/admin/users" do - test "renders users array for the first page", %{conn: conn, admin: admin} do - user = insert(:user, local: false, tags: ["foo", "bar"]) - conn = get(conn, "/api/pleroma/admin/users?page=1") - - users = - [ - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "url" => admin.ap_id - }, - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => false, - "tags" => ["foo", "bar"], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => users - } - end - - test "pagination works correctly with service users", %{conn: conn} do - service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido") - - insert_list(25, :user) - - assert %{"count" => 26, "page_size" => 10, "users" => users1} = - conn - |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users1) == 10 - assert service1 not in users1 - - assert %{"count" => 26, "page_size" => 10, "users" => users2} = - conn - |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users2) == 10 - assert service1 not in users2 - - assert %{"count" => 26, "page_size" => 10, "users" => users3} = - conn - |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"}) - |> json_response(200) - - assert Enum.count(users3) == 6 - assert service1 not in users3 - end - - test "renders empty array for the second page", %{conn: conn} do - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?page=2") - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => [] - } - end - - test "regular search", %{conn: conn} do - user = insert(:user, nickname: "bob") - - conn = get(conn, "/api/pleroma/admin/users?query=bo") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "search by domain", %{conn: conn} do - user = insert(:user, nickname: "nickname@domain.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?query=domain.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "search by full nickname", %{conn: conn} do - user = insert(:user, nickname: "nickname@domain.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "search by display name", %{conn: conn} do - user = insert(:user, name: "Display name") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?name=display") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "search by email", %{conn: conn} do - user = insert(:user, email: "email@example.com") - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?email=email@example.com") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "regular search with page size", %{conn: conn} do - user = insert(:user, nickname: "aalice") - user2 = insert(:user, nickname: "alice") - - conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1") - - assert json_response(conn1, 200) == %{ - "count" => 2, - "page_size" => 1, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - - conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2") - - assert json_response(conn2, 200) == %{ - "count" => 2, - "page_size" => 1, - "users" => [ - %{ - "deactivated" => user2.deactivated, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname), - "confirmation_pending" => false, - "url" => user2.ap_id - } - ] - } - end - - test "only local users" do - admin = insert(:user, is_admin: true, nickname: "john") - token = insert(:oauth_admin_token, user: admin) - user = insert(:user, nickname: "bob") - - insert(:user, nickname: "bobb", local: false) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> get("/api/pleroma/admin/users?query=bo&filters=local") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "only local users with no query", %{conn: conn, admin: old_admin} do - admin = insert(:user, is_admin: true, nickname: "john") - user = insert(:user, nickname: "bob") - - insert(:user, nickname: "bobb", local: false) - - conn = get(conn, "/api/pleroma/admin/users?filters=local") - - users = - [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - }, - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "url" => admin.ap_id - }, - %{ - "deactivated" => false, - "id" => old_admin.id, - "local" => true, - "nickname" => old_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "tags" => [], - "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname), - "confirmation_pending" => false, - "url" => old_admin.ap_id - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 3, - "page_size" => 50, - "users" => users - } - end - - test "load only admins", %{conn: conn, admin: admin} do - second_admin = insert(:user, is_admin: true) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?filters=is_admin") - - users = - [ - %{ - "deactivated" => false, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => admin.local, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "url" => admin.ap_id - }, - %{ - "deactivated" => false, - "id" => second_admin.id, - "nickname" => second_admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => second_admin.local, - "tags" => [], - "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname), - "confirmation_pending" => false, - "url" => second_admin.ap_id - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => users - } - end - - test "load only moderators", %{conn: conn} do - moderator = insert(:user, is_moderator: true) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => false, - "id" => moderator.id, - "nickname" => moderator.nickname, - "roles" => %{"admin" => false, "moderator" => true}, - "local" => moderator.local, - "tags" => [], - "avatar" => User.avatar_url(moderator) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(moderator.name || moderator.nickname), - "confirmation_pending" => false, - "url" => moderator.ap_id - } - ] - } - end - - test "load users with tags list", %{conn: conn} do - user1 = insert(:user, tags: ["first"]) - user2 = insert(:user, tags: ["second"]) - insert(:user) - insert(:user) - - conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second") - - users = - [ - %{ - "deactivated" => false, - "id" => user1.id, - "nickname" => user1.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user1.local, - "tags" => ["first"], - "avatar" => User.avatar_url(user1) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user1.name || user1.nickname), - "confirmation_pending" => false, - "url" => user1.ap_id - }, - %{ - "deactivated" => false, - "id" => user2.id, - "nickname" => user2.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user2.local, - "tags" => ["second"], - "avatar" => User.avatar_url(user2) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user2.name || user2.nickname), - "confirmation_pending" => false, - "url" => user2.ap_id - } - ] - |> Enum.sort_by(& &1["nickname"]) - - assert json_response(conn, 200) == %{ - "count" => 2, - "page_size" => 50, - "users" => users - } - end - - test "it works with multiple filters" do - admin = insert(:user, nickname: "john", is_admin: true) - token = insert(:oauth_admin_token, user: admin) - user = insert(:user, nickname: "bob", local: false, deactivated: true) - - insert(:user, nickname: "ken", local: true, deactivated: true) - insert(:user, nickname: "bobb", local: false, deactivated: false) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> get("/api/pleroma/admin/users?filters=deactivated,external") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => user.local, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - ] - } - end - - test "it omits relay user", %{admin: admin, conn: conn} do - assert %User{} = Relay.get_actor() - - conn = get(conn, "/api/pleroma/admin/users") - - assert json_response(conn, 200) == %{ - "count" => 1, - "page_size" => 50, - "users" => [ - %{ - "deactivated" => admin.deactivated, - "id" => admin.id, - "nickname" => admin.nickname, - "roles" => %{"admin" => true, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(admin) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(admin.name || admin.nickname), - "confirmation_pending" => false, - "url" => admin.ap_id - } - ] - } - end - end - - test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do - user_one = insert(:user, deactivated: true) - user_two = insert(:user, deactivated: true) - - conn = - patch( - conn, - "/api/pleroma/admin/users/activate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response(conn, 200) - assert Enum.map(response["users"], & &1["deactivated"]) == [false, false] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do - user_one = insert(:user, deactivated: false) - user_two = insert(:user, deactivated: false) - - conn = - patch( - conn, - "/api/pleroma/admin/users/deactivate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response(conn, 200) - assert Enum.map(response["users"], & &1["deactivated"]) == [true, true] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do - user = insert(:user) - - conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation") - - assert json_response(conn, 200) == - %{ - "deactivated" => !user.deactivated, - "id" => user.id, - "nickname" => user.nickname, - "roles" => %{"admin" => false, "moderator" => false}, - "local" => true, - "tags" => [], - "avatar" => User.avatar_url(user) |> MediaProxy.url(), - "display_name" => HTML.strip_tags(user.name || user.nickname), - "confirmation_pending" => false, - "url" => user.ap_id - } - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user.nickname}" - end - - describe "PUT disable_mfa" do - test "returns 200 and disable 2fa", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true} - } - ) - - response = - conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname}) - |> json_response(200) - - assert response == user.nickname - mfa_settings = refresh_record(user).multi_factor_authentication_settings - - refute mfa_settings.enabled - refute mfa_settings.totp.confirmed - end - - test "returns 404 if user not found", %{conn: conn} do - response = - conn - |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) - |> json_response(404) - - assert response == %{"error" => "Not found"} - end - end - - describe "GET /api/pleroma/admin/restart" do - setup do: clear_config(:configurable_from_database, true) - - test "pleroma restarts", %{conn: conn} do - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} - end) =~ "pleroma restarted" - - refute Restarter.Pleroma.need_reboot?() - end - end - - test "need_reboot flag", %{conn: conn} do - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => false} - - Restarter.Pleroma.need_reboot() - - assert conn - |> get("/api/pleroma/admin/need_reboot") - |> json_response(200) == %{"need_reboot" => true} - - on_exit(fn -> Restarter.Pleroma.refresh() end) - end - - describe "GET /api/pleroma/admin/users/:nickname/statuses" do - setup do - user = insert(:user) - - date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!() - date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!() - date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!() - - insert(:note_activity, user: user, published: date1) - insert(:note_activity, user: user, published: date2) - insert(:note_activity, user: user, published: date3) - - %{user: user} - end - - test "renders user's statuses", %{conn: conn, user: user} do - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") - - assert json_response(conn, 200) |> length() == 3 - end - - test "renders user's statuses with a limit", %{conn: conn, user: user} do - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2") - - assert json_response(conn, 200) |> length() == 2 - end - - test "doesn't return private statuses by default", %{conn: conn, user: user} do - {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) - - {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") - - assert json_response(conn, 200) |> length() == 4 - end - - test "returns private statuses with godmode on", %{conn: conn, user: user} do - {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"}) - - {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"}) - - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true") - - assert json_response(conn, 200) |> length() == 5 - end - - test "excludes reblogs by default", %{conn: conn, user: user} do - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "."}) - {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user) - - conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses") - assert json_response(conn_res, 200) |> length() == 0 - - conn_res = - get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true") - - assert json_response(conn_res, 200) |> length() == 1 - end - end - - describe "GET /api/pleroma/admin/moderation_log" do - setup do - moderator = insert(:user, is_moderator: true) - - %{moderator: moderator} - end - - test "returns the log", %{conn: conn, admin: admin} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) - }) - - conn = get(conn, "/api/pleroma/admin/moderation_log") - - response = json_response(conn, 200) - [first_entry, second_entry] = response["items"] - - assert response["total"] == 2 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - - assert second_entry["data"]["action"] == "relay_follow" - - assert second_entry["message"] == - "@#{admin.nickname} followed relay: https://example.org/relay" - end - - test "returns the log with pagination", %{conn: conn, admin: admin} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second) - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 2 - assert response1["items"] |> length() == 1 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - - conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2") - - response2 = json_response(conn2, 200) - [second_entry] = response2["items"] - - assert response2["total"] == 2 - assert response2["items"] |> length() == 1 - assert second_entry["data"]["action"] == "relay_follow" - - assert second_entry["message"] == - "@#{admin.nickname} followed relay: https://example.org/relay" - end - - test "filters log by date", %{conn: conn, admin: admin} do - first_date = "2017-08-15T15:47:06Z" - second_date = "2017-08-20T15:47:06Z" - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.from_iso8601!(first_date) - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - }, - inserted_at: NaiveDateTime.from_iso8601!(second_date) - }) - - conn1 = - get( - conn, - "/api/pleroma/admin/moderation_log?start_date=#{second_date}" - ) - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - assert first_entry["data"]["action"] == "relay_unfollow" - - assert first_entry["message"] == - "@#{admin.nickname} unfollowed relay: https://example.org/relay" - end - - test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => admin.id, - "nickname" => admin.nickname, - "type" => "user" - }, - action: "relay_follow", - target: "https://example.org/relay" - } - }) - - Repo.insert(%ModerationLog{ - data: %{ - actor: %{ - "id" => moderator.id, - "nickname" => moderator.nickname, - "type" => "user" - }, - action: "relay_unfollow", - target: "https://example.org/relay" - } - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id - end - - test "returns log filtered by search", %{conn: conn, moderator: moderator} do - ModerationLog.insert_log(%{ - actor: moderator, - action: "relay_follow", - target: "https://example.org/relay" - }) - - ModerationLog.insert_log(%{ - actor: moderator, - action: "relay_unfollow", - target: "https://example.org/relay" - }) - - conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") - - response1 = json_response(conn1, 200) - [first_entry] = response1["items"] - - assert response1["total"] == 1 - - assert get_in(first_entry, ["data", "message"]) == - "@#{moderator.nickname} unfollowed relay: https://example.org/relay" - end - end - - test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated", - %{conn: conn} do - clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated) - user = insert(:user, %{local: false, nickname: "u@peer1.com"}) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") - - assert json_response(conn, 200) - end - - describe "GET /users/:nickname/credentials" do - test "gets the user credentials", %{conn: conn} do - user = insert(:user) - conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") - - response = assert json_response(conn, 200) - assert response["email"] == user.email - end - - test "returns 403 if requested by a non-admin" do - user = insert(:user) - - conn = - build_conn() - |> assign(:user, user) - |> get("/api/pleroma/admin/users/#{user.nickname}/credentials") - - assert json_response(conn, :forbidden) - end - end - - describe "PATCH /users/:nickname/credentials" do - setup do - user = insert(:user) - [user: user] - end - - test "changes password and email", %{conn: conn, admin: admin, user: user} do - assert user.password_reset_pending == false - - conn = - patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "password" => "new_password", - "email" => "new_email@example.com", - "name" => "new_name" - }) - - assert json_response(conn, 200) == %{"status" => "success"} - - ObanHelpers.perform_all() - - updated_user = User.get_by_id(user.id) - - assert updated_user.email == "new_email@example.com" - assert updated_user.name == "new_name" - assert updated_user.password_hash != user.password_hash - assert updated_user.password_reset_pending == true - - [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort() - - assert ModerationLog.get_log_entry_message(log_entry1) == - "@#{admin.nickname} updated users: @#{user.nickname}" - - assert ModerationLog.get_log_entry_message(log_entry2) == - "@#{admin.nickname} forced password reset for users: @#{user.nickname}" - end - - test "returns 403 if requested by a non-admin", %{user: user} do - conn = - build_conn() - |> assign(:user, user) - |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "password" => "new_password", - "email" => "new_email@example.com", - "name" => "new_name" - }) - - assert json_response(conn, :forbidden) - end - - test "changes actor type from permitted list", %{conn: conn, user: user} do - assert user.actor_type == "Person" - - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "actor_type" => "Service" - }) - |> json_response(200) == %{"status" => "success"} - - updated_user = User.get_by_id(user.id) - - assert updated_user.actor_type == "Service" - - assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ - "actor_type" => "Application" - }) - |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}} - end - - test "update non existing user", %{conn: conn} do - assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{ - "password" => "new_password" - }) - |> json_response(404) == %{"error" => "Not found"} - end - end - - describe "PATCH /users/:nickname/force_password_reset" do - test "sets password_reset_pending to true", %{conn: conn} do - user = insert(:user) - assert user.password_reset_pending == false - - conn = - patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]}) - - assert json_response(conn, 204) == "" - - ObanHelpers.perform_all() - - assert User.get_by_id(user.id).password_reset_pending == true - end - end - - describe "instances" do - test "GET /instances/:instance/statuses", %{conn: conn} do - user = insert(:user, local: false, nickname: "archaeme@archae.me") - user2 = insert(:user, local: false, nickname: "test@test.com") - insert_pair(:note_activity, user: user) - activity = insert(:note_activity, user: user2) - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") - - response = json_response(ret_conn, 200) - - assert length(response) == 2 - - ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses") - - response = json_response(ret_conn, 200) - - assert length(response) == 1 - - ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses") - - response = json_response(ret_conn, 200) - - assert Enum.empty?(response) - - CommonAPI.repeat(activity.id, user) - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") - response = json_response(ret_conn, 200) - assert length(response) == 2 - - ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") - response = json_response(ret_conn, 200) - assert length(response) == 3 - end - end - - describe "PATCH /confirm_email" do - test "it confirms emails of two users", %{conn: conn, admin: admin} do - [first_user, second_user] = insert_pair(:user, confirmation_pending: true) - - assert first_user.confirmation_pending == true - assert second_user.confirmation_pending == true - - ret_conn = - patch(conn, "/api/pleroma/admin/users/confirm_email", %{ - nicknames: [ - first_user.nickname, - second_user.nickname - ] - }) - - assert ret_conn.status == 200 - - assert first_user.confirmation_pending == true - assert second_user.confirmation_pending == true - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{ - second_user.nickname - }" - end - end - - describe "PATCH /resend_confirmation_email" do - test "it resend emails for two users", %{conn: conn, admin: admin} do - [first_user, second_user] = insert_pair(:user, confirmation_pending: true) - - ret_conn = - patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{ - nicknames: [ - first_user.nickname, - second_user.nickname - ] - }) - - assert ret_conn.status == 200 - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{ - second_user.nickname - }" - - ObanHelpers.perform_all() - assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user)) - end - end - - describe "/api/pleroma/admin/stats" do - test "status visibility count", %{conn: conn} do - admin = insert(:user, is_admin: true) - user = insert(:user) - CommonAPI.post(user, %{visibility: "public", status: "hey"}) - CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) - CommonAPI.post(user, %{visibility: "unlisted", status: "hey"}) - - response = - conn - |> assign(:user, admin) - |> get("/api/pleroma/admin/stats") - |> json_response(200) - - assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} = - response["status_visibility"] - end - - test "by instance", %{conn: conn} do - admin = insert(:user, is_admin: true) - user1 = insert(:user) - instance2 = "instance2.tld" - user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"}) - - CommonAPI.post(user1, %{visibility: "public", status: "hey"}) - CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"}) - CommonAPI.post(user2, %{visibility: "private", status: "hey"}) - - response = - conn - |> assign(:user, admin) - |> get("/api/pleroma/admin/stats", instance: instance2) - |> json_response(200) - - assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} = - response["status_visibility"] - 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/controllers/config_controller_test.exs b/test/web/admin_api/controllers/config_controller_test.exs deleted file mode 100644 index 61bc9fd39..000000000 --- a/test/web/admin_api/controllers/config_controller_test.exs +++ /dev/null @@ -1,1396 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do - use Pleroma.Web.ConnCase, async: true - - import ExUnit.CaptureLog - import Pleroma.Factory - - alias Pleroma.Config - alias Pleroma.ConfigDB - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "GET /api/pleroma/admin/config" do - setup do: clear_config(:configurable_from_database, true) - - test "when configuration from database is off", %{conn: conn} do - Config.put(:configurable_from_database, false) - conn = get(conn, "/api/pleroma/admin/config") - - assert json_response_and_validate_schema(conn, 400) == - %{ - "error" => "To use this endpoint you need to enable configuration from database." - } - end - - test "with settings only in db", %{conn: conn} do - config1 = insert(:config) - config2 = insert(:config) - - conn = get(conn, "/api/pleroma/admin/config?only_db=true") - - %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => key1, - "value" => _ - }, - %{ - "group" => ":pleroma", - "key" => key2, - "value" => _ - } - ] - } = json_response_and_validate_schema(conn, 200) - - assert key1 == inspect(config1.key) - assert key2 == inspect(config2.key) - end - - test "db is added to settings that are in db", %{conn: conn} do - _config = insert(:config, key: ":instance", value: [name: "Some name"]) - - %{"configs" => configs} = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - [instance_config] = - Enum.filter(configs, fn %{"group" => group, "key" => key} -> - group == ":pleroma" and key == ":instance" - end) - - assert instance_config["db"] == [":name"] - end - - test "merged default setting with db settings", %{conn: conn} do - config1 = insert(:config) - config2 = insert(:config) - - config3 = - insert(:config, - value: [k1: :v1, k2: :v2] - ) - - %{"configs" => configs} = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - assert length(configs) > 3 - - saved_configs = [config1, config2, config3] - keys = Enum.map(saved_configs, &inspect(&1.key)) - - received_configs = - Enum.filter(configs, fn %{"group" => group, "key" => key} -> - group == ":pleroma" and key in keys - end) - - assert length(received_configs) == 3 - - db_keys = - config3.value - |> Keyword.keys() - |> ConfigDB.to_json_types() - - keys = Enum.map(saved_configs -- [config3], &inspect(&1.key)) - - values = Enum.map(saved_configs, &ConfigDB.to_json_types(&1.value)) - - mapset_keys = MapSet.new(keys ++ db_keys) - - Enum.each(received_configs, fn %{"value" => value, "db" => db} -> - db = MapSet.new(db) - assert MapSet.subset?(db, mapset_keys) - - assert value in values - end) - end - - test "subkeys with full update right merge", %{conn: conn} do - insert(:config, - key: ":emoji", - value: [groups: [a: 1, b: 2], key: [a: 1]] - ) - - insert(:config, - key: ":assets", - value: [mascots: [a: 1, b: 2], key: [a: 1]] - ) - - %{"configs" => configs} = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - vals = - Enum.filter(configs, fn %{"group" => group, "key" => key} -> - group == ":pleroma" and key in [":emoji", ":assets"] - end) - - emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) - assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) - - emoji_val = ConfigDB.to_elixir_types(emoji["value"]) - assets_val = ConfigDB.to_elixir_types(assets["value"]) - - assert emoji_val[:groups] == [a: 1, b: 2] - assert assets_val[:mascots] == [a: 1, b: 2] - end - - test "with valid `admin_token` query parameter, skips OAuth scopes check" do - clear_config([:admin_token], "password123") - - build_conn() - |> get("/api/pleroma/admin/config?admin_token=password123") - |> json_response_and_validate_schema(200) - end - end - - test "POST /api/pleroma/admin/config error", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{"configs" => []}) - - assert json_response_and_validate_schema(conn, 400) == - %{"error" => "To use this endpoint you need to enable configuration from database."} - end - - describe "POST /api/pleroma/admin/config" do - setup do - http = Application.get_env(:pleroma, :http) - - 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) - Application.put_env(:pleroma, :http, http) - Application.put_env(:tesla, :adapter, Tesla.Mock) - Restarter.Pleroma.refresh() - end) - end - - setup do: clear_config(:configurable_from_database, true) - - @tag capture_log: true - test "create new config setting in db", %{conn: conn} do - ueberauth = Application.get_env(:ueberauth, Ueberauth) - on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":key1", value: "value1"}, - %{ - group: ":ueberauth", - key: "Ueberauth", - 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_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => "value1", - "db" => [":key1"] - }, - %{ - "group" => ":ueberauth", - "key" => "Ueberauth", - "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], - "db" => [":consumer_secret"] - }, - %{ - "group" => ":pleroma", - "key" => ":key2", - "value" => %{ - ":nested_1" => "nested_value1", - ":nested_2" => [ - %{":nested_22" => "nested_value222"}, - %{":nested_33" => %{":nested_44" => "nested_444"}} - ] - }, - "db" => [":key2"] - }, - %{ - "group" => ":pleroma", - "key" => ":key3", - "value" => [ - %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, - %{"nested_4" => true} - ], - "db" => [":key3"] - }, - %{ - "group" => ":pleroma", - "key" => ":key4", - "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, - "db" => [":key4"] - }, - %{ - "group" => ":idna", - "key" => ":key5", - "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, - "db" => [":key5"] - } - ], - "need_reboot" => false - } - - 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 "save configs setting without explicit key", %{conn: conn} do - level = Application.get_env(:quack, :level) - meta = Application.get_env(:quack, :meta) - webhook_url = Application.get_env(:quack, :webhook_url) - - on_exit(fn -> - Application.put_env(:quack, :level, level) - Application.put_env(:quack, :meta, meta) - Application.put_env(:quack, :webhook_url, webhook_url) - end) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":quack", - key: ":level", - value: ":info" - }, - %{ - group: ":quack", - key: ":meta", - value: [":none"] - }, - %{ - group: ":quack", - key: ":webhook_url", - value: "https://hooks.slack.com/services/KEY" - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":quack", - "key" => ":level", - "value" => ":info", - "db" => [":level"] - }, - %{ - "group" => ":quack", - "key" => ":meta", - "value" => [":none"], - "db" => [":meta"] - }, - %{ - "group" => ":quack", - "key" => ":webhook_url", - "value" => "https://hooks.slack.com/services/KEY", - "db" => [":webhook_url"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:quack, :level) == :info - assert Application.get_env(:quack, :meta) == [:none] - assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY" - end - - test "saving config with partial update", %{conn: conn} do - insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => [ - %{"tuple" => [":key1", 1]}, - %{"tuple" => [":key2", 2]}, - %{"tuple" => [":key3", 3]} - ], - "db" => [":key1", ":key2", ":key3"] - } - ], - "need_reboot" => false - } - end - - test "saving config which need pleroma reboot", %{conn: conn} do - chat = Config.get(:chat) - on_exit(fn -> Config.put(:chat, chat) end) - - assert conn - |> put_req_header("content-type", "application/json") - |> post( - "/api/pleroma/admin/config", - %{ - configs: [ - %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} - ] - } - ) - |> json_response_and_validate_schema(200) == %{ - "configs" => [ - %{ - "db" => [":enabled"], - "group" => ":pleroma", - "key" => ":chat", - "value" => [%{"tuple" => [":enabled", true]}] - } - ], - "need_reboot" => true - } - - configs = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - assert configs["need_reboot"] - - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == - %{} - end) =~ "pleroma restarted" - - configs = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - assert configs["need_reboot"] == false - end - - test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do - chat = Config.get(:chat) - on_exit(fn -> Config.put(:chat, chat) end) - - assert conn - |> put_req_header("content-type", "application/json") - |> post( - "/api/pleroma/admin/config", - %{ - configs: [ - %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} - ] - } - ) - |> json_response_and_validate_schema(200) == %{ - "configs" => [ - %{ - "db" => [":enabled"], - "group" => ":pleroma", - "key" => ":chat", - "value" => [%{"tuple" => [":enabled", true]}] - } - ], - "need_reboot" => true - } - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} - ] - }) - |> json_response_and_validate_schema(200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => [ - %{"tuple" => [":key3", 3]} - ], - "db" => [":key3"] - } - ], - "need_reboot" => true - } - - capture_log(fn -> - assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == - %{} - end) =~ "pleroma restarted" - - configs = - conn - |> get("/api/pleroma/admin/config") - |> json_response_and_validate_schema(200) - - assert configs["need_reboot"] == false - end - - test "saving config with nested merge", %{conn: conn} do - insert(:config, key: :key1, value: [key1: 1, key2: [k1: 1, k2: 2]]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":key1", - value: [ - %{"tuple" => [":key3", 3]}, - %{ - "tuple" => [ - ":key2", - [ - %{"tuple" => [":k2", 1]}, - %{"tuple" => [":k3", 3]} - ] - ] - } - ] - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => [ - %{"tuple" => [":key1", 1]}, - %{"tuple" => [":key3", 3]}, - %{ - "tuple" => [ - ":key2", - [ - %{"tuple" => [":k1", 1]}, - %{"tuple" => [":k2", 1]}, - %{"tuple" => [":k3", 3]} - ] - ] - } - ], - "db" => [":key1", ":key3", ":key2"] - } - ], - "need_reboot" => false - } - end - - test "saving special atoms", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => [ - %{ - "tuple" => [ - ":ssl_options", - [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] - ] - } - ] - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => [ - %{ - "tuple" => [ - ":ssl_options", - [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] - ] - } - ], - "db" => [":ssl_options"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:pleroma, :key1) == [ - ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]] - ] - end - - test "saving full setting if value is in full_key_update list", %{conn: conn} do - backends = Application.get_env(:logger, :backends) - on_exit(fn -> Application.put_env(:logger, :backends, backends) end) - - insert(:config, - group: :logger, - key: :backends, - value: [] - ) - - Pleroma.Config.TransferTask.load_and_update_env([], false) - - assert Application.get_env(:logger, :backends) == [] - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":logger", - key: ":backends", - value: [":console"] - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":logger", - "key" => ":backends", - "value" => [ - ":console" - ], - "db" => [":backends"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:logger, :backends) == [ - :console - ] - end - - test "saving full setting if value is not keyword", %{conn: conn} do - insert(:config, - group: :tesla, - key: :adapter, - value: Tesla.Adapter.Hackey - ) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":tesla", key: ":adapter", value: "Tesla.Adapter.Httpc"} - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":tesla", - "key" => ":adapter", - "value" => "Tesla.Adapter.Httpc", - "db" => [":adapter"] - } - ], - "need_reboot" => false - } - end - - test "update config setting & delete with fallback to default value", %{ - conn: conn, - admin: admin, - token: token - } do - ueberauth = Application.get_env(:ueberauth, Ueberauth) - insert(:config, key: :keyaa1) - insert(:config, key: :keyaa2) - - config3 = - insert(:config, - group: :ueberauth, - key: Ueberauth - ) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":keyaa1", value: "another_value"}, - %{group: ":pleroma", key: ":keyaa2", value: "another_value"} - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":keyaa1", - "value" => "another_value", - "db" => [":keyaa1"] - }, - %{ - "group" => ":pleroma", - "key" => ":keyaa2", - "value" => "another_value", - "db" => [":keyaa2"] - } - ], - "need_reboot" => false - } - - assert Application.get_env(:pleroma, :keyaa1) == "another_value" - assert Application.get_env(:pleroma, :keyaa2) == "another_value" - assert Application.get_env(:ueberauth, Ueberauth) == config3.value - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":keyaa2", delete: true}, - %{ - group: ":ueberauth", - key: "Ueberauth", - delete: true - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [], - "need_reboot" => false - } - - assert Application.get_env(:ueberauth, Ueberauth) == ueberauth - refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2) - end - - test "common config example", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/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]}, - %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, - %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]}, - %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]}, - %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, - %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}, - %{"tuple" => [":name", "Pleroma"]} - ] - } - ] - }) - - assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" - - assert json_response_and_validate_schema(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]}, - %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, - %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]}, - %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]}, - %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, - %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}, - %{"tuple" => [":name", "Pleroma"]} - ], - "db" => [ - ":enabled", - ":method", - ":seconds_valid", - ":path", - ":key1", - ":partial_chain", - ":regex1", - ":regex2", - ":regex3", - ":regex4", - ":name" - ] - } - ], - "need_reboot" => false - } - end - - test "tuples with more than two values", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/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_and_validate_schema(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", []]} - ] - } - ] - ] - } - ] - ] - } - ] - ] - } - ], - "db" => [":http"] - } - ], - "need_reboot" => false - } - end - - test "settings with nesting map", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/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_and_validate_schema(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 - } - } - ] - } - ], - "db" => [":key2", ":key3"] - } - ], - "need_reboot" => false - } - end - - test "value as map", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => %{"key" => "some_val"} - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == - %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":key1", - "value" => %{"key" => "some_val"}, - "db" => [":key1"] - } - ], - "need_reboot" => false - } - end - - test "queues key as atom", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - "group" => ":oban", - "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_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":oban", - "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]} - ], - "db" => [ - ":federator_incoming", - ":federator_outgoing", - ":web_push", - ":mailer", - ":transmogrifier", - ":scheduled_activities", - ":background" - ] - } - ], - "need_reboot" => false - } - end - - test "delete part of settings by atom subkeys", %{conn: conn} do - insert(:config, - key: :keyaa1, - value: [subkey1: "val1", subkey2: "val2", subkey3: "val3"] - ) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":keyaa1", - subkeys: [":subkey1", ":subkey3"], - delete: true - } - ] - }) - - assert json_response_and_validate_schema(conn, 200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":keyaa1", - "value" => [%{"tuple" => [":subkey2", "val2"]}], - "db" => [":subkey2"] - } - ], - "need_reboot" => false - } - end - - test "proxy tuple localhost", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":http", - value: [ - %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} - ] - } - ] - }) - - assert %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":http", - "value" => value, - "db" => db - } - ] - } = json_response_and_validate_schema(conn, 200) - - assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value - assert ":proxy_url" in db - end - - test "proxy tuple domain", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":http", - value: [ - %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} - ] - } - ] - }) - - assert %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":http", - "value" => value, - "db" => db - } - ] - } = json_response_and_validate_schema(conn, 200) - - assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value - assert ":proxy_url" in db - end - - test "proxy tuple ip", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: ":http", - value: [ - %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} - ] - } - ] - }) - - assert %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => ":http", - "value" => value, - "db" => db - } - ] - } = json_response_and_validate_schema(conn, 200) - - assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value - assert ":proxy_url" in db - end - - @tag capture_log: true - test "doesn't set keys not in the whitelist", %{conn: conn} do - clear_config(:database_config_whitelist, [ - {:pleroma, :key1}, - {:pleroma, :key2}, - {:pleroma, Pleroma.Captcha.NotReal}, - {:not_real} - ]) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{group: ":pleroma", key: ":key1", value: "value1"}, - %{group: ":pleroma", key: ":key2", value: "value2"}, - %{group: ":pleroma", key: ":key3", value: "value3"}, - %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, - %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, - %{group: ":not_real", key: ":anything", value: "value6"} - ] - }) - - assert Application.get_env(:pleroma, :key1) == "value1" - assert Application.get_env(:pleroma, :key2) == "value2" - assert Application.get_env(:pleroma, :key3) == nil - assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil - assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" - assert Application.get_env(:not_real, :anything) == "value6" - end - - test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do - clear_config(Pleroma.Upload.Filter.Mogrify) - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: "Pleroma.Upload.Filter.Mogrify", - value: [ - %{"tuple" => [":args", ["auto-orient", "strip"]]} - ] - } - ] - }) - |> json_response_and_validate_schema(200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => "Pleroma.Upload.Filter.Mogrify", - "value" => [ - %{"tuple" => [":args", ["auto-orient", "strip"]]} - ], - "db" => [":args"] - } - ], - "need_reboot" => false - } - - assert Config.get(Pleroma.Upload.Filter.Mogrify) == [args: ["auto-orient", "strip"]] - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/config", %{ - configs: [ - %{ - group: ":pleroma", - key: "Pleroma.Upload.Filter.Mogrify", - value: [ - %{ - "tuple" => [ - ":args", - [ - "auto-orient", - "strip", - "{\"implode\", \"1\"}", - "{\"resize\", \"3840x1080>\"}" - ] - ] - } - ] - } - ] - }) - |> json_response(200) == %{ - "configs" => [ - %{ - "group" => ":pleroma", - "key" => "Pleroma.Upload.Filter.Mogrify", - "value" => [ - %{ - "tuple" => [ - ":args", - [ - "auto-orient", - "strip", - "{\"implode\", \"1\"}", - "{\"resize\", \"3840x1080>\"}" - ] - ] - } - ], - "db" => [":args"] - } - ], - "need_reboot" => false - } - - assert Config.get(Pleroma.Upload.Filter.Mogrify) == [ - args: ["auto-orient", "strip", {"implode", "1"}, {"resize", "3840x1080>"}] - ] - end - end - - describe "GET /api/pleroma/admin/config/descriptions" do - test "structure", %{conn: conn} do - admin = insert(:user, is_admin: true) - - conn = - assign(conn, :user, admin) - |> get("/api/pleroma/admin/config/descriptions") - - assert [child | _others] = json_response_and_validate_schema(conn, 200) - - assert child["children"] - assert child["key"] - assert String.starts_with?(child["group"], ":") - assert child["description"] - end - - test "filters by database configuration whitelist", %{conn: conn} do - clear_config(:database_config_whitelist, [ - {:pleroma, :instance}, - {:pleroma, :activitypub}, - {:pleroma, Pleroma.Upload}, - {:esshd} - ]) - - admin = insert(:user, is_admin: true) - - conn = - assign(conn, :user, admin) - |> get("/api/pleroma/admin/config/descriptions") - - children = json_response_and_validate_schema(conn, 200) - - assert length(children) == 4 - - assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3 - - instance = Enum.find(children, fn c -> c["key"] == ":instance" end) - assert instance["children"] - - activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end) - assert activitypub["children"] - - web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) - assert web_endpoint["children"] - - esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end) - assert esshd["children"] - end - end -end diff --git a/test/web/admin_api/controllers/invite_controller_test.exs b/test/web/admin_api/controllers/invite_controller_test.exs deleted file mode 100644 index ab186c5e7..000000000 --- a/test/web/admin_api/controllers/invite_controller_test.exs +++ /dev/null @@ -1,281 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.InviteControllerTest do - use Pleroma.Web.ConnCase, async: true - - import Pleroma.Factory - - alias Pleroma.Config - alias Pleroma.Repo - alias Pleroma.UserInviteToken - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "POST /api/pleroma/admin/users/email_invite, with valid config" do - setup do: clear_config([:instance, :registrations_open], false) - setup do: clear_config([:instance, :invites_enabled], true) - - test "sends invitation and returns 204", %{admin: admin, conn: conn} do - recipient_email = "foo@bar.com" - recipient_name = "J. D." - - conn = - conn - |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{ - email: recipient_email, - name: recipient_name - }) - - assert json_response_and_validate_schema(conn, :no_content) - - token_record = List.last(Repo.all(Pleroma.UserInviteToken)) - assert token_record - refute token_record.used - - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - email = - Pleroma.Emails.UserEmail.user_invitation_email( - admin, - token_record, - recipient_email, - recipient_name - ) - - Swoosh.TestAssertions.assert_email_sent( - from: {instance_name, notify_email}, - to: {recipient_name, recipient_email}, - html_body: email.html_body - ) - end - - test "it returns 403 if requested by a non-admin" do - non_admin_user = insert(:user) - token = insert(:oauth_token, user: non_admin_user) - - conn = - build_conn() - |> assign(:user, non_admin_user) - |> assign(:token, token) - |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{ - email: "foo@bar.com", - name: "JD" - }) - - assert json_response(conn, :forbidden) - end - - test "email with +", %{conn: conn, admin: admin} do - recipient_email = "foo+bar@baz.com" - - conn - |> put_req_header("content-type", "application/json;charset=utf-8") - |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email}) - |> json_response_and_validate_schema(:no_content) - - token_record = - Pleroma.UserInviteToken - |> Repo.all() - |> List.last() - - assert token_record - refute token_record.used - - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - email = - Pleroma.Emails.UserEmail.user_invitation_email( - admin, - token_record, - recipient_email - ) - - Swoosh.TestAssertions.assert_email_sent( - from: {instance_name, notify_email}, - to: recipient_email, - html_body: email.html_body - ) - end - end - - describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do - setup do: clear_config([:instance, :registrations_open]) - setup do: clear_config([:instance, :invites_enabled]) - - test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do - Config.put([:instance, :registrations_open], false) - Config.put([:instance, :invites_enabled], false) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/email_invite", %{ - email: "foo@bar.com", - name: "JD" - }) - - assert json_response_and_validate_schema(conn, :bad_request) == - %{ - "error" => - "To send invites you need to set the `invites_enabled` option to true." - } - end - - test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do - Config.put([:instance, :registrations_open], true) - Config.put([:instance, :invites_enabled], true) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/email_invite", %{ - email: "foo@bar.com", - name: "JD" - }) - - assert json_response_and_validate_schema(conn, :bad_request) == - %{ - "error" => - "To send invites you need to set the `registrations_open` option to false." - } - end - end - - describe "POST /api/pleroma/admin/users/invite_token" do - test "without options", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token") - - invite_json = json_response_and_validate_schema(conn, 200) - invite = UserInviteToken.find_by_token!(invite_json["token"]) - refute invite.used - refute invite.expires_at - refute invite.max_use - assert invite.invite_type == "one_time" - end - - test "with expires_at", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{ - "expires_at" => Date.to_string(Date.utc_today()) - }) - - invite_json = json_response_and_validate_schema(conn, 200) - invite = UserInviteToken.find_by_token!(invite_json["token"]) - - refute invite.used - assert invite.expires_at == Date.utc_today() - refute invite.max_use - assert invite.invite_type == "date_limited" - end - - test "with max_use", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) - - invite_json = json_response_and_validate_schema(conn, 200) - invite = UserInviteToken.find_by_token!(invite_json["token"]) - refute invite.used - refute invite.expires_at - assert invite.max_use == 150 - assert invite.invite_type == "reusable" - end - - test "with max use and expires_at", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/invite_token", %{ - "max_use" => 150, - "expires_at" => Date.to_string(Date.utc_today()) - }) - - invite_json = json_response_and_validate_schema(conn, 200) - invite = UserInviteToken.find_by_token!(invite_json["token"]) - refute invite.used - assert invite.expires_at == Date.utc_today() - assert invite.max_use == 150 - assert invite.invite_type == "reusable_date_limited" - end - end - - describe "GET /api/pleroma/admin/users/invites" do - test "no invites", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/users/invites") - - assert json_response_and_validate_schema(conn, 200) == %{"invites" => []} - end - - test "with invite", %{conn: conn} do - {:ok, invite} = UserInviteToken.create_invite() - - conn = get(conn, "/api/pleroma/admin/users/invites") - - assert json_response_and_validate_schema(conn, 200) == %{ - "invites" => [ - %{ - "expires_at" => nil, - "id" => invite.id, - "invite_type" => "one_time", - "max_use" => nil, - "token" => invite.token, - "used" => false, - "uses" => 0 - } - ] - } - end - end - - describe "POST /api/pleroma/admin/users/revoke_invite" do - test "with token", %{conn: conn} do - {:ok, invite} = UserInviteToken.create_invite() - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token}) - - assert json_response_and_validate_schema(conn, 200) == %{ - "expires_at" => nil, - "id" => invite.id, - "invite_type" => "one_time", - "max_use" => nil, - "token" => invite.token, - "used" => true, - "uses" => 0 - } - end - - test "with invalid token", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) - - assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} - end - end -end diff --git a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs b/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs deleted file mode 100644 index 5ab6cb78a..000000000 --- a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs +++ /dev/null @@ -1,145 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - import Mock - - alias Pleroma.Web.MediaProxy - - setup do: clear_config([:media_proxy]) - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - Config.put([:media_proxy, :enabled], true) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], MediaProxy.Invalidation.Script) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "GET /api/pleroma/admin/media_proxy_caches" do - test "shows banned MediaProxy URLs", %{conn: conn} do - MediaProxy.put_in_banned_urls([ - "http://localhost:4001/media/a688346.jpg", - "http://localhost:4001/media/fb1f4d.jpg" - ]) - - MediaProxy.put_in_banned_urls("http://localhost:4001/media/gb1f44.jpg") - MediaProxy.put_in_banned_urls("http://localhost:4001/media/tb13f47.jpg") - MediaProxy.put_in_banned_urls("http://localhost:4001/media/wb1f46.jpg") - - response = - conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2") - |> json_response_and_validate_schema(200) - - assert response["urls"] == [ - "http://localhost:4001/media/fb1f4d.jpg", - "http://localhost:4001/media/a688346.jpg" - ] - - response = - conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=2") - |> json_response_and_validate_schema(200) - - assert response["urls"] == [ - "http://localhost:4001/media/gb1f44.jpg", - "http://localhost:4001/media/tb13f47.jpg" - ] - - response = - conn - |> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=3") - |> json_response_and_validate_schema(200) - - assert response["urls"] == ["http://localhost:4001/media/wb1f46.jpg"] - end - end - - describe "POST /api/pleroma/admin/media_proxy_caches/delete" do - test "deleted MediaProxy URLs from banned", %{conn: conn} do - MediaProxy.put_in_banned_urls([ - "http://localhost:4001/media/a688346.jpg", - "http://localhost:4001/media/fb1f4d.jpg" - ]) - - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/media_proxy_caches/delete", %{ - urls: ["http://localhost:4001/media/a688346.jpg"] - }) - |> json_response_and_validate_schema(200) - - assert response["urls"] == ["http://localhost:4001/media/a688346.jpg"] - refute MediaProxy.in_banned_urls("http://localhost:4001/media/a688346.jpg") - assert MediaProxy.in_banned_urls("http://localhost:4001/media/fb1f4d.jpg") - end - end - - describe "POST /api/pleroma/admin/media_proxy_caches/purge" do - test "perform invalidates cache of MediaProxy", %{conn: conn} do - urls = [ - "http://example.com/media/a688346.jpg", - "http://example.com/media/fb1f4d.jpg" - ] - - with_mocks [ - {MediaProxy.Invalidation.Script, [], - [ - purge: fn _, _ -> {"ok", 0} end - ]} - ] do - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/media_proxy_caches/purge", %{urls: urls, ban: false}) - |> json_response_and_validate_schema(200) - - assert response["urls"] == urls - - refute MediaProxy.in_banned_urls("http://example.com/media/a688346.jpg") - refute MediaProxy.in_banned_urls("http://example.com/media/fb1f4d.jpg") - end - end - - test "perform invalidates cache of MediaProxy and adds url to banned", %{conn: conn} do - urls = [ - "http://example.com/media/a688346.jpg", - "http://example.com/media/fb1f4d.jpg" - ] - - with_mocks [{MediaProxy.Invalidation.Script, [], [purge: fn _, _ -> {"ok", 0} end]}] do - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/media_proxy_caches/purge", %{ - urls: urls, - ban: true - }) - |> json_response_and_validate_schema(200) - - assert response["urls"] == urls - - assert MediaProxy.in_banned_urls("http://example.com/media/a688346.jpg") - assert MediaProxy.in_banned_urls("http://example.com/media/fb1f4d.jpg") - end - end - end -end diff --git a/test/web/admin_api/controllers/oauth_app_controller_test.exs b/test/web/admin_api/controllers/oauth_app_controller_test.exs deleted file mode 100644 index ed7c4172c..000000000 --- a/test/web/admin_api/controllers/oauth_app_controller_test.exs +++ /dev/null @@ -1,220 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do - use Pleroma.Web.ConnCase, async: true - use Oban.Testing, repo: Pleroma.Repo - - import Pleroma.Factory - - alias Pleroma.Config - alias Pleroma.Web - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "POST /api/pleroma/admin/oauth_app" do - test "errors", %{conn: conn} do - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{}) - |> json_response_and_validate_schema(400) - - assert %{ - "error" => "Missing field: name. Missing field: redirect_uris." - } = response - end - - test "success", %{conn: conn} do - base_url = Web.base_url() - app_name = "Trusted app" - - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{ - name: app_name, - redirect_uris: base_url - }) - |> json_response_and_validate_schema(200) - - assert %{ - "client_id" => _, - "client_secret" => _, - "name" => ^app_name, - "redirect_uri" => ^base_url, - "trusted" => false - } = response - end - - test "with trusted", %{conn: conn} do - base_url = Web.base_url() - app_name = "Trusted app" - - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/oauth_app", %{ - name: app_name, - redirect_uris: base_url, - trusted: true - }) - |> json_response_and_validate_schema(200) - - assert %{ - "client_id" => _, - "client_secret" => _, - "name" => ^app_name, - "redirect_uri" => ^base_url, - "trusted" => true - } = response - end - end - - describe "GET /api/pleroma/admin/oauth_app" do - setup do - app = insert(:oauth_app) - {:ok, app: app} - end - - test "list", %{conn: conn} do - response = - conn - |> get("/api/pleroma/admin/oauth_app") - |> json_response_and_validate_schema(200) - - assert %{"apps" => apps, "count" => count, "page_size" => _} = response - - assert length(apps) == count - end - - test "with page size", %{conn: conn} do - insert(:oauth_app) - page_size = 1 - - response = - conn - |> get("/api/pleroma/admin/oauth_app?page_size=#{page_size}") - |> json_response_and_validate_schema(200) - - assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response - - assert length(apps) == page_size - end - - test "search by client name", %{conn: conn, app: app} do - response = - conn - |> get("/api/pleroma/admin/oauth_app?name=#{app.client_name}") - |> json_response_and_validate_schema(200) - - assert %{"apps" => [returned], "count" => _, "page_size" => _} = response - - assert returned["client_id"] == app.client_id - assert returned["name"] == app.client_name - end - - test "search by client id", %{conn: conn, app: app} do - response = - conn - |> get("/api/pleroma/admin/oauth_app?client_id=#{app.client_id}") - |> json_response_and_validate_schema(200) - - assert %{"apps" => [returned], "count" => _, "page_size" => _} = response - - assert returned["client_id"] == app.client_id - assert returned["name"] == app.client_name - end - - test "only trusted", %{conn: conn} do - app = insert(:oauth_app, trusted: true) - - response = - conn - |> get("/api/pleroma/admin/oauth_app?trusted=true") - |> json_response_and_validate_schema(200) - - assert %{"apps" => [returned], "count" => _, "page_size" => _} = response - - assert returned["client_id"] == app.client_id - assert returned["name"] == app.client_name - end - end - - describe "DELETE /api/pleroma/admin/oauth_app/:id" do - test "with id", %{conn: conn} do - app = insert(:oauth_app) - - response = - conn - |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id)) - |> json_response_and_validate_schema(:no_content) - - assert response == "" - end - - test "with non existance id", %{conn: conn} do - response = - conn - |> delete("/api/pleroma/admin/oauth_app/0") - |> json_response_and_validate_schema(:bad_request) - - assert response == "" - end - end - - describe "PATCH /api/pleroma/admin/oauth_app/:id" do - test "with id", %{conn: conn} do - app = insert(:oauth_app) - - name = "another name" - url = "https://example.com" - scopes = ["admin"] - id = app.id - website = "http://website.com" - - response = - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/oauth_app/#{id}", %{ - name: name, - trusted: true, - redirect_uris: url, - scopes: scopes, - website: website - }) - |> json_response_and_validate_schema(200) - - assert %{ - "client_id" => _, - "client_secret" => _, - "id" => ^id, - "name" => ^name, - "redirect_uri" => ^url, - "trusted" => true, - "website" => ^website - } = response - end - - test "without id", %{conn: conn} do - response = - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/oauth_app/0") - |> json_response_and_validate_schema(:bad_request) - - assert response == "" - end - end -end diff --git a/test/web/admin_api/controllers/relay_controller_test.exs b/test/web/admin_api/controllers/relay_controller_test.exs deleted file mode 100644 index 64086adc5..000000000 --- a/test/web/admin_api/controllers/relay_controller_test.exs +++ /dev/null @@ -1,92 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.RelayControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Config - alias Pleroma.ModerationLog - alias Pleroma.Repo - alias Pleroma.User - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - - :ok - end - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "relays" do - test "POST /relay", %{conn: conn, admin: admin} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/relay", %{ - relay_url: "http://mastodon.example.org/users/admin" - }) - - assert json_response_and_validate_schema(conn, 200) == - "http://mastodon.example.org/users/admin" - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" - end - - test "GET /relay", %{conn: conn} do - relay_user = Pleroma.Web.ActivityPub.Relay.get_actor() - - ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"] - |> Enum.each(fn ap_id -> - {:ok, user} = User.get_or_fetch_by_ap_id(ap_id) - User.follow(relay_user, user) - end) - - conn = get(conn, "/api/pleroma/admin/relay") - - assert json_response_and_validate_schema(conn, 200)["relays"] -- - ["mastodon.example.org", "mstdn.io"] == [] - end - - test "DELETE /relay", %{conn: conn, admin: admin} do - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/relay", %{ - relay_url: "http://mastodon.example.org/users/admin" - }) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/relay", %{ - relay_url: "http://mastodon.example.org/users/admin" - }) - - assert json_response_and_validate_schema(conn, 200) == - "http://mastodon.example.org/users/admin" - - [log_entry_one, log_entry_two] = Repo.all(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry_one) == - "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" - - assert ModerationLog.get_log_entry_message(log_entry_two) == - "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" - end - end -end diff --git a/test/web/admin_api/controllers/report_controller_test.exs b/test/web/admin_api/controllers/report_controller_test.exs deleted file mode 100644 index f30dc8956..000000000 --- a/test/web/admin_api/controllers/report_controller_test.exs +++ /dev/null @@ -1,374 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.ReportControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.ModerationLog - alias Pleroma.Repo - alias Pleroma.ReportNote - alias Pleroma.Web.CommonAPI - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "GET /api/pleroma/admin/reports/:id" do - test "returns report by its id", %{conn: conn} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - response = - conn - |> get("/api/pleroma/admin/reports/#{report_id}") - |> json_response_and_validate_schema(:ok) - - assert response["id"] == report_id - end - - test "returns 404 when report id is invalid", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/reports/test") - - assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} - end - end - - describe "PATCH /api/pleroma/admin/reports" do - setup do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - {:ok, %{id: second_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel very offended", - status_ids: [activity.id] - }) - - %{ - id: report_id, - second_report_id: second_report_id - } - end - - test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do - read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"]) - - response = - conn - |> assign(:token, read_token) - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [%{"state" => "resolved", "id" => id}] - }) - |> json_response_and_validate_schema(403) - - assert response == %{ - "error" => "Insufficient permissions: admin:write:reports." - } - - conn - |> assign(:token, write_token) - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [%{"state" => "resolved", "id" => id}] - }) - |> json_response_and_validate_schema(:no_content) - end - - test "mark report as resolved", %{conn: conn, id: id, admin: admin} do - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [ - %{"state" => "resolved", "id" => id} - ] - }) - |> json_response_and_validate_schema(:no_content) - - activity = Activity.get_by_id(id) - assert activity.data["state"] == "resolved" - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated report ##{id} with 'resolved' state" - end - - test "closes report", %{conn: conn, id: id, admin: admin} do - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [ - %{"state" => "closed", "id" => id} - ] - }) - |> json_response_and_validate_schema(:no_content) - - activity = Activity.get_by_id(id) - assert activity.data["state"] == "closed" - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated report ##{id} with 'closed' state" - end - - test "returns 400 when state is unknown", %{conn: conn, id: id} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [ - %{"state" => "test", "id" => id} - ] - }) - - assert "Unsupported state" = - hd(json_response_and_validate_schema(conn, :bad_request))["error"] - end - - test "returns 404 when report is not exist", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [ - %{"state" => "closed", "id" => "test"} - ] - }) - - assert hd(json_response_and_validate_schema(conn, :bad_request))["error"] == "not_found" - end - - test "updates state of multiple reports", %{ - conn: conn, - id: id, - admin: admin, - second_report_id: second_report_id - } do - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/reports", %{ - "reports" => [ - %{"state" => "resolved", "id" => id}, - %{"state" => "closed", "id" => second_report_id} - ] - }) - |> json_response_and_validate_schema(:no_content) - - activity = Activity.get_by_id(id) - second_activity = Activity.get_by_id(second_report_id) - assert activity.data["state"] == "resolved" - assert second_activity.data["state"] == "closed" - - [first_log_entry, second_log_entry] = Repo.all(ModerationLog) - - assert ModerationLog.get_log_entry_message(first_log_entry) == - "@#{admin.nickname} updated report ##{id} with 'resolved' state" - - assert ModerationLog.get_log_entry_message(second_log_entry) == - "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state" - end - end - - describe "GET /api/pleroma/admin/reports" do - test "returns empty response when no reports created", %{conn: conn} do - response = - conn - |> get("/api/pleroma/admin/reports") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response["reports"]) - assert response["total"] == 0 - end - - test "returns reports", %{conn: conn} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - response = - conn - |> get("/api/pleroma/admin/reports") - |> json_response_and_validate_schema(:ok) - - [report] = response["reports"] - - assert length(response["reports"]) == 1 - assert report["id"] == report_id - - assert response["total"] == 1 - end - - test "returns reports with specified state", %{conn: conn} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: first_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - {:ok, %{id: second_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I don't like this user" - }) - - CommonAPI.update_report_state(second_report_id, "closed") - - response = - conn - |> get("/api/pleroma/admin/reports?state=open") - |> json_response_and_validate_schema(:ok) - - assert [open_report] = response["reports"] - - assert length(response["reports"]) == 1 - assert open_report["id"] == first_report_id - - assert response["total"] == 1 - - response = - conn - |> get("/api/pleroma/admin/reports?state=closed") - |> json_response_and_validate_schema(:ok) - - assert [closed_report] = response["reports"] - - assert length(response["reports"]) == 1 - assert closed_report["id"] == second_report_id - - assert response["total"] == 1 - - assert %{"total" => 0, "reports" => []} == - conn - |> get("/api/pleroma/admin/reports?state=resolved", %{ - "" => "" - }) - |> json_response_and_validate_schema(:ok) - end - - test "returns 403 when requested by a non-admin" do - user = insert(:user) - token = insert(:oauth_token, user: user) - - conn = - build_conn() - |> assign(:user, user) - |> assign(:token, token) - |> get("/api/pleroma/admin/reports") - - assert json_response(conn, :forbidden) == - %{"error" => "User is not an admin."} - end - - test "returns 403 when requested by anonymous" do - conn = get(build_conn(), "/api/pleroma/admin/reports") - - assert json_response(conn, :forbidden) == %{ - "error" => "Invalid credentials." - } - end - end - - describe "POST /api/pleroma/admin/reports/:id/notes" do - setup %{conn: conn, admin: admin} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ - content: "this is disgusting!" - }) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ - content: "this is disgusting2!" - }) - - %{ - admin_id: admin.id, - report_id: report_id - } - end - - test "it creates report note", %{admin_id: admin_id, report_id: report_id} do - assert [note, _] = Repo.all(ReportNote) - - assert %{ - activity_id: ^report_id, - content: "this is disgusting!", - user_id: ^admin_id - } = note - end - - test "it returns reports with notes", %{conn: conn, admin: admin} do - conn = get(conn, "/api/pleroma/admin/reports") - - response = json_response_and_validate_schema(conn, 200) - notes = hd(response["reports"])["notes"] - [note, _] = notes - - assert note["user"]["nickname"] == admin.nickname - assert note["content"] == "this is disgusting!" - assert note["created_at"] - assert response["total"] == 1 - end - - test "it deletes the note", %{conn: conn, report_id: report_id} do - assert ReportNote |> Repo.all() |> length() == 2 - assert [note, _] = Repo.all(ReportNote) - - delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}") - - assert ReportNote |> Repo.all() |> length() == 1 - end - end -end diff --git a/test/web/admin_api/controllers/status_controller_test.exs b/test/web/admin_api/controllers/status_controller_test.exs deleted file mode 100644 index eff78fb0a..000000000 --- a/test/web/admin_api/controllers/status_controller_test.exs +++ /dev/null @@ -1,202 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.StatusControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.ModerationLog - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - {:ok, %{admin: admin, token: token, conn: conn}} - end - - describe "GET /api/pleroma/admin/statuses/:id" do - test "not found", %{conn: conn} do - assert conn - |> get("/api/pleroma/admin/statuses/not_found") - |> json_response_and_validate_schema(:not_found) - end - - test "shows activity", %{conn: conn} do - activity = insert(:note_activity) - - response = - conn - |> get("/api/pleroma/admin/statuses/#{activity.id}") - |> json_response_and_validate_schema(200) - - assert response["id"] == activity.id - - account = response["account"] - actor = User.get_by_ap_id(activity.actor) - - assert account["id"] == actor.id - assert account["nickname"] == actor.nickname - assert account["deactivated"] == actor.deactivated - assert account["confirmation_pending"] == actor.confirmation_pending - end - end - - describe "PUT /api/pleroma/admin/statuses/:id" do - setup do - activity = insert(:note_activity) - - %{id: activity.id} - end - - test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do - response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"}) - |> json_response_and_validate_schema(:ok) - - assert response["sensitive"] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'" - - response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"}) - |> json_response_and_validate_schema(:ok) - - refute response["sensitive"] - end - - test "change visibility flag", %{conn: conn, id: id, admin: admin} do - response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "public"}) - |> json_response_and_validate_schema(:ok) - - assert response["visibility"] == "public" - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} updated status ##{id}, set visibility: 'public'" - - response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "private"}) - |> json_response_and_validate_schema(:ok) - - assert response["visibility"] == "private" - - response = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"}) - |> json_response_and_validate_schema(:ok) - - assert response["visibility"] == "unlisted" - end - - test "returns 400 when visibility is unknown", %{conn: conn, id: id} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "test"}) - - assert %{"error" => "test - Invalid value for enum."} = - json_response_and_validate_schema(conn, :bad_request) - end - end - - describe "DELETE /api/pleroma/admin/statuses/:id" do - setup do - activity = insert(:note_activity) - - %{id: activity.id} - end - - test "deletes status", %{conn: conn, id: id, admin: admin} do - conn - |> delete("/api/pleroma/admin/statuses/#{id}") - |> json_response_and_validate_schema(:ok) - - refute Activity.get_by_id(id) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted status ##{id}" - end - - test "returns 404 when the status does not exist", %{conn: conn} do - conn = delete(conn, "/api/pleroma/admin/statuses/test") - - assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} - end - end - - describe "GET /api/pleroma/admin/statuses" do - test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do - blocked = insert(:user) - user = insert(:user) - User.block(admin, blocked) - - {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"}) - - {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"}) - {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"}) - {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - {:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"}) - - response = - conn - |> get("/api/pleroma/admin/statuses") - |> json_response_and_validate_schema(200) - - refute "private" in Enum.map(response, & &1["visibility"]) - assert length(response) == 3 - end - - test "returns only local statuses with local_only on", %{conn: conn} do - user = insert(:user) - remote_user = insert(:user, local: false, nickname: "archaeme@archae.me") - insert(:note_activity, user: user, local: true) - insert(:note_activity, user: remote_user, local: false) - - response = - conn - |> get("/api/pleroma/admin/statuses?local_only=true") - |> json_response_and_validate_schema(200) - - assert length(response) == 1 - end - - test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do - user = insert(:user) - - {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"}) - - {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"}) - {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - conn = get(conn, "/api/pleroma/admin/statuses?godmode=true") - assert json_response_and_validate_schema(conn, 200) |> length() == 3 - end - end -end diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs deleted file mode 100644 index e0e3d4153..000000000 --- a/test/web/admin_api/search_test.exs +++ /dev/null @@ -1,170 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.SearchTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.AdminAPI.Search - - import Pleroma.Factory - - describe "search for admin" do - test "it ignores case" do - insert(:user, nickname: "papercoach") - insert(:user, nickname: "CanadaPaperCoach") - - {:ok, _results, count} = - Search.user(%{ - query: "paper", - local: false, - page: 1, - page_size: 50 - }) - - assert count == 2 - end - - test "it returns local/external users" do - insert(:user, local: true) - insert(:user, local: false) - insert(:user, local: false) - - {:ok, _results, local_count} = - Search.user(%{ - query: "", - local: true - }) - - {:ok, _results, external_count} = - Search.user(%{ - query: "", - external: true - }) - - assert local_count == 1 - assert external_count == 2 - end - - test "it returns active/deactivated users" do - insert(:user, deactivated: true) - insert(:user, deactivated: true) - insert(:user, deactivated: false) - - {:ok, _results, active_count} = - Search.user(%{ - query: "", - active: true - }) - - {:ok, _results, deactivated_count} = - Search.user(%{ - query: "", - deactivated: true - }) - - assert active_count == 1 - assert deactivated_count == 2 - end - - test "it returns specific user" do - insert(:user) - insert(:user) - user = insert(:user, nickname: "bob", local: true, deactivated: false) - - {:ok, _results, total_count} = Search.user(%{query: ""}) - - {:ok, [^user], count} = - Search.user(%{ - query: "Bo", - active: true, - local: true - }) - - assert total_count == 3 - assert count == 1 - end - - test "it returns user by domain" do - insert(:user) - insert(:user) - user = insert(:user, nickname: "some@domain.com") - - {:ok, _results, total} = Search.user() - {:ok, [^user], count} = Search.user(%{query: "domain.com"}) - assert total == 3 - assert count == 1 - end - - test "it return user by full nickname" do - insert(:user) - insert(:user) - user = insert(:user, nickname: "some@domain.com") - - {:ok, _results, total} = Search.user() - {:ok, [^user], count} = Search.user(%{query: "some@domain.com"}) - assert total == 3 - assert count == 1 - end - - test "it returns admin user" do - admin = insert(:user, is_admin: true) - insert(:user) - insert(:user) - - {:ok, _results, total} = Search.user() - {:ok, [^admin], count} = Search.user(%{is_admin: true}) - assert total == 3 - assert count == 1 - end - - test "it returns moderator user" do - moderator = insert(:user, is_moderator: true) - insert(:user) - insert(:user) - - {:ok, _results, total} = Search.user() - {:ok, [^moderator], count} = Search.user(%{is_moderator: true}) - assert total == 3 - assert count == 1 - end - - test "it returns users with tags" do - user1 = insert(:user, tags: ["first"]) - user2 = insert(:user, tags: ["second"]) - insert(:user) - insert(:user) - - {:ok, _results, total} = Search.user() - {:ok, users, count} = Search.user(%{tags: ["first", "second"]}) - assert total == 4 - assert count == 2 - assert user1 in users - assert user2 in users - end - - test "it returns user by display name" do - user = insert(:user, name: "Display name") - insert(:user) - insert(:user) - - {:ok, _results, total} = Search.user() - {:ok, [^user], count} = Search.user(%{name: "display"}) - - assert total == 3 - assert count == 1 - end - - test "it returns user by email" do - user = insert(:user, email: "some@example.com") - insert(:user) - insert(:user) - - {:ok, _results, total} = Search.user() - {:ok, [^user], count} = Search.user(%{email: "some@example.com"}) - - assert total == 3 - assert count == 1 - 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 deleted file mode 100644 index 5a02292be..000000000 --- a/test/web/admin_api/views/report_view_test.exs +++ /dev/null @@ -1,146 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 - alias Pleroma.Web.AdminAPI.Report - alias Pleroma.Web.AdminAPI.ReportView - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI - 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( - MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true}), - AdminAPI.AccountView.render("show.json", %{user: user}) - ), - account: - Map.merge( - MastodonAPI.AccountView.render("show.json", %{ - user: other_user, - skip_visibility_check: true - }), - AdminAPI.AccountView.render("show.json", %{user: other_user}) - ), - statuses: [], - notes: [], - state: "open", - id: activity.id - } - - result = - ReportView.render("show.json", Report.extract_report_info(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]}) - - other_user = Pleroma.User.get_by_id(other_user.id) - - expected = %{ - content: nil, - actor: - Map.merge( - MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true}), - AdminAPI.AccountView.render("show.json", %{user: user}) - ), - account: - Map.merge( - MastodonAPI.AccountView.render("show.json", %{ - user: other_user, - skip_visibility_check: true - }), - AdminAPI.AccountView.render("show.json", %{user: other_user}) - ), - statuses: [StatusView.render("show.json", %{activity: activity})], - state: "open", - notes: [], - id: report_activity.id - } - - result = - ReportView.render("show.json", Report.extract_report_info(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.extract_report_info(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.extract_report_info(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.extract_report_info(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.extract_report_info(activity)) - end -end diff --git a/test/web/api_spec/schema_examples_test.exs b/test/web/api_spec/schema_examples_test.exs deleted file mode 100644 index f00e834fc..000000000 --- a/test/web/api_spec/schema_examples_test.exs +++ /dev/null @@ -1,43 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do - use ExUnit.Case, async: true - import Pleroma.Tests.ApiSpecHelpers - - @content_type "application/json" - - for operation <- api_operations() do - describe operation.operationId <> " Request Body" do - if operation.requestBody do - @media_type operation.requestBody.content[@content_type] - @schema resolve_schema(@media_type.schema) - - if @media_type.example do - test "request body media type example matches schema" do - assert_schema(@media_type.example, @schema) - end - end - - if @schema.example do - test "request body schema example matches schema" do - assert_schema(@schema.example, @schema) - end - end - end - end - - for {status, response} <- operation.responses, is_map(response.content[@content_type]) do - describe "#{operation.operationId} - #{status} Response" do - @schema resolve_schema(response.content[@content_type].schema) - - if @schema.example do - test "example matches schema" do - assert_schema(@schema.example, @schema) - end - end - end - end - end -end diff --git a/test/web/auth/auth_test_controller_test.exs b/test/web/auth/auth_test_controller_test.exs deleted file mode 100644 index fed52b7f3..000000000 --- a/test/web/auth/auth_test_controller_test.exs +++ /dev/null @@ -1,242 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Tests.AuthTestControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - describe "do_oauth_check" do - test "serves with proper OAuth token (fulfilling requested scopes)" do - %{conn: good_token_conn, user: user} = oauth_access(["read"]) - - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/authenticated_api/do_oauth_check") - |> json_response(200) - - # Unintended usage (:api) — use with :authenticated_api instead - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/api/do_oauth_check") - |> json_response(200) - end - - test "fails on no token / missing scope(s)" do - %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"]) - - bad_token_conn - |> get("/test/authenticated_api/do_oauth_check") - |> json_response(403) - - bad_token_conn - |> assign(:token, nil) - |> get("/test/api/do_oauth_check") - |> json_response(403) - end - end - - describe "fallback_oauth_check" do - test "serves with proper OAuth token (fulfilling requested scopes)" do - %{conn: good_token_conn, user: user} = oauth_access(["read"]) - - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/api/fallback_oauth_check") - |> json_response(200) - - # Unintended usage (:authenticated_api) — use with :api instead - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/authenticated_api/fallback_oauth_check") - |> json_response(200) - end - - test "for :api on public instance, drops :user and renders on no token / missing scope(s)" do - clear_config([:instance, :public], true) - - %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"]) - - assert %{"user_id" => nil} == - bad_token_conn - |> get("/test/api/fallback_oauth_check") - |> json_response(200) - - assert %{"user_id" => nil} == - bad_token_conn - |> assign(:token, nil) - |> get("/test/api/fallback_oauth_check") - |> json_response(200) - end - - test "for :api on private instance, fails on no token / missing scope(s)" do - clear_config([:instance, :public], false) - - %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"]) - - bad_token_conn - |> get("/test/api/fallback_oauth_check") - |> json_response(403) - - bad_token_conn - |> assign(:token, nil) - |> get("/test/api/fallback_oauth_check") - |> json_response(403) - end - end - - describe "skip_oauth_check" do - test "for :authenticated_api, serves if :user is set (regardless of token / token scopes)" do - user = insert(:user) - - assert %{"user_id" => user.id} == - build_conn() - |> assign(:user, user) - |> get("/test/authenticated_api/skip_oauth_check") - |> json_response(200) - - %{conn: bad_token_conn, user: user} = oauth_access(["irrelevant_scope"]) - - assert %{"user_id" => user.id} == - bad_token_conn - |> get("/test/authenticated_api/skip_oauth_check") - |> json_response(200) - end - - test "serves via :api on public instance if :user is not set" do - clear_config([:instance, :public], true) - - assert %{"user_id" => nil} == - build_conn() - |> get("/test/api/skip_oauth_check") - |> json_response(200) - - build_conn() - |> get("/test/authenticated_api/skip_oauth_check") - |> json_response(403) - end - - test "fails on private instance if :user is not set" do - clear_config([:instance, :public], false) - - build_conn() - |> get("/test/api/skip_oauth_check") - |> json_response(403) - - build_conn() - |> get("/test/authenticated_api/skip_oauth_check") - |> json_response(403) - end - end - - describe "fallback_oauth_skip_publicity_check" do - test "serves with proper OAuth token (fulfilling requested scopes)" do - %{conn: good_token_conn, user: user} = oauth_access(["read"]) - - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/api/fallback_oauth_skip_publicity_check") - |> json_response(200) - - # Unintended usage (:authenticated_api) - assert %{"user_id" => user.id} == - good_token_conn - |> get("/test/authenticated_api/fallback_oauth_skip_publicity_check") - |> json_response(200) - end - - test "for :api on private / public instance, drops :user and renders on token issue" do - %{conn: bad_token_conn} = oauth_access(["irrelevant_scope"]) - - for is_public <- [true, false] do - clear_config([:instance, :public], is_public) - - assert %{"user_id" => nil} == - bad_token_conn - |> get("/test/api/fallback_oauth_skip_publicity_check") - |> json_response(200) - - assert %{"user_id" => nil} == - bad_token_conn - |> assign(:token, nil) - |> get("/test/api/fallback_oauth_skip_publicity_check") - |> json_response(200) - end - end - end - - describe "skip_oauth_skip_publicity_check" do - test "for :authenticated_api, serves if :user is set (regardless of token / token scopes)" do - user = insert(:user) - - assert %{"user_id" => user.id} == - build_conn() - |> assign(:user, user) - |> get("/test/authenticated_api/skip_oauth_skip_publicity_check") - |> json_response(200) - - %{conn: bad_token_conn, user: user} = oauth_access(["irrelevant_scope"]) - - assert %{"user_id" => user.id} == - bad_token_conn - |> get("/test/authenticated_api/skip_oauth_skip_publicity_check") - |> json_response(200) - end - - test "for :api, serves on private and public instances regardless of whether :user is set" do - user = insert(:user) - - for is_public <- [true, false] do - clear_config([:instance, :public], is_public) - - assert %{"user_id" => nil} == - build_conn() - |> get("/test/api/skip_oauth_skip_publicity_check") - |> json_response(200) - - assert %{"user_id" => user.id} == - build_conn() - |> assign(:user, user) - |> get("/test/api/skip_oauth_skip_publicity_check") - |> json_response(200) - end - end - end - - describe "missing_oauth_check_definition" do - def test_missing_oauth_check_definition_failure(endpoint, expected_error) do - %{conn: conn} = oauth_access(["read", "write", "follow", "push", "admin"]) - - assert %{"error" => expected_error} == - conn - |> get(endpoint) - |> json_response(403) - end - - test "fails if served via :authenticated_api" do - test_missing_oauth_check_definition_failure( - "/test/authenticated_api/missing_oauth_check_definition", - "Security violation: OAuth scopes check was neither handled nor explicitly skipped." - ) - end - - test "fails if served via :api and the instance is private" do - clear_config([:instance, :public], false) - - test_missing_oauth_check_definition_failure( - "/test/api/missing_oauth_check_definition", - "This resource requires authentication." - ) - end - - test "succeeds with dropped :user if served via :api on public instance" do - %{conn: conn} = oauth_access(["read", "write", "follow", "push", "admin"]) - - assert %{"user_id" => nil} == - conn - |> get("/test/api/missing_oauth_check_definition") - |> json_response(200) - end - end -end diff --git a/test/web/auth/authenticator_test.exs b/test/web/auth/authenticator_test.exs deleted file mode 100644 index d54253343..000000000 --- a/test/web/auth/authenticator_test.exs +++ /dev/null @@ -1,42 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Auth.AuthenticatorTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.Auth.Authenticator - import Pleroma.Factory - - describe "fetch_user/1" do - test "returns user by name" do - user = insert(:user) - assert Authenticator.fetch_user(user.nickname) == user - end - - test "returns user by email" do - user = insert(:user) - assert Authenticator.fetch_user(user.email) == user - end - - test "returns nil" do - assert Authenticator.fetch_user("email") == nil - end - end - - describe "fetch_credentials/1" do - test "returns name and password from authorization params" do - params = %{"authorization" => %{"name" => "test", "password" => "test-pass"}} - assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}} - end - - test "returns name and password with grant_type 'password'" do - params = %{"grant_type" => "password", "username" => "test", "password" => "test-pass"} - assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}} - end - - test "returns error" do - assert Authenticator.fetch_credentials(%{}) == {:error, :invalid_credentials} - end - end -end diff --git a/test/web/auth/basic_auth_test.exs b/test/web/auth/basic_auth_test.exs deleted file mode 100644 index bf6e3d2fc..000000000 --- a/test/web/auth/basic_auth_test.exs +++ /dev/null @@ -1,46 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Auth.BasicAuthTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - test "with HTTP Basic Auth used, grants access to OAuth scope-restricted endpoints", %{ - conn: conn - } do - user = insert(:user) - assert Pbkdf2.verify_pass("test", user.password_hash) - - basic_auth_contents = - (URI.encode_www_form(user.nickname) <> ":" <> URI.encode_www_form("test")) - |> Base.encode64() - - # Succeeds with HTTP Basic Auth - response = - conn - |> put_req_header("authorization", "Basic " <> basic_auth_contents) - |> get("/api/v1/accounts/verify_credentials") - |> json_response(200) - - user_nickname = user.nickname - assert %{"username" => ^user_nickname} = response - - # Succeeds with a properly scoped OAuth token - valid_token = insert(:oauth_token, scopes: ["read:accounts"]) - - conn - |> put_req_header("authorization", "Bearer #{valid_token.token}") - |> get("/api/v1/accounts/verify_credentials") - |> json_response(200) - - # Fails with a wrong-scoped OAuth token (proof of restriction) - invalid_token = insert(:oauth_token, scopes: ["read:something"]) - - conn - |> put_req_header("authorization", "Bearer #{invalid_token.token}") - |> get("/api/v1/accounts/verify_credentials") - |> json_response(403) - end -end diff --git a/test/web/auth/pleroma_authenticator_test.exs b/test/web/auth/pleroma_authenticator_test.exs deleted file mode 100644 index 1ba0dfecc..000000000 --- a/test/web/auth/pleroma_authenticator_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.Auth.PleromaAuthenticator - import Pleroma.Factory - - setup do - password = "testpassword" - name = "AgentSmith" - user = insert(:user, nickname: name, password_hash: Pbkdf2.hash_pwd_salt(password)) - {:ok, [user: user, name: name, password: password]} - end - - test "get_user/authorization", %{name: name, password: password} do - name = name <> "1" - user = insert(:user, nickname: name, password_hash: Bcrypt.hash_pwd_salt(password)) - - params = %{"authorization" => %{"name" => name, "password" => password}} - res = PleromaAuthenticator.get_user(%Plug.Conn{params: params}) - - assert {:ok, returned_user} = res - assert returned_user.id == user.id - assert "$pbkdf2" <> _ = returned_user.password_hash - end - - test "get_user/authorization with invalid password", %{name: name} do - params = %{"authorization" => %{"name" => name, "password" => "password"}} - res = PleromaAuthenticator.get_user(%Plug.Conn{params: params}) - - assert {:error, {:checkpw, false}} == res - end - - test "get_user/grant_type_password", %{user: user, name: name, password: password} do - params = %{"grant_type" => "password", "username" => name, "password" => password} - res = PleromaAuthenticator.get_user(%Plug.Conn{params: params}) - - assert {:ok, user} == res - end - - test "error credintails" do - res = PleromaAuthenticator.get_user(%Plug.Conn{params: %{}}) - assert {:error, :invalid_credentials} == res - end -end diff --git a/test/web/auth/totp_authenticator_test.exs b/test/web/auth/totp_authenticator_test.exs deleted file mode 100644 index 84d4cd840..000000000 --- a/test/web/auth/totp_authenticator_test.exs +++ /dev/null @@ -1,51 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do - use Pleroma.Web.ConnCase - - alias Pleroma.MFA - alias Pleroma.MFA.BackupCodes - alias Pleroma.MFA.TOTP - alias Pleroma.Web.Auth.TOTPAuthenticator - - import Pleroma.Factory - - test "verify token" do - otp_secret = TOTP.generate_secret() - otp_token = TOTP.generate_token(otp_secret) - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - assert TOTPAuthenticator.verify(otp_token, user) == {:ok, :pass} - assert TOTPAuthenticator.verify(nil, user) == {:error, :invalid_token} - assert TOTPAuthenticator.verify("", user) == {:error, :invalid_token} - end - - test "checks backup codes" do - [code | _] = backup_codes = BackupCodes.generate() - - hashed_codes = - backup_codes - |> Enum.map(&Pbkdf2.hash_pwd_salt(&1)) - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - backup_codes: hashed_codes, - totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true} - } - ) - - assert TOTPAuthenticator.verify_recovery_code(user, code) == {:ok, :pass} - refute TOTPAuthenticator.verify_recovery_code(code, refresh_record(user)) == {:ok, :pass} - end -end diff --git a/test/web/chat_channel_test.exs b/test/web/chat_channel_test.exs deleted file mode 100644 index f18f3a212..000000000 --- a/test/web/chat_channel_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Pleroma.Web.ChatChannelTest do - use Pleroma.Web.ChannelCase - alias Pleroma.Web.ChatChannel - alias Pleroma.Web.UserSocket - - import Pleroma.Factory - - setup do - user = insert(:user) - - {:ok, _, socket} = - socket(UserSocket, "", %{user_name: user.nickname}) - |> subscribe_and_join(ChatChannel, "chat:public") - - {:ok, socket: socket} - end - - test "it broadcasts a message", %{socket: socket} do - push(socket, "new_msg", %{"text" => "why is tenshi eating a corndog so cute?"}) - assert_broadcast("new_msg", %{text: "why is tenshi eating a corndog so cute?"}) - end - - describe "message lengths" do - setup do: clear_config([:instance, :chat_limit]) - - test "it ignores messages of length zero", %{socket: socket} do - push(socket, "new_msg", %{"text" => ""}) - refute_broadcast("new_msg", %{text: ""}) - end - - test "it ignores messages above a certain length", %{socket: socket} do - Pleroma.Config.put([:instance, :chat_limit], 2) - push(socket, "new_msg", %{"text" => "123"}) - refute_broadcast("new_msg", %{text: "123"}) - end - end -end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs deleted file mode 100644 index 313dda21b..000000000 --- a/test/web/common_api/common_api_test.exs +++ /dev/null @@ -1,1124 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.CommonAPITest do - use Pleroma.DataCase - alias Pleroma.Activity - alias Pleroma.Chat - alias Pleroma.Conversation.Participation - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.ActivityPub.Visibility - alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - import Mock - - require Pleroma.Constants - - setup do: clear_config([:instance, :safe_dm_mentions]) - setup do: clear_config([:instance, :limit]) - setup do: clear_config([:instance, :max_pinned_statuses]) - - describe "blocking" do - setup do - blocker = insert(:user) - blocked = insert(:user) - User.follow(blocker, blocked) - User.follow(blocked, blocker) - %{blocker: blocker, blocked: blocked} - end - - test "it blocks and federates", %{blocker: blocker, blocked: blocked} do - clear_config([:instance, :federating], true) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - assert {:ok, block} = CommonAPI.block(blocker, blocked) - - assert block.local - assert User.blocks?(blocker, blocked) - refute User.following?(blocker, blocked) - refute User.following?(blocked, blocker) - - assert called(Pleroma.Web.Federator.publish(block)) - end - end - - test "it blocks and does not federate if outgoing blocks are disabled", %{ - blocker: blocker, - blocked: blocked - } do - clear_config([:instance, :federating], true) - clear_config([:activitypub, :outgoing_blocks], false) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - assert {:ok, block} = CommonAPI.block(blocker, blocked) - - assert block.local - assert User.blocks?(blocker, blocked) - refute User.following?(blocker, blocked) - refute User.following?(blocked, blocker) - - refute called(Pleroma.Web.Federator.publish(block)) - end - end - end - - describe "posting chat messages" do - setup do: clear_config([:instance, :chat_limit]) - - test "it posts a chat message without content but with an attachment" do - author = insert(:user) - recipient = insert(:user) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: author.ap_id) - - with_mocks([ - { - Pleroma.Web.Streamer, - [], - [ - stream: fn _, _ -> - nil - end - ] - }, - { - Pleroma.Web.Push, - [], - [ - send: fn _ -> nil end - ] - } - ]) do - {:ok, activity} = - CommonAPI.post_chat_message( - author, - recipient, - nil, - media_id: upload.id - ) - - notification = - Notification.for_user_and_activity(recipient, activity) - |> Repo.preload(:activity) - - assert called(Pleroma.Web.Push.send(notification)) - assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) - assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) - - assert activity - end - end - - test "it adds html newlines" do - author = insert(:user) - recipient = insert(:user) - - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post_chat_message( - author, - recipient, - "uguu\nuguuu" - ) - - assert other_user.ap_id not in activity.recipients - - object = Object.normalize(activity, false) - - assert object.data["content"] == "uguu<br/>uguuu" - end - - test "it linkifies" do - author = insert(:user) - recipient = insert(:user) - - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post_chat_message( - author, - recipient, - "https://example.org is the site of @#{other_user.nickname} #2hu" - ) - - assert other_user.ap_id not in activity.recipients - - object = Object.normalize(activity, false) - - assert object.data["content"] == - "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{ - other_user.id - }\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>" - end - - test "it posts a chat message" do - author = insert(:user) - recipient = insert(:user) - - {:ok, activity} = - CommonAPI.post_chat_message( - author, - recipient, - "a test message <script>alert('uuu')</script> :firefox:" - ) - - assert activity.data["type"] == "Create" - assert activity.local - object = Object.normalize(activity) - - assert object.data["type"] == "ChatMessage" - assert object.data["to"] == [recipient.ap_id] - - assert object.data["content"] == - "a test message <script>alert('uuu')</script> :firefox:" - - assert object.data["emoji"] == %{ - "firefox" => "http://localhost:4001/emoji/Firefox.gif" - } - - assert Chat.get(author.id, recipient.ap_id) - assert Chat.get(recipient.id, author.ap_id) - - assert :ok == Pleroma.Web.Federator.perform(:publish, activity) - end - - test "it reject messages over the local limit" do - Pleroma.Config.put([:instance, :chat_limit], 2) - - author = insert(:user) - recipient = insert(:user) - - {:error, message} = - CommonAPI.post_chat_message( - author, - recipient, - "123" - ) - - assert message == :content_too_long - end - end - - describe "unblocking" do - test "it works even without an existing block activity" do - blocked = insert(:user) - blocker = insert(:user) - User.block(blocker, blocked) - - assert User.blocks?(blocker, blocked) - assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked) - refute User.blocks?(blocker, blocked) - end - end - - describe "deletion" do - test "it works with pruned objects" do - user = insert(:user) - - {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - - clear_config([:instance, :federating], true) - - Object.normalize(post, false) - |> Object.prune() - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - assert {:ok, delete} = CommonAPI.delete(post.id, user) - assert delete.local - assert called(Pleroma.Web.Federator.publish(delete)) - end - - refute Activity.get_by_id(post.id) - end - - test "it allows users to delete their posts" do - user = insert(:user) - - {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - - clear_config([:instance, :federating], true) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - assert {:ok, delete} = CommonAPI.delete(post.id, user) - assert delete.local - assert called(Pleroma.Web.Federator.publish(delete)) - end - - refute Activity.get_by_id(post.id) - end - - test "it does not allow a user to delete their posts" do - user = insert(:user) - other_user = insert(:user) - - {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - - assert {:error, "Could not delete"} = CommonAPI.delete(post.id, other_user) - assert Activity.get_by_id(post.id) - end - - test "it allows moderators to delete other user's posts" do - user = insert(:user) - moderator = insert(:user, is_moderator: true) - - {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - - assert {:ok, delete} = CommonAPI.delete(post.id, moderator) - assert delete.local - - refute Activity.get_by_id(post.id) - end - - test "it allows admins to delete other user's posts" do - user = insert(:user) - moderator = insert(:user, is_admin: true) - - {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - - assert {:ok, delete} = CommonAPI.delete(post.id, moderator) - assert delete.local - - refute Activity.get_by_id(post.id) - end - - test "superusers deleting non-local posts won't federate the delete" do - # This is the user of the ingested activity - _user = - insert(:user, - local: false, - ap_id: "http://mastodon.example.org/users/admin", - last_refreshed_at: NaiveDateTime.utc_now() - ) - - moderator = insert(:user, is_admin: true) - - data = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Jason.decode!() - - {:ok, post} = Transmogrifier.handle_incoming(data) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - assert {:ok, delete} = CommonAPI.delete(post.id, moderator) - assert delete.local - refute called(Pleroma.Web.Federator.publish(:_)) - end - - refute Activity.get_by_id(post.id) - end - end - - test "favoriting race condition" do - user = insert(:user) - users_serial = insert_list(10, :user) - users = insert_list(10, :user) - - {:ok, activity} = CommonAPI.post(user, %{status: "."}) - - users_serial - |> Enum.map(fn user -> - CommonAPI.favorite(user, activity.id) - end) - - object = Object.get_by_ap_id(activity.data["object"]) - assert object.data["like_count"] == 10 - - users - |> Enum.map(fn user -> - Task.async(fn -> - CommonAPI.favorite(user, activity.id) - end) - end) - |> Enum.map(&Task.await/1) - - object = Object.get_by_ap_id(activity.data["object"]) - assert object.data["like_count"] == 20 - end - - test "repeating race condition" do - user = insert(:user) - users_serial = insert_list(10, :user) - users = insert_list(10, :user) - - {:ok, activity} = CommonAPI.post(user, %{status: "."}) - - users_serial - |> Enum.map(fn user -> - CommonAPI.repeat(activity.id, user) - end) - - object = Object.get_by_ap_id(activity.data["object"]) - assert object.data["announcement_count"] == 10 - - users - |> Enum.map(fn user -> - Task.async(fn -> - CommonAPI.repeat(activity.id, user) - end) - end) - |> Enum.map(&Task.await/1) - - object = Object.get_by_ap_id(activity.data["object"]) - assert object.data["announcement_count"] == 20 - end - - test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - [participation] = Participation.for_user(user) - - {:ok, convo_reply} = - CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id}) - - assert Visibility.is_direct?(convo_reply) - - assert activity.data["context"] == convo_reply.data["context"] - end - - test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do - har = insert(:user) - jafnhar = insert(:user) - tridi = insert(:user) - - {:ok, activity} = - CommonAPI.post(har, %{ - status: "@#{jafnhar.nickname} hey", - visibility: "direct" - }) - - assert har.ap_id in activity.recipients - assert jafnhar.ap_id in activity.recipients - - [participation] = Participation.for_user(har) - - {:ok, activity} = - CommonAPI.post(har, %{ - status: "I don't really like @#{tridi.nickname}", - visibility: "direct", - in_reply_to_status_id: activity.id, - in_reply_to_conversation_id: participation.id - }) - - assert har.ap_id in activity.recipients - assert jafnhar.ap_id in activity.recipients - refute tridi.ap_id in activity.recipients - end - - test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do - har = insert(:user) - jafnhar = insert(:user) - tridi = insert(:user) - - Pleroma.Config.put([:instance, :safe_dm_mentions], true) - - {:ok, activity} = - CommonAPI.post(har, %{ - status: "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again", - visibility: "direct" - }) - - refute tridi.ap_id in activity.recipients - assert jafnhar.ap_id in activity.recipients - end - - test "it de-duplicates tags" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"}) - - object = Object.normalize(activity) - - assert object.data["tag"] == ["2hu"] - end - - test "it adds emoji in the object" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"}) - - assert Object.normalize(activity).data["emoji"]["firefox"] - 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) - - post = "<p><b>2hu</b></p><script>alert('xss')</script>" - - {:ok, activity} = - CommonAPI.post(user, %{ - status: post, - content_type: "text/html" - }) - - object = Object.normalize(activity) - - assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" - assert object.data["source"] == post - end - - test "it filters out obviously bad tags when accepting a post as Markdown" do - user = insert(:user) - - post = "<p><b>2hu</b></p><script>alert('xss')</script>" - - {:ok, activity} = - CommonAPI.post(user, %{ - status: post, - content_type: "text/markdown" - }) - - object = Object.normalize(activity) - - assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" - assert object.data["source"] == post - end - - test "it does not allow replies to direct messages that are not direct messages themselves" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "suya..", visibility: "direct"}) - - assert {:ok, _} = - CommonAPI.post(user, %{ - status: "suya..", - visibility: "direct", - in_reply_to_status_id: activity.id - }) - - Enum.each(["public", "private", "unlisted"], fn visibility -> - assert {:error, "The message visibility must be direct"} = - CommonAPI.post(user, %{ - status: "suya..", - visibility: visibility, - in_reply_to_status_id: activity.id - }) - end) - end - - test "replying with a direct message will NOT auto-add the author of the reply to the recipient list" do - user = insert(:user) - other_user = insert(:user) - third_user = insert(:user) - - {:ok, post} = CommonAPI.post(user, %{status: "I'm stupid"}) - - {:ok, open_answer} = - CommonAPI.post(other_user, %{status: "No ur smart", in_reply_to_status_id: post.id}) - - # The OP is implicitly added - assert user.ap_id in open_answer.recipients - - {:ok, secret_answer} = - CommonAPI.post(other_user, %{ - status: "lol, that guy really is stupid, right, @#{third_user.nickname}?", - in_reply_to_status_id: post.id, - visibility: "direct" - }) - - assert third_user.ap_id in secret_answer.recipients - - # The OP is not added - refute user.ap_id in secret_answer.recipients - 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 validates character limits are correctly enforced" do - Pleroma.Config.put([:instance, :limit], 5) - - user = insert(:user) - - assert {:error, "The status is over the character limit"} = - CommonAPI.post(user, %{status: "foobar"}) - - assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"}) - end - - test "it can handle activities that expire" do - user = insert(:user) - - expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(1_000_000, :second) - - assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000}) - - assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id) - assert expiration.scheduled_at == expires_at - end - end - - describe "reactions" do - test "reacting to a status with an emoji" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍") - - assert reaction.data["actor"] == user.ap_id - assert reaction.data["content"] == "👍" - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".") - end - - test "unreacting to a status with an emoji" do - user = insert(:user) - other_user = insert(:user) - - clear_config([:instance, :federating], true) - - with_mock Pleroma.Web.Federator, - publish: fn _ -> nil end do - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍") - - {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍") - - assert unreaction.data["type"] == "Undo" - assert unreaction.data["object"] == reaction.data["id"] - assert unreaction.local - - # On federation, it contains the undone (and deleted) object - unreaction_with_object = %{ - unreaction - | data: Map.put(unreaction.data, "object", reaction.data) - } - - assert called(Pleroma.Web.Federator.publish(unreaction_with_object)) - end - end - - test "repeating a status" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user) - assert Visibility.is_public?(announce_activity) - end - - test "can't repeat a repeat" do - user = insert(:user) - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user) - - refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user)) - end - - test "repeating a status privately" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:ok, %Activity{} = announce_activity} = - CommonAPI.repeat(activity.id, user, %{visibility: "private"}) - - assert Visibility.is_private?(announce_activity) - refute Visibility.visible_for_user?(announce_activity, nil) - end - - test "favoriting a status" do - user = insert(:user) - other_user = insert(:user) - - {:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"}) - - {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id) - assert data["type"] == "Like" - assert data["actor"] == user.ap_id - assert data["object"] == post_activity.data["object"] - end - - test "retweeting a status twice returns the status" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user) - {:ok, ^announce} = CommonAPI.repeat(activity.id, user) - end - - test "favoriting a status twice returns ok, but without the like activity" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) - {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id) - assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id) - end - end - - describe "pinned statuses" do - setup do - Pleroma.Config.put([:instance, :max_pinned_statuses], 1) - - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"}) - - [user: user, activity: activity] - end - - test "pin status", %{user: user, activity: activity} do - assert {:ok, ^activity} = CommonAPI.pin(activity.id, user) - - id = activity.id - user = refresh_record(user) - - assert %User{pinned_activities: [^id]} = user - end - - test "pin poll", %{user: user} do - {:ok, activity} = - CommonAPI.post(user, %{ - status: "How is fediverse today?", - poll: %{options: ["Absolutely outstanding", "Not good"], expires_in: 20} - }) - - assert {:ok, ^activity} = CommonAPI.pin(activity.id, user) - - id = activity.id - user = refresh_record(user) - - assert %User{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) - - assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user) - end - - test "max pinned statuses", %{user: user, activity: activity_one} do - {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"}) - - assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user) - - user = refresh_record(user) - - assert {:error, "You have already pinned the maximum number of statuses"} = - CommonAPI.pin(activity_two.id, user) - end - - test "unpin status", %{user: user, activity: activity} do - {:ok, activity} = CommonAPI.pin(activity.id, user) - - user = refresh_record(user) - - id = activity.id - - assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user)) - - user = refresh_record(user) - - assert %User{pinned_activities: []} = user - end - - test "should unpin when deleting a status", %{user: user, activity: activity} do - {:ok, activity} = CommonAPI.pin(activity.id, user) - - user = refresh_record(user) - - assert {:ok, _} = CommonAPI.delete(activity.id, user) - - user = refresh_record(user) - - assert %User{pinned_activities: []} = user - end - end - - describe "mute tests" do - setup do - user = insert(:user) - - activity = insert(:note_activity) - - [user: user, activity: activity] - end - - test "add mute", %{user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - assert CommonAPI.thread_muted?(user, activity) - end - - test "remove mute", %{user: user, activity: activity} do - CommonAPI.add_mute(user, activity) - {:ok, _} = CommonAPI.remove_mute(user, activity) - refute CommonAPI.thread_muted?(user, activity) - end - - test "check that mutes can't be duplicate", %{user: user, activity: activity} do - CommonAPI.add_mute(user, activity) - {:error, _} = CommonAPI.add_mute(user, activity) - end - end - - describe "reports" do - test "creates a report" do - reporter = insert(:user) - target_user = insert(:user) - - {:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"}) - - reporter_ap_id = reporter.ap_id - target_ap_id = target_user.ap_id - activity_ap_id = activity.data["id"] - comment = "foobar" - - report_data = %{ - account_id: target_user.id, - comment: comment, - status_ids: [activity.id] - } - - note_obj = %{ - "type" => "Note", - "id" => activity_ap_id, - "content" => "foobar", - "published" => activity.object.data["published"], - "actor" => AccountView.render("show.json", %{user: target_user}) - } - - assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data) - - assert %Activity{ - actor: ^reporter_ap_id, - data: %{ - "type" => "Flag", - "content" => ^comment, - "object" => [^target_ap_id, ^note_obj], - "state" => "open" - } - } = flag_activity - end - - test "updates report state" do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %Activity{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - {:ok, report} = CommonAPI.update_report_state(report_id, "resolved") - - assert report.data["state"] == "resolved" - - [reported_user, activity_id] = report.data["object"] - - assert reported_user == target_user.ap_id - assert activity_id == activity.data["id"] - end - - test "does not update report state when state is unsupported" do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %Activity{id: report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"} - end - - test "updates state of multiple reports" do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %Activity{id: first_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel offended", - status_ids: [activity.id] - }) - - {:ok, %Activity{id: second_report_id}} = - CommonAPI.report(reporter, %{ - account_id: target_user.id, - comment: "I feel very offended!", - status_ids: [activity.id] - }) - - {:ok, report_ids} = - CommonAPI.update_report_state([first_report_id, second_report_id], "resolved") - - first_report = Activity.get_by_id(first_report_id) - second_report = Activity.get_by_id(second_report_id) - - assert report_ids -- [first_report_id, second_report_id] == [] - assert first_report.data["state"] == "resolved" - assert second_report.data["state"] == "resolved" - end - end - - describe "reblog muting" do - setup do - muter = insert(:user) - - muted = insert(:user) - - [muter: muter, muted: muted] - end - - test "add a reblog mute", %{muter: muter, muted: muted} do - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted) - - assert User.showing_reblogs?(muter, muted) == false - end - - test "remove a reblog mute", %{muter: muter, muted: muted} do - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted) - {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted) - - assert User.showing_reblogs?(muter, muted) == true - end - end - - describe "follow/2" do - test "directly follows a non-locked local user" do - [follower, followed] = insert_pair(:user) - {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) - - assert User.following?(follower, followed) - 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, _subscription} = User.subscribe(follower, followed) - - assert User.subscribed_to?(follower, followed) - - {:ok, follower} = CommonAPI.unfollow(follower, followed) - - refute User.subscribed_to?(follower, followed) - end - - test "cancels a pending follow for a local user" do - follower = insert(:user) - followed = insert(:user, locked: true) - - assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = - CommonAPI.follow(follower, followed) - - assert User.get_follow_state(follower, followed) == :follow_pending - assert {:ok, follower} = CommonAPI.unfollow(follower, followed) - assert User.get_follow_state(follower, followed) == nil - - assert %{id: ^activity_id, data: %{"state" => "cancelled"}} = - Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed) - - assert %{ - data: %{ - "type" => "Undo", - "object" => %{"type" => "Follow", "state" => "cancelled"} - } - } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower) - end - - test "cancels a pending follow for a remote user" do - follower = insert(:user) - followed = insert(:user, locked: true, local: false, ap_enabled: true) - - assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = - CommonAPI.follow(follower, followed) - - assert User.get_follow_state(follower, followed) == :follow_pending - assert {:ok, follower} = CommonAPI.unfollow(follower, followed) - assert User.get_follow_state(follower, followed) == nil - - assert %{id: ^activity_id, data: %{"state" => "cancelled"}} = - Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed) - - assert %{ - data: %{ - "type" => "Undo", - "object" => %{"type" => "Follow", "state" => "cancelled"} - } - } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower) - 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, locked: true) - follower = insert(:user) - follower_two = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_three} = CommonAPI.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, locked: true) - follower = insert(:user) - follower_two = insert(:user) - - {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) - {:ok, _, _, follow_activity_three} = CommonAPI.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 - - test "doesn't create a following relationship if the corresponding follow request doesn't exist" do - user = insert(:user, locked: true) - not_follower = insert(:user) - CommonAPI.accept_follow_request(not_follower, user) - - assert Pleroma.FollowingRelationship.following?(not_follower, user) == false - 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 - - describe "listen/2" do - test "returns a valid activity" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.listen(user, %{ - title: "lain radio episode 1", - album: "lain radio", - artist: "lain", - length: 180_000 - }) - - object = Object.normalize(activity) - - assert object.data["title"] == "lain radio episode 1" - - assert Visibility.get_visibility(activity) == "public" - end - - test "respects visibility=private" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.listen(user, %{ - title: "lain radio episode 1", - album: "lain radio", - artist: "lain", - length: 180_000, - visibility: "private" - }) - - object = Object.normalize(activity) - - assert object.data["title"] == "lain radio episode 1" - - assert Visibility.get_visibility(activity) == "private" - 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 deleted file mode 100644 index e67c10b93..000000000 --- a/test/web/common_api/common_api_utils_test.exs +++ /dev/null @@ -1,593 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.CommonAPI.UtilsTest do - alias Pleroma.Builders.UserBuilder - alias Pleroma.Object - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.CommonAPI.Utils - use Pleroma.DataCase - - import ExUnit.CaptureLog - import Pleroma.Factory - - @public_address "https://www.w3.org/ns/activitystreams#Public" - - describe "add_attachments/2" do - setup do - name = - "Sakura Mana – Turned on by a Senior OL with a Temptating Tight Skirt-s Full Hipline and Panty Shot- Beautiful Thick Thighs- and Erotic Ass- -2015- -- Oppaitime 8-28-2017 6-50-33 PM.png" - - attachment = %{ - "url" => [%{"href" => URI.encode(name)}] - } - - %{name: name, attachment: attachment} - end - - test "it adds attachment links to a given text and attachment set", %{ - name: name, - attachment: attachment - } do - len = 10 - clear_config([Pleroma.Upload, :filename_display_max_length], len) - - expected = - "<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{String.slice(name, 0..len)}…</a>" - - assert Utils.add_attachments("", [attachment]) == expected - end - - test "doesn't truncate file name if config for truncate is set to 0", %{ - name: name, - attachment: attachment - } do - clear_config([Pleroma.Upload, :filename_display_max_length], 0) - - expected = "<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{name}</a>" - - assert Utils.add_attachments("", [attachment]) == expected - end - end - - describe "it confirms the password given is the current users password" do - test "incorrect password given" do - {:ok, user} = UserBuilder.insert() - - assert Utils.confirm_current_password(user, "") == {:error, "Invalid password."} - end - - test "correct password given" do - {:ok, user} = UserBuilder.insert() - assert Utils.confirm_current_password(user, "test") == {:ok, user} - end - end - - describe "format_input/3" do - test "works for bare text/plain" do - text = "hello world!" - expected = "hello world!" - - {output, [], []} = Utils.format_input(text, "text/plain") - - assert output == expected - - text = "hello world!\n\nsecond paragraph!" - expected = "hello world!<br><br>second paragraph!" - - {output, [], []} = Utils.format_input(text, "text/plain") - - assert output == expected - end - - test "works for bare text/html" do - text = "<p>hello world!</p>" - expected = "<p>hello world!</p>" - - {output, [], []} = Utils.format_input(text, "text/html") - - assert output == expected - - text = "<p>hello world!</p><br/>\n<p>second paragraph</p>" - expected = "<p>hello world!</p><br/>\n<p>second paragraph</p>" - - {output, [], []} = Utils.format_input(text, "text/html") - - assert output == expected - end - - test "works for bare text/markdown" do - text = "**hello world**" - expected = "<p><strong>hello world</strong></p>" - - {output, [], []} = Utils.format_input(text, "text/markdown") - - assert output == expected - - text = "**hello world**\n\n*another paragraph*" - expected = "<p><strong>hello world</strong></p><p><em>another paragraph</em></p>" - - {output, [], []} = Utils.format_input(text, "text/markdown") - - assert output == expected - - text = """ - > cool quote - - by someone - """ - - expected = "<blockquote><p>cool quote</p></blockquote><p>by someone</p>" - - {output, [], []} = Utils.format_input(text, "text/markdown") - - assert output == expected - end - - test "works for bare text/bbcode" do - text = "[b]hello world[/b]" - expected = "<strong>hello world</strong>" - - {output, [], []} = Utils.format_input(text, "text/bbcode") - - assert output == expected - - text = "[b]hello world![/b]\n\nsecond paragraph!" - expected = "<strong>hello world!</strong><br><br>second paragraph!" - - {output, [], []} = Utils.format_input(text, "text/bbcode") - - assert output == expected - - text = "[b]hello world![/b]\n\n<strong>second paragraph!</strong>" - - expected = - "<strong>hello world!</strong><br><br><strong>second paragraph!</strong>" - - {output, [], []} = Utils.format_input(text, "text/bbcode") - - assert output == expected - end - - test "works for text/markdown with mentions" do - {:ok, user} = - UserBuilder.insert(%{nickname: "user__test", ap_id: "http://foo.com/user__test"}) - - text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*" - - {output, _, _} = Utils.format_input(text, "text/markdown") - - assert output == - ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{ - user.id - }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{ - user.id - }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>) - end - end - - describe "context_to_conversation_id" do - test "creates a mapping object" do - conversation_id = Utils.context_to_conversation_id("random context") - object = Object.get_by_ap_id("random context") - - assert conversation_id == object.id - end - - test "returns an existing mapping for an existing object" do - {:ok, object} = Object.context_mapping("random context") |> Repo.insert() - conversation_id = Utils.context_to_conversation_id("random context") - - assert conversation_id == object.id - end - end - - describe "formats date to asctime" do - test "when date is in ISO 8601 format" do - date = DateTime.utc_now() |> DateTime.to_iso8601() - - expected = - date - |> DateTime.from_iso8601() - |> elem(1) - |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y") - - assert Utils.date_to_asctime(date) == expected - end - - test "when date is a binary in wrong format" do - date = DateTime.utc_now() - - 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 - date = DateTime.utc_now() |> DateTime.to_unix() - - 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 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", nil) - - 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", nil) - - 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", nil) - - 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", nil) - - 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", nil) - assert length(to) == 2 - assert Enum.empty?(cc) - - 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", nil) - - assert length(to) == 2 - assert Enum.empty?(cc) - - assert mentioned_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", nil) - - assert length(to) == 1 - assert Enum.empty?(cc) - - 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", nil) - - assert length(to) == 1 - assert Enum.empty?(cc) - - assert mentioned_user.ap_id in to - - {:ok, direct_activity} = CommonAPI.post(third_user, %{status: "uguu", visibility: "direct"}) - - {to, cc} = Utils.get_to_and_cc(user, mentions, direct_activity, "direct", nil) - - assert length(to) == 2 - assert Enum.empty?(cc) - - assert mentioned_user.ap_id in to - assert third_user.ap_id in to - end - end - - describe "to_master_date/1" do - test "removes microseconds from date (NaiveDateTime)" do - assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z" - end - - test "removes microseconds from date (String)" do - assert Utils.to_masto_date("2015-01-23T23:50:07.123Z") == "2015-01-23T23:50:07.000Z" - end - - test "returns empty string when date invalid" do - assert Utils.to_masto_date("2015-01?23T23:50:07.123Z") == "" - end - end - - describe "conversation_id_to_context/1" do - test "returns id" do - object = insert(:note) - assert Utils.conversation_id_to_context(object.id) == object.data["id"] - end - - test "returns error if object not found" do - assert Utils.conversation_id_to_context("123") == {:error, "No such conversation"} - end - end - - describe "maybe_notify_mentioned_recipients/2" do - test "returns recipients when activity is not `Create`" do - activity = insert(:like_activity) - assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == ["test"] - end - - test "returns recipients from tag" do - user = insert(:user) - - object = - insert(:note, - user: user, - data: %{ - "tag" => [ - %{"type" => "Hashtag"}, - "", - %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"}, - %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}, - %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"} - ] - } - ) - - activity = insert(:note_activity, user: user, note: object) - - assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [ - "test", - "https://testing.pleroma.lol/users/lain", - "https://shitposter.club/user/5381" - ] - end - - test "returns recipients when object is map" do - user = insert(:user) - object = insert(:note, user: user) - - activity = - insert(:note_activity, - user: user, - note: object, - data_attrs: %{ - "object" => %{ - "tag" => [ - %{"type" => "Hashtag"}, - "", - %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"}, - %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}, - %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"} - ] - } - } - ) - - Pleroma.Repo.delete(object) - - assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [ - "test", - "https://testing.pleroma.lol/users/lain", - "https://shitposter.club/user/5381" - ] - end - - test "returns recipients when object not found" do - user = insert(:user) - object = insert(:note, user: user) - - activity = insert(:note_activity, user: user, note: object) - Pleroma.Repo.delete(object) - - obj_url = activity.data["object"] - - Tesla.Mock.mock(fn - %{method: :get, url: ^obj_url} -> - %Tesla.Env{status: 404, body: ""} - end) - - assert Utils.maybe_notify_mentioned_recipients(["test-test"], activity) == [ - "test-test" - ] - end - end - - describe "attachments_from_ids_descs/2" do - test "returns [] when attachment ids is empty" do - assert Utils.attachments_from_ids_descs([], "{}") == [] - end - - test "returns list attachments with desc" do - object = insert(:note) - desc = Jason.encode!(%{object.id => "test-desc"}) - - assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [ - Map.merge(object.data, %{"name" => "test-desc"}) - ] - end - end - - describe "attachments_from_ids/1" do - test "returns attachments with descs" do - object = insert(:note) - desc = Jason.encode!(%{object.id => "test-desc"}) - - assert Utils.attachments_from_ids(%{ - media_ids: ["#{object.id}"], - descriptions: desc - }) == [ - Map.merge(object.data, %{"name" => "test-desc"}) - ] - end - - test "returns attachments without descs" do - object = insert(:note) - assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data] - end - - test "returns [] when not pass media_ids" do - assert Utils.attachments_from_ids(%{}) == [] - end - end - - describe "maybe_add_list_data/3" do - test "adds list params when found user list" do - user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user) - - assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == - %{ - additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id}, - object: %{"listMessage" => list.ap_id} - } - end - - test "returns original params when list not found" do - user = insert(:user) - {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user)) - - assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == - %{additional: %{}, object: %{}} - end - end - - describe "make_note_data/11" do - test "returns note data" do - user = insert(:user) - note = insert(:note) - user2 = insert(:user) - user3 = insert(:user) - - assert Utils.make_note_data( - user.ap_id, - [user2.ap_id], - "2hu", - "<h1>This is :moominmamma: note</h1>", - [], - note.id, - [name: "jimm"], - "test summary", - [user3.ap_id], - false, - %{"custom_tag" => "test"} - ) == %{ - "actor" => user.ap_id, - "attachment" => [], - "cc" => [user3.ap_id], - "content" => "<h1>This is :moominmamma: note</h1>", - "context" => "2hu", - "sensitive" => false, - "summary" => "test summary", - "tag" => ["jimm"], - "to" => [user2.ap_id], - "type" => "Note", - "custom_tag" => "test" - } - end - end - - describe "maybe_add_attachments/3" do - test "returns parsed results when attachment_links is false" do - assert Utils.maybe_add_attachments( - {"test", [], ["tags"]}, - [], - false - ) == {"test", [], ["tags"]} - end - - test "adds attachments to parsed results" do - attachment = %{"url" => [%{"href" => "SakuraPM.png"}]} - - assert Utils.maybe_add_attachments( - {"test", [], ["tags"]}, - [attachment], - true - ) == { - "test<br><a href=\"SakuraPM.png\" class='attachment'>SakuraPM.png</a>", - [], - ["tags"] - } - end - end -end diff --git a/test/web/fallback_test.exs b/test/web/fallback_test.exs deleted file mode 100644 index a65865860..000000000 --- a/test/web/fallback_test.exs +++ /dev/null @@ -1,80 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FallbackTest do - use Pleroma.Web.ConnCase - import Pleroma.Factory - - describe "neither preloaded data nor metadata attached to" do - test "GET /registration/:token", %{conn: conn} do - response = get(conn, "/registration/foo") - - assert html_response(response, 200) =~ "<!--server-generated-meta-->" - end - - test "GET /*path", %{conn: conn} do - assert conn - |> get("/foo") - |> html_response(200) =~ "<!--server-generated-meta-->" - end - end - - describe "preloaded data and metadata attached to" do - test "GET /:maybe_nickname_or_id", %{conn: conn} do - user = insert(:user) - user_missing = get(conn, "/foo") - user_present = get(conn, "/#{user.nickname}") - - assert(html_response(user_missing, 200) =~ "<!--server-generated-meta-->") - refute html_response(user_present, 200) =~ "<!--server-generated-meta-->" - assert html_response(user_present, 200) =~ "initial-results" - end - - test "GET /*path", %{conn: conn} do - assert conn - |> get("/foo") - |> html_response(200) =~ "<!--server-generated-meta-->" - - refute conn - |> get("/foo/bar") - |> html_response(200) =~ "<!--server-generated-meta-->" - end - end - - describe "preloaded data is attached to" do - test "GET /main/public", %{conn: conn} do - public_page = get(conn, "/main/public") - - refute html_response(public_page, 200) =~ "<!--server-generated-meta-->" - assert html_response(public_page, 200) =~ "initial-results" - end - - test "GET /main/all", %{conn: conn} do - public_page = get(conn, "/main/all") - - refute html_response(public_page, 200) =~ "<!--server-generated-meta-->" - assert html_response(public_page, 200) =~ "initial-results" - end - end - - test "GET /api*path", %{conn: conn} do - assert conn - |> get("/api/foo") - |> json_response(404) == %{"error" => "Not implemented"} - end - - test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do - assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/" - end - - test "OPTIONS /*path", %{conn: conn} do - assert conn - |> options("/foo") - |> response(204) == "" - - assert conn - |> options("/foo/bar") - |> response(204) == "" - end -end diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs deleted file mode 100644 index 592fdccd1..000000000 --- a/test/web/federator_test.exs +++ /dev/null @@ -1,173 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FederatorTest do - alias Pleroma.Instances - alias Pleroma.Tests.ObanHelpers - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Federator - alias Pleroma.Workers.PublisherWorker - - use Pleroma.DataCase - use Oban.Testing, repo: Pleroma.Repo - - import Pleroma.Factory - import Mock - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - - :ok - end - - setup_all do: clear_config([:instance, :federating], true) - setup do: clear_config([:instance, :allow_relay]) - setup do: clear_config([:mrf, :policies]) - setup do: clear_config([:mrf_keyword]) - - describe "Publish an activity" do - setup do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "HI"}) - - relay_mock = { - Pleroma.Web.ActivityPub.Relay, - [], - [publish: fn _activity -> send(self(), :relay_publish) end] - } - - %{activity: activity, relay_mock: relay_mock} - end - - test "with relays active, it publishes to the relay", %{ - activity: activity, - relay_mock: relay_mock - } do - with_mocks([relay_mock]) do - Federator.publish(activity) - ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) - end - - assert_received :relay_publish - end - - test "with relays deactivated, it does not publish to the relay", %{ - activity: activity, - relay_mock: relay_mock - } do - Pleroma.Config.put([:instance, :allow_relay], false) - - with_mocks([relay_mock]) do - Federator.publish(activity) - ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) - end - - refute_received :relay_publish - end - end - - describe "Targets reachability filtering in `publish`" do - test "it federates only to reachable instances via AP" do - user = insert(:user) - - {inbox1, inbox2} = - {"https://domain.com/users/nick1/inbox", "https://domain2.com/users/nick2/inbox"} - - insert(:user, %{ - local: false, - nickname: "nick1@domain.com", - ap_id: "https://domain.com/users/nick1", - inbox: inbox1, - ap_enabled: true - }) - - insert(:user, %{ - local: false, - nickname: "nick2@domain2.com", - ap_id: "https://domain2.com/users/nick2", - inbox: inbox2, - ap_enabled: true - }) - - dt = NaiveDateTime.utc_now() - Instances.set_unreachable(inbox1, dt) - - Instances.set_consistently_unreachable(URI.parse(inbox2).host) - - {:ok, _activity} = - CommonAPI.post(user, %{status: "HI @nick1@domain.com, @nick2@domain2.com!"}) - - expected_dt = NaiveDateTime.to_iso8601(dt) - - ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) - - assert ObanHelpers.member?( - %{ - "op" => "publish_one", - "params" => %{"inbox" => inbox1, "unreachable_since" => expected_dt} - }, - all_enqueued(worker: PublisherWorker) - ) - end - end - - describe "Receive an activity" do - test "successfully processes incoming AP docs with correct origin" do - params = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => "http://mastodon.example.org/users/admin", - "type" => "Create", - "id" => "http://mastodon.example.org/users/admin/activities/1", - "object" => %{ - "type" => "Note", - "content" => "hi world!", - "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" - }, - "to" => ["https://www.w3.org/ns/activitystreams#Public"] - } - - assert {:ok, job} = Federator.incoming_ap_doc(params) - assert {:ok, _activity} = ObanHelpers.perform(job) - - assert {:ok, job} = Federator.incoming_ap_doc(params) - assert {:error, :already_present} = ObanHelpers.perform(job) - end - - test "rejects incoming AP docs with incorrect origin" do - params = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => "https://niu.moe/users/rye", - "type" => "Create", - "id" => "http://mastodon.example.org/users/admin/activities/1", - "object" => %{ - "type" => "Note", - "content" => "hi world!", - "id" => "http://mastodon.example.org/users/admin/objects/1", - "attributedTo" => "http://mastodon.example.org/users/admin" - }, - "to" => ["https://www.w3.org/ns/activitystreams#Public"] - } - - assert {:ok, job} = Federator.incoming_ap_doc(params) - assert {:error, :origin_containment_failed} = ObanHelpers.perform(job) - end - - test "it does not crash if MRF rejects the post" do - Pleroma.Config.put([:mrf_keyword, :reject], ["lain"]) - - Pleroma.Config.put( - [:mrf, :policies], - Pleroma.Web.ActivityPub.MRF.KeywordPolicy - ) - - params = - File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() - - assert {:ok, job} = Federator.incoming_ap_doc(params) - assert {:error, _} = ObanHelpers.perform(job) - end - end -end diff --git a/test/web/feed/tag_controller_test.exs b/test/web/feed/tag_controller_test.exs deleted file mode 100644 index 3c29cd94f..000000000 --- a/test/web/feed/tag_controller_test.exs +++ /dev/null @@ -1,184 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Feed.TagControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - import SweetXml - - alias Pleroma.Object - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Feed.FeedView - - setup do: clear_config([:feed]) - - test "gets a feed (ATOM)", %{conn: conn} do - Pleroma.Config.put( - [:feed, :post_title], - %{max_length: 25, omission: "..."} - ) - - user = insert(:user) - {:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"}) - - object = Object.normalize(activity1) - - object_data = - Map.put(object.data, "attachment", [ - %{ - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ]) - - object - |> Ecto.Changeset.change(data: object_data) - |> Pleroma.Repo.update() - - {:ok, activity2} = CommonAPI.post(user, %{status: "42 This is :moominmamma #PleromaArt"}) - - {:ok, _activity3} = CommonAPI.post(user, %{status: "This is :moominmamma"}) - - response = - conn - |> put_req_header("accept", "application/atom+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.atom")) - |> response(200) - - xml = parse(response) - - assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart' - - assert xpath(xml, ~x"//feed/entry/title/text()"l) == [ - '42 This is :moominmamm...', - 'yeah #PleromaArt' - ] - - assert xpath(xml, ~x"//feed/entry/author/name/text()"ls) == [user.nickname, user.nickname] - assert xpath(xml, ~x"//feed/entry/author/id/text()"ls) == [user.ap_id, user.ap_id] - - conn = - conn - |> put_req_header("accept", "application/atom+xml") - |> get("/tags/pleromaart.atom", %{"max_id" => activity2.id}) - - assert get_resp_header(conn, "content-type") == ["application/atom+xml; charset=utf-8"] - resp = response(conn, 200) - xml = parse(resp) - - assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart' - - assert xpath(xml, ~x"//feed/entry/title/text()"l) == [ - 'yeah #PleromaArt' - ] - end - - test "gets a feed (RSS)", %{conn: conn} do - Pleroma.Config.put( - [:feed, :post_title], - %{max_length: 25, omission: "..."} - ) - - user = insert(:user) - {:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"}) - - object = Object.normalize(activity1) - - object_data = - Map.put(object.data, "attachment", [ - %{ - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ]) - - object - |> Ecto.Changeset.change(data: object_data) - |> Pleroma.Repo.update() - - {:ok, activity2} = CommonAPI.post(user, %{status: "42 This is :moominmamma #PleromaArt"}) - - {:ok, _activity3} = CommonAPI.post(user, %{status: "This is :moominmamma"}) - - response = - conn - |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) - |> response(200) - - xml = parse(response) - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' - - assert xpath(xml, ~x"//channel/description/text()"s) == - "These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse." - - assert xpath(xml, ~x"//channel/link/text()") == - '#{Pleroma.Web.base_url()}/tags/pleromaart.rss' - - assert xpath(xml, ~x"//channel/webfeeds:logo/text()") == - '#{Pleroma.Web.base_url()}/static/logo.png' - - assert xpath(xml, ~x"//channel/item/title/text()"l) == [ - '42 This is :moominmamm...', - 'yeah #PleromaArt' - ] - - assert xpath(xml, ~x"//channel/item/pubDate/text()"sl) == [ - FeedView.pub_date(activity2.data["published"]), - FeedView.pub_date(activity1.data["published"]) - ] - - assert xpath(xml, ~x"//channel/item/enclosure/@url"sl) == [ - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4" - ] - - obj1 = Object.normalize(activity1) - obj2 = Object.normalize(activity2) - - assert xpath(xml, ~x"//channel/item/description/text()"sl) == [ - HtmlEntities.decode(FeedView.activity_content(obj2.data)), - HtmlEntities.decode(FeedView.activity_content(obj1.data)) - ] - - response = - conn - |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart")) - |> response(200) - - xml = parse(response) - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' - - assert xpath(xml, ~x"//channel/description/text()"s) == - "These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse." - - conn = - conn - |> put_req_header("accept", "application/rss+xml") - |> get("/tags/pleromaart.rss", %{"max_id" => activity2.id}) - - assert get_resp_header(conn, "content-type") == ["application/rss+xml; charset=utf-8"] - resp = response(conn, 200) - xml = parse(resp) - - assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart' - - assert xpath(xml, ~x"//channel/item/title/text()"l) == [ - 'yeah #PleromaArt' - ] - end -end diff --git a/test/web/feed/user_controller_test.exs b/test/web/feed/user_controller_test.exs deleted file mode 100644 index fa2ed1ea5..000000000 --- a/test/web/feed/user_controller_test.exs +++ /dev/null @@ -1,238 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Feed.UserControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - import SweetXml - - alias Pleroma.Config - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - setup do: clear_config([:instance, :federating], true) - - describe "feed" do - setup do: clear_config([:feed]) - - test "gets an atom feed", %{conn: conn} do - Config.put( - [:feed, :post_title], - %{max_length: 10, omission: "..."} - ) - - activity = insert(:note_activity) - - note = - insert(:note, - data: %{ - "content" => "This is :moominmamma: note ", - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"} - ] - } - ], - "inReplyTo" => activity.data["id"] - } - ) - - note_activity = insert(:note_activity, note: note) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - - note2 = - insert(:note, - user: user, - data: %{ - "content" => "42 This is :moominmamma: note ", - "inReplyTo" => activity.data["id"] - } - ) - - note_activity2 = insert(:note_activity, note: note2) - object = Object.normalize(note_activity) - - resp = - conn - |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) - |> response(200) - - activity_titles = - resp - |> SweetXml.parse() - |> SweetXml.xpath(~x"//entry/title/text()"l) - - assert activity_titles == ['42 This...', 'This is...'] - assert resp =~ object.data["content"] - - resp = - conn - |> put_req_header("accept", "application/atom+xml") - |> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id}) - |> response(200) - - activity_titles = - resp - |> SweetXml.parse() - |> SweetXml.xpath(~x"//entry/title/text()"l) - - assert activity_titles == ['This is...'] - end - - test "gets a rss feed", %{conn: conn} do - Pleroma.Config.put( - [:feed, :post_title], - %{max_length: 10, omission: "..."} - ) - - activity = insert(:note_activity) - - note = - insert(:note, - data: %{ - "content" => "This is :moominmamma: note ", - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"} - ] - } - ], - "inReplyTo" => activity.data["id"] - } - ) - - note_activity = insert(:note_activity, note: note) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - - note2 = - insert(:note, - user: user, - data: %{ - "content" => "42 This is :moominmamma: note ", - "inReplyTo" => activity.data["id"] - } - ) - - note_activity2 = insert(:note_activity, note: note2) - object = Object.normalize(note_activity) - - resp = - conn - |> put_req_header("accept", "application/rss+xml") - |> get("/users/#{user.nickname}/feed.rss") - |> response(200) - - activity_titles = - resp - |> SweetXml.parse() - |> SweetXml.xpath(~x"//item/title/text()"l) - - assert activity_titles == ['42 This...', 'This is...'] - assert resp =~ object.data["content"] - - resp = - conn - |> put_req_header("accept", "application/rss+xml") - |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id}) - |> response(200) - - activity_titles = - resp - |> SweetXml.parse() - |> SweetXml.xpath(~x"//item/title/text()"l) - - assert activity_titles == ['This is...'] - end - - test "returns 404 for a missing feed", %{conn: conn} do - conn = - conn - |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, "nonexisting")) - - assert response(conn, 404) - end - - test "returns feed with public and unlisted activities", %{conn: conn} do - user = insert(:user) - - {:ok, _} = CommonAPI.post(user, %{status: "public", visibility: "public"}) - {:ok, _} = CommonAPI.post(user, %{status: "direct", visibility: "direct"}) - {:ok, _} = CommonAPI.post(user, %{status: "unlisted", visibility: "unlisted"}) - {:ok, _} = CommonAPI.post(user, %{status: "private", visibility: "private"}) - - resp = - conn - |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) - |> response(200) - - activity_titles = - resp - |> SweetXml.parse() - |> SweetXml.xpath(~x"//entry/title/text()"l) - |> Enum.sort() - - assert activity_titles == ['public', 'unlisted'] - end - end - - # Note: see ActivityPubControllerTest for JSON format tests - describe "feed_redirect" do - test "with html format, it redirects to user feed", %{conn: conn} do - note_activity = insert(:note_activity) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - - response = - conn - |> get("/users/#{user.nickname}") - |> response(200) - - assert response == - Fallback.RedirectController.redirector_with_meta( - conn, - %{user: user} - ).resp_body - end - - test "with html format, it returns error when user is not found", %{conn: conn} do - response = - conn - |> get("/users/jimm") - |> json_response(404) - - assert response == %{"error" => "Not found"} - end - - test "with non-html / non-json format, it redirects to user feed in atom format", %{ - conn: conn - } do - note_activity = insert(:note_activity) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - - conn = - conn - |> put_req_header("accept", "application/xml") - |> get("/users/#{user.nickname}") - - assert conn.status == 302 - assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom" - end - - test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do - response = - conn - |> put_req_header("accept", "application/xml") - |> get(user_feed_path(conn, :feed, "jimm")) - |> response(404) - - assert response == ~S({"error":"Not found"}) - end - end -end diff --git a/test/web/instances/instance_test.exs b/test/web/instances/instance_test.exs deleted file mode 100644 index e463200ca..000000000 --- a/test/web/instances/instance_test.exs +++ /dev/null @@ -1,100 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Instances.InstanceTest do - alias Pleroma.Instances.Instance - alias Pleroma.Repo - - use Pleroma.DataCase - - import Pleroma.Factory - - setup_all do: clear_config([:instance, :federation_reachability_timeout_days], 1) - - describe "set_reachable/1" do - test "clears `unreachable_since` of existing matching Instance record having non-nil `unreachable_since`" do - unreachable_since = NaiveDateTime.to_iso8601(NaiveDateTime.utc_now()) - instance = insert(:instance, unreachable_since: unreachable_since) - - assert {:ok, instance} = Instance.set_reachable(instance.host) - refute instance.unreachable_since - end - - test "keeps nil `unreachable_since` of existing matching Instance record having nil `unreachable_since`" do - instance = insert(:instance, unreachable_since: nil) - - assert {:ok, instance} = Instance.set_reachable(instance.host) - refute instance.unreachable_since - end - - test "does NOT create an Instance record in case of no existing matching record" do - host = "domain.org" - assert nil == Instance.set_reachable(host) - - assert [] = Repo.all(Ecto.Query.from(i in Instance)) - assert Instance.reachable?(host) - end - end - - describe "set_unreachable/1" do - test "creates new record having `unreachable_since` to current time if record does not exist" do - assert {:ok, instance} = Instance.set_unreachable("https://domain.com/path") - - instance = Repo.get(Instance, instance.id) - assert instance.unreachable_since - assert "domain.com" == instance.host - end - - test "sets `unreachable_since` of existing record having nil `unreachable_since`" do - instance = insert(:instance, unreachable_since: nil) - refute instance.unreachable_since - - assert {:ok, _} = Instance.set_unreachable(instance.host) - - instance = Repo.get(Instance, instance.id) - assert instance.unreachable_since - end - - test "does NOT modify `unreachable_since` value of existing record in case it's present" do - instance = - insert(:instance, unreachable_since: NaiveDateTime.add(NaiveDateTime.utc_now(), -10)) - - assert instance.unreachable_since - initial_value = instance.unreachable_since - - assert {:ok, _} = Instance.set_unreachable(instance.host) - - instance = Repo.get(Instance, instance.id) - assert initial_value == instance.unreachable_since - end - end - - describe "set_unreachable/2" do - test "sets `unreachable_since` value of existing record in case it's newer than supplied value" do - instance = - insert(:instance, unreachable_since: NaiveDateTime.add(NaiveDateTime.utc_now(), -10)) - - assert instance.unreachable_since - - past_value = NaiveDateTime.add(NaiveDateTime.utc_now(), -100) - assert {:ok, _} = Instance.set_unreachable(instance.host, past_value) - - instance = Repo.get(Instance, instance.id) - assert past_value == instance.unreachable_since - end - - test "does NOT modify `unreachable_since` value of existing record in case it's equal to or older than supplied value" do - instance = - insert(:instance, unreachable_since: NaiveDateTime.add(NaiveDateTime.utc_now(), -10)) - - assert instance.unreachable_since - initial_value = instance.unreachable_since - - assert {:ok, _} = Instance.set_unreachable(instance.host, NaiveDateTime.utc_now()) - - instance = Repo.get(Instance, instance.id) - assert initial_value == instance.unreachable_since - end - end -end diff --git a/test/web/instances/instances_test.exs b/test/web/instances/instances_test.exs deleted file mode 100644 index d2618025c..000000000 --- a/test/web/instances/instances_test.exs +++ /dev/null @@ -1,124 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.InstancesTest do - alias Pleroma.Instances - - use Pleroma.DataCase - - setup_all do: clear_config([:instance, :federation_reachability_timeout_days], 1) - - describe "reachable?/1" do - test "returns `true` for host / url with unknown reachability status" do - assert Instances.reachable?("unknown.site") - assert Instances.reachable?("http://unknown.site") - end - - test "returns `false` for host / url marked unreachable for at least `reachability_datetime_threshold()`" do - host = "consistently-unreachable.name" - Instances.set_consistently_unreachable(host) - - refute Instances.reachable?(host) - refute Instances.reachable?("http://#{host}/path") - end - - test "returns `true` for host / url marked unreachable for less than `reachability_datetime_threshold()`" do - url = "http://eventually-unreachable.name/path" - - Instances.set_unreachable(url) - - assert Instances.reachable?(url) - assert Instances.reachable?(URI.parse(url).host) - end - - test "returns true on non-binary input" do - assert Instances.reachable?(nil) - assert Instances.reachable?(1) - end - end - - describe "filter_reachable/1" do - setup do - host = "consistently-unreachable.name" - url1 = "http://eventually-unreachable.com/path" - url2 = "http://domain.com/path" - - Instances.set_consistently_unreachable(host) - Instances.set_unreachable(url1) - - result = Instances.filter_reachable([host, url1, url2, nil]) - %{result: result, url1: url1, url2: url2} - end - - test "returns a map with keys containing 'not marked consistently unreachable' elements of supplied list", - %{result: result, url1: url1, url2: url2} do - assert is_map(result) - assert Enum.sort([url1, url2]) == result |> Map.keys() |> Enum.sort() - end - - test "returns a map with `unreachable_since` values for keys", - %{result: result, url1: url1, url2: url2} do - assert is_map(result) - assert %NaiveDateTime{} = result[url1] - assert is_nil(result[url2]) - end - - test "returns an empty map for empty list or list containing no hosts / url" do - assert %{} == Instances.filter_reachable([]) - assert %{} == Instances.filter_reachable([nil]) - end - end - - describe "set_reachable/1" do - test "sets unreachable url or host reachable" do - host = "domain.com" - Instances.set_consistently_unreachable(host) - refute Instances.reachable?(host) - - Instances.set_reachable(host) - assert Instances.reachable?(host) - end - - test "keeps reachable url or host reachable" do - url = "https://site.name?q=" - assert Instances.reachable?(url) - - Instances.set_reachable(url) - assert Instances.reachable?(url) - end - - test "returns error status on non-binary input" do - assert {:error, _} = Instances.set_reachable(nil) - assert {:error, _} = Instances.set_reachable(1) - end - end - - # Note: implementation-specific (e.g. Instance) details of set_unreachable/1 - # should be tested in implementation-specific tests - describe "set_unreachable/1" do - test "returns error status on non-binary input" do - assert {:error, _} = Instances.set_unreachable(nil) - assert {:error, _} = Instances.set_unreachable(1) - end - end - - describe "set_consistently_unreachable/1" do - test "sets reachable url or host unreachable" do - url = "http://domain.com?q=" - assert Instances.reachable?(url) - - Instances.set_consistently_unreachable(url) - refute Instances.reachable?(url) - end - - test "keeps unreachable url or host unreachable" do - host = "site.name" - Instances.set_consistently_unreachable(host) - refute Instances.reachable?(host) - - Instances.set_consistently_unreachable(host) - refute Instances.reachable?(host) - end - end -end diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs deleted file mode 100644 index f3b54b5f2..000000000 --- a/test/web/masto_fe_controller_test.exs +++ /dev/null @@ -1,85 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MastoFEController do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.User - - import Pleroma.Factory - - setup do: clear_config([:instance, :public]) - - test "put settings", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:accounts"])) - |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}}) - - assert _result = json_response(conn, 200) - - user = User.get_cached_by_ap_id(user.ap_id) - assert user.mastofe_settings == %{"programming" => "socks"} - end - - describe "index/2 redirections" do - setup %{conn: conn} do - session_opts = [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - conn = - conn - |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session() - - test_path = "/web/statuses/test" - %{conn: conn, path: test_path} - end - - test "redirects not logged-in users to the login page", %{conn: conn, path: path} do - conn = get(conn, path) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/login" - end - - test "redirects not logged-in users to the login page on private instances", %{ - conn: conn, - path: path - } do - Config.put([:instance, :public], false) - - conn = get(conn, path) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/login" - end - - test "does not redirect logged in users to the login page", %{conn: conn, path: path} do - token = insert(:oauth_token, scopes: ["read"]) - - conn = - conn - |> assign(:user, token.user) - |> assign(:token, token) - |> get(path) - - assert conn.status == 200 - end - - test "saves referer path to session", %{conn: conn, path: path} do - conn = get(conn, path) - return_to = Plug.Conn.get_session(conn, :return_to) - - assert return_to == path - end - end -end diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs deleted file mode 100644 index b888e4c71..000000000 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ /dev/null @@ -1,525 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 Mock - import Pleroma.Factory - - setup do: clear_config([:instance, :max_account_fields]) - - describe "updating credentials" do - setup do: oauth_access(["write:accounts"]) - setup :request_content_type - - test "sets user settings in a generic way", %{conn: conn} do - res_conn = - patch(conn, "/api/v1/accounts/update_credentials", %{ - "pleroma_settings_store" => %{ - pleroma_fe: %{ - theme: "bla" - } - } - }) - - assert user_data = json_response_and_validate_schema(res_conn, 200) - assert user_data["pleroma"]["settings_store"] == %{"pleroma_fe" => %{"theme" => "bla"}} - - user = Repo.get(User, user_data["id"]) - - res_conn = - conn - |> assign(:user, user) - |> patch("/api/v1/accounts/update_credentials", %{ - "pleroma_settings_store" => %{ - masto_fe: %{ - theme: "bla" - } - } - }) - - assert user_data = json_response_and_validate_schema(res_conn, 200) - - assert user_data["pleroma"]["settings_store"] == - %{ - "pleroma_fe" => %{"theme" => "bla"}, - "masto_fe" => %{"theme" => "bla"} - } - - user = Repo.get(User, user_data["id"]) - - clear_config([:instance, :federating], true) - - with_mock Pleroma.Web.Federator, - publish: fn _activity -> :ok end do - res_conn = - conn - |> assign(:user, user) - |> patch("/api/v1/accounts/update_credentials", %{ - "pleroma_settings_store" => %{ - masto_fe: %{ - theme: "blub" - } - } - }) - - assert user_data = json_response_and_validate_schema(res_conn, 200) - - assert user_data["pleroma"]["settings_store"] == - %{ - "pleroma_fe" => %{"theme" => "bla"}, - "masto_fe" => %{"theme" => "blub"} - } - - assert_called(Pleroma.Web.Federator.publish(:_)) - end - end - - test "updates the user's bio", %{conn: conn} do - user2 = insert(:user) - - raw_bio = "I drink #cofe with @#{user2.nickname}\n\nsuya.." - - conn = patch(conn, "/api/v1/accounts/update_credentials", %{"note" => raw_bio}) - - assert user_data = json_response_and_validate_schema(conn, 200) - - assert user_data["note"] == - ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a class="u-url mention" data-user="#{ - user2.id - }" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span><br/><br/>suya..) - - assert user_data["source"]["note"] == raw_bio - - user = Repo.get(User, user_data["id"]) - - assert user.raw_bio == raw_bio - end - - test "updates the user's locking status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{locked: "true"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["locked"] == true - end - - test "updates the user's chat acceptance status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{accepts_chat_messages: "false"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["accepts_chat_messages"] == false - end - - test "updates the user's allow_following_move", %{user: user, conn: conn} do - assert user.allow_following_move == true - - conn = patch(conn, "/api/v1/accounts/update_credentials", %{allow_following_move: "false"}) - - assert refresh_record(user).allow_following_move == false - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["allow_following_move"] == false - end - - test "updates the user's default scope", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{default_scope: "unlisted"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["source"]["privacy"] == "unlisted" - end - - test "updates the user's privacy", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{source: %{privacy: "unlisted"}}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["source"]["privacy"] == "unlisted" - end - - test "updates the user's hide_followers status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{hide_followers: "true"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["hide_followers"] == true - end - - test "updates the user's discoverable status", %{conn: conn} do - assert %{"source" => %{"pleroma" => %{"discoverable" => true}}} = - conn - |> patch("/api/v1/accounts/update_credentials", %{discoverable: "true"}) - |> json_response_and_validate_schema(:ok) - - assert %{"source" => %{"pleroma" => %{"discoverable" => false}}} = - conn - |> patch("/api/v1/accounts/update_credentials", %{discoverable: "false"}) - |> json_response_and_validate_schema(:ok) - end - - test "updates the user's hide_followers_count and hide_follows_count", %{conn: conn} do - conn = - patch(conn, "/api/v1/accounts/update_credentials", %{ - hide_followers_count: "true", - hide_follows_count: "true" - }) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["hide_followers_count"] == true - assert user_data["pleroma"]["hide_follows_count"] == true - end - - test "updates the user's skip_thread_containment option", %{user: user, conn: conn} do - response = - conn - |> patch("/api/v1/accounts/update_credentials", %{skip_thread_containment: "true"}) - |> json_response_and_validate_schema(200) - - assert response["pleroma"]["skip_thread_containment"] == true - assert refresh_record(user).skip_thread_containment - end - - test "updates the user's hide_follows status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{hide_follows: "true"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["hide_follows"] == true - end - - test "updates the user's hide_favorites status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{hide_favorites: "true"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["pleroma"]["hide_favorites"] == true - end - - test "updates the user's show_role status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{show_role: "false"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["source"]["pleroma"]["show_role"] == false - end - - test "updates the user's no_rich_text status", %{conn: conn} do - conn = patch(conn, "/api/v1/accounts/update_credentials", %{no_rich_text: "true"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["source"]["pleroma"]["no_rich_text"] == true - end - - test "updates the user's name", %{conn: conn} do - conn = - patch(conn, "/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"}) - - assert user_data = json_response_and_validate_schema(conn, 200) - assert user_data["display_name"] == "markorepairs" - end - - test "updates the user's avatar", %{user: user, conn: conn} do - new_avatar = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - assert user.avatar == %{} - - res = patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => new_avatar}) - - assert user_response = json_response_and_validate_schema(res, 200) - assert user_response["avatar"] != User.avatar_url(user) - - user = User.get_by_id(user.id) - refute user.avatar == %{} - - # Also resets it - _res = patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => ""}) - - user = User.get_by_id(user.id) - assert user.avatar == nil - end - - test "updates the user's banner", %{user: user, conn: conn} do - new_header = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - res = patch(conn, "/api/v1/accounts/update_credentials", %{"header" => new_header}) - - assert user_response = json_response_and_validate_schema(res, 200) - assert user_response["header"] != User.banner_url(user) - - # Also resets it - _res = patch(conn, "/api/v1/accounts/update_credentials", %{"header" => ""}) - - user = User.get_by_id(user.id) - assert user.banner == nil - end - - test "updates the user's background", %{conn: conn, user: user} do - new_header = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - res = - patch(conn, "/api/v1/accounts/update_credentials", %{ - "pleroma_background_image" => new_header - }) - - assert user_response = json_response_and_validate_schema(res, 200) - assert user_response["pleroma"]["background_image"] - # - # Also resets it - _res = - patch(conn, "/api/v1/accounts/update_credentials", %{"pleroma_background_image" => ""}) - - user = User.get_by_id(user.id) - assert user.background == nil - end - - test "requires 'write:accounts' permission" do - token1 = insert(:oauth_token, scopes: ["read"]) - token2 = insert(:oauth_token, scopes: ["write", "follow"]) - - for token <- [token1, token2] do - conn = - build_conn() - |> put_req_header("content-type", "multipart/form-data") - |> put_req_header("authorization", "Bearer #{token.token}") - |> patch("/api/v1/accounts/update_credentials", %{}) - - if token == token1 do - assert %{"error" => "Insufficient permissions: write:accounts."} == - json_response_and_validate_schema(conn, 403) - else - assert json_response_and_validate_schema(conn, 200) - end - end - end - - test "updates profile emojos", %{user: user, conn: conn} do - note = "*sips :blank:*" - name = "I am :firefox:" - - ret_conn = - patch(conn, "/api/v1/accounts/update_credentials", %{ - "note" => note, - "display_name" => name - }) - - assert json_response_and_validate_schema(ret_conn, 200) - - conn = get(conn, "/api/v1/accounts/#{user.id}") - - assert user_data = json_response_and_validate_schema(conn, 200) - - assert user_data["note"] == note - assert user_data["display_name"] == name - assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user_data["emojis"] - end - - test "update fields", %{conn: conn} do - fields = [ - %{"name" => "<a href=\"http://google.com\">foo</a>", "value" => "<script>bar</script>"}, - %{"name" => "link.io", "value" => "cofe.io"} - ] - - account_data = - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(200) - - assert account_data["fields"] == [ - %{"name" => "<a href=\"http://google.com\">foo</a>", "value" => "bar"}, - %{ - "name" => "link.io", - "value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>) - } - ] - - assert account_data["source"]["fields"] == [ - %{ - "name" => "<a href=\"http://google.com\">foo</a>", - "value" => "<script>bar</script>" - }, - %{"name" => "link.io", "value" => "cofe.io"} - ] - end - - test "emojis in fields labels", %{conn: conn} do - fields = [ - %{"name" => ":firefox:", "value" => "is best 2hu"}, - %{"name" => "they wins", "value" => ":blank:"} - ] - - account_data = - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(200) - - assert account_data["fields"] == [ - %{"name" => ":firefox:", "value" => "is best 2hu"}, - %{"name" => "they wins", "value" => ":blank:"} - ] - - assert account_data["source"]["fields"] == [ - %{"name" => ":firefox:", "value" => "is best 2hu"}, - %{"name" => "they wins", "value" => ":blank:"} - ] - - assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = account_data["emojis"] - end - - test "update fields via x-www-form-urlencoded", %{conn: conn} do - fields = - [ - "fields_attributes[1][name]=link", - "fields_attributes[1][value]=http://cofe.io", - "fields_attributes[0][name]=foo", - "fields_attributes[0][value]=bar" - ] - |> Enum.join("&") - - account = - conn - |> put_req_header("content-type", "application/x-www-form-urlencoded") - |> patch("/api/v1/accounts/update_credentials", fields) - |> json_response_and_validate_schema(200) - - assert account["fields"] == [ - %{"name" => "foo", "value" => "bar"}, - %{ - "name" => "link", - "value" => ~S(<a href="http://cofe.io" rel="ugc">http://cofe.io</a>) - } - ] - - assert account["source"]["fields"] == [ - %{"name" => "foo", "value" => "bar"}, - %{"name" => "link", "value" => "http://cofe.io"} - ] - end - - test "update fields with empty name", %{conn: conn} do - fields = [ - %{"name" => "foo", "value" => ""}, - %{"name" => "", "value" => "bar"} - ] - - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(200) - - assert account["fields"] == [ - %{"name" => "foo", "value" => ""} - ] - end - - test "update fields when invalid request", %{conn: conn} do - name_limit = Pleroma.Config.get([:instance, :account_field_name_length]) - value_limit = Pleroma.Config.get([:instance, :account_field_value_length]) - - long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join() - long_value = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join() - - fields = [%{"name" => "foo", "value" => long_value}] - - assert %{"error" => "Invalid request"} == - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(403) - - fields = [%{"name" => long_name, "value" => "bar"}] - - assert %{"error" => "Invalid request"} == - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(403) - - Pleroma.Config.put([:instance, :max_account_fields], 1) - - fields = [ - %{"name" => "foo", "value" => "bar"}, - %{"name" => "link", "value" => "cofe.io"} - ] - - assert %{"error" => "Invalid request"} == - conn - |> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields}) - |> json_response_and_validate_schema(403) - end - end - - describe "Mark account as bot" do - setup do: oauth_access(["write:accounts"]) - setup :request_content_type - - test "changing actor_type to Service makes account a bot", %{conn: conn} do - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{actor_type: "Service"}) - |> json_response_and_validate_schema(200) - - assert account["bot"] - assert account["source"]["pleroma"]["actor_type"] == "Service" - end - - test "changing actor_type to Person makes account a human", %{conn: conn} do - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{actor_type: "Person"}) - |> json_response_and_validate_schema(200) - - refute account["bot"] - assert account["source"]["pleroma"]["actor_type"] == "Person" - end - - test "changing actor_type to Application causes error", %{conn: conn} do - response = - conn - |> patch("/api/v1/accounts/update_credentials", %{actor_type: "Application"}) - |> json_response_and_validate_schema(403) - - assert %{"error" => "Invalid request"} == response - end - - test "changing bot field to true changes actor_type to Service", %{conn: conn} do - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{bot: "true"}) - |> json_response_and_validate_schema(200) - - assert account["bot"] - assert account["source"]["pleroma"]["actor_type"] == "Service" - end - - test "changing bot field to false changes actor_type to Person", %{conn: conn} do - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{bot: "false"}) - |> json_response_and_validate_schema(200) - - refute account["bot"] - assert account["source"]["pleroma"]["actor_type"] == "Person" - end - - test "actor_type field has a higher priority than bot", %{conn: conn} do - account = - conn - |> patch("/api/v1/accounts/update_credentials", %{ - actor_type: "Person", - bot: "true" - }) - |> json_response_and_validate_schema(200) - - refute account["bot"] - assert account["source"]["pleroma"]["actor_type"] == "Person" - end - end -end diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs deleted file mode 100644 index c304487ea..000000000 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ /dev/null @@ -1,1399 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.InternalFetchActor - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.OAuth.Token - - import Pleroma.Factory - - describe "account fetching" do - setup do: clear_config([:instance, :limit_to_local_content]) - - test "works by id" do - %User{id: user_id} = insert(:user) - - assert %{"id" => ^user_id} = - build_conn() - |> get("/api/v1/accounts/#{user_id}") - |> json_response_and_validate_schema(200) - - assert %{"error" => "Can't find user"} = - build_conn() - |> get("/api/v1/accounts/-1") - |> json_response_and_validate_schema(404) - end - - test "works by nickname" do - user = insert(:user) - - assert %{"id" => user_id} = - build_conn() - |> get("/api/v1/accounts/#{user.nickname}") - |> json_response_and_validate_schema(200) - end - - test "works by nickname for remote users" do - Config.put([:instance, :limit_to_local_content], false) - - user = insert(:user, nickname: "user@example.com", local: false) - - assert %{"id" => user_id} = - build_conn() - |> get("/api/v1/accounts/#{user.nickname}") - |> json_response_and_validate_schema(200) - end - - test "respects limit_to_local_content == :all for remote user nicknames" do - Config.put([:instance, :limit_to_local_content], :all) - - user = insert(:user, nickname: "user@example.com", local: false) - - assert build_conn() - |> get("/api/v1/accounts/#{user.nickname}") - |> json_response_and_validate_schema(404) - end - - test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do - Config.put([:instance, :limit_to_local_content], :unauthenticated) - - user = insert(:user, nickname: "user@example.com", local: false) - reading_user = insert(:user) - - conn = - build_conn() - |> get("/api/v1/accounts/#{user.nickname}") - - assert json_response_and_validate_schema(conn, 404) - - conn = - build_conn() - |> assign(:user, reading_user) - |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"])) - |> get("/api/v1/accounts/#{user.nickname}") - - assert %{"id" => id} = json_response_and_validate_schema(conn, 200) - assert id == user.id - end - - test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do - # Need to set an old-style integer ID to reproduce the problem - # (these are no longer assigned to new accounts but were preserved - # for existing accounts during the migration to flakeIDs) - user_one = insert(:user, %{id: 1212}) - user_two = insert(:user, %{nickname: "#{user_one.id}garbage"}) - - acc_one = - conn - |> get("/api/v1/accounts/#{user_one.id}") - |> json_response_and_validate_schema(:ok) - - acc_two = - conn - |> get("/api/v1/accounts/#{user_two.nickname}") - |> json_response_and_validate_schema(:ok) - - acc_three = - conn - |> get("/api/v1/accounts/#{user_two.id}") - |> json_response_and_validate_schema(:ok) - - refute acc_one == acc_two - assert acc_two == acc_three - end - - test "returns 404 when user is invisible", %{conn: conn} do - user = insert(:user, %{invisible: true}) - - assert %{"error" => "Can't find user"} = - conn - |> get("/api/v1/accounts/#{user.nickname}") - |> json_response_and_validate_schema(404) - end - - test "returns 404 for internal.fetch actor", %{conn: conn} do - %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor() - - assert %{"error" => "Can't find user"} = - conn - |> get("/api/v1/accounts/internal.fetch") - |> json_response_and_validate_schema(404) - end - - test "returns 404 for deactivated user", %{conn: conn} do - user = insert(:user, deactivated: true) - - assert %{"error" => "Can't find user"} = - conn - |> get("/api/v1/accounts/#{user.id}") - |> json_response_and_validate_schema(:not_found) - end - end - - defp local_and_remote_users do - local = insert(:user) - remote = insert(:user, local: false) - {:ok, local: local, remote: remote} - end - - describe "user fetching with restrict unauthenticated profiles for local and remote" do - setup do: local_and_remote_users() - - setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true) - - setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{local.id}") - |> json_response_and_validate_schema(:unauthorized) - - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{remote.id}") - |> json_response_and_validate_schema(:unauthorized) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - describe "user fetching with restrict unauthenticated profiles for local" do - setup do: local_and_remote_users() - - setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/accounts/#{local.id}") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "This API requires an authenticated user" - } - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - describe "user fetching with restrict unauthenticated profiles for remote" do - setup do: local_and_remote_users() - - setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/accounts/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "This API requires an authenticated user" - } - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - describe "user timelines" do - setup do: oauth_access(["read:statuses"]) - - test "works with announces that are just addressed to public", %{conn: conn} do - user = insert(:user, ap_id: "https://honktest/u/test", local: false) - other_user = insert(:user) - - {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"}) - - {:ok, announce, _} = - %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "actor" => "https://honktest/u/test", - "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx", - "object" => post.data["object"], - "published" => "2019-06-25T19:33:58Z", - "to" => ["https://www.w3.org/ns/activitystreams#Public"], - "type" => "Announce" - } - |> ActivityPub.persist(local: false) - - assert resp = - conn - |> get("/api/v1/accounts/#{user.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id}] = resp - assert id == announce.id - end - - test "deactivated user", %{conn: conn} do - user = insert(:user, deactivated: true) - - assert %{"error" => "Can't find user"} == - conn - |> get("/api/v1/accounts/#{user.id}/statuses") - |> json_response_and_validate_schema(:not_found) - end - - test "returns 404 when user is invisible", %{conn: conn} do - user = insert(:user, %{invisible: true}) - - assert %{"error" => "Can't find user"} = - conn - |> get("/api/v1/accounts/#{user.id}") - |> json_response_and_validate_schema(404) - end - - test "respects blocks", %{user: user_one, conn: conn} do - user_two = insert(:user) - user_three = insert(:user) - - User.block(user_one, user_two) - - {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"}) - {:ok, repeat} = CommonAPI.repeat(activity.id, user_three) - - assert resp = - conn - |> get("/api/v1/accounts/#{user_two.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id}] = resp - assert id == activity.id - - # Even a blocked user will deliver the full user timeline, there would be - # no point in looking at a blocked users timeline otherwise - assert resp = - conn - |> get("/api/v1/accounts/#{user_two.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id}] = resp - assert id == activity.id - - # Third user's timeline includes the repeat when viewed by unauthenticated user - resp = - build_conn() - |> get("/api/v1/accounts/#{user_three.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id}] = resp - assert id == repeat.id - - # When viewing a third user's timeline, the blocked users' statuses will NOT be shown - resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses") - - assert [] == json_response_and_validate_schema(resp, 200) - end - - test "gets users statuses", %{conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - user_three = insert(:user) - - {:ok, _user_three} = User.follow(user_three, user_one) - - {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"}) - - {:ok, direct_activity} = - CommonAPI.post(user_one, %{ - status: "Hi, @#{user_two.nickname}.", - visibility: "direct" - }) - - {:ok, private_activity} = - CommonAPI.post(user_one, %{status: "private", visibility: "private"}) - - # TODO!!! - resp = - conn - |> get("/api/v1/accounts/#{user_one.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id}] = resp - assert id == to_string(activity.id) - - resp = - conn - |> assign(:user, user_two) - |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"])) - |> get("/api/v1/accounts/#{user_one.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id_one}, %{"id" => id_two}] = resp - assert id_one == to_string(direct_activity.id) - assert id_two == to_string(activity.id) - - resp = - conn - |> assign(:user, user_three) - |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"])) - |> get("/api/v1/accounts/#{user_one.id}/statuses") - |> json_response_and_validate_schema(200) - - assert [%{"id" => id_one}, %{"id" => id_two}] = resp - assert id_one == to_string(private_activity.id) - assert id_two == to_string(activity.id) - end - - test "unimplemented pinned statuses feature", %{conn: conn} do - note = insert(:note_activity) - user = User.get_cached_by_ap_id(note.data["actor"]) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?pinned=true") - - assert json_response_and_validate_schema(conn, 200) == [] - end - - test "gets an users media, excludes reblogs", %{conn: conn} do - note = insert(:note_activity) - user = User.get_cached_by_ap_id(note.data["actor"]) - other_user = insert(:user) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id) - - {:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]}) - - {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id) - - {:ok, %{id: other_image_post_id}} = - CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]}) - - {:ok, _announce} = CommonAPI.repeat(other_image_post_id, user) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true") - - assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200) - - conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1") - - assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200) - end - - test "gets a user's statuses without reblogs", %{user: user, conn: conn} do - {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"}) - {:ok, _} = CommonAPI.repeat(post_id, user) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true") - assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1") - assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200) - end - - test "filters user's statuses by a hashtag", %{user: user, conn: conn} do - {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"}) - {:ok, _post} = CommonAPI.post(user, %{status: "hashtag"}) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag") - assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200) - end - - test "the user views their own timelines and excludes direct messages", %{ - user: user, - conn: conn - } do - {:ok, %{id: public_activity_id}} = - CommonAPI.post(user, %{status: ".", visibility: "public"}) - - {:ok, _direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct") - assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200) - end - end - - defp local_and_remote_activities(%{local: local, remote: remote}) do - insert(:note_activity, user: local) - insert(:note_activity, user: remote, local: false) - - :ok - end - - describe "statuses with restrict unauthenticated profiles for local and remote" do - setup do: local_and_remote_users() - setup :local_and_remote_activities - - setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true) - - setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{local.id}/statuses") - |> json_response_and_validate_schema(:unauthorized) - - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{remote.id}/statuses") - |> json_response_and_validate_schema(:unauthorized) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - end - end - - describe "statuses with restrict unauthenticated profiles for local" do - setup do: local_and_remote_users() - setup :local_and_remote_activities - - setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{local.id}/statuses") - |> json_response_and_validate_schema(:unauthorized) - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - end - end - - describe "statuses with restrict unauthenticated profiles for remote" do - setup do: local_and_remote_users() - setup :local_and_remote_activities - - setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - assert %{"error" => "This API requires an authenticated user"} == - conn - |> get("/api/v1/accounts/#{remote.id}/statuses") - |> json_response_and_validate_schema(:unauthorized) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - end - end - - describe "followers" do - setup do: oauth_access(["read:accounts"]) - - test "getting followers", %{user: user, conn: conn} do - other_user = insert(:user) - {:ok, %{id: user_id}} = User.follow(user, other_user) - - conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers") - - assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200) - end - - test "getting followers, hide_followers", %{user: user, conn: conn} do - other_user = insert(:user, hide_followers: true) - {:ok, _user} = User.follow(user, other_user) - - conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers") - - assert [] == json_response_and_validate_schema(conn, 200) - end - - test "getting followers, hide_followers, same user requesting" do - user = insert(:user) - other_user = insert(:user, hide_followers: true) - {:ok, _user} = User.follow(user, other_user) - - conn = - build_conn() - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"])) - |> get("/api/v1/accounts/#{other_user.id}/followers") - - refute [] == json_response_and_validate_schema(conn, 200) - end - - test "getting followers, pagination", %{user: user, conn: conn} do - {:ok, %User{id: follower1_id}} = :user |> insert() |> User.follow(user) - {:ok, %User{id: follower2_id}} = :user |> insert() |> User.follow(user) - {:ok, %User{id: follower3_id}} = :user |> insert() |> User.follow(user) - - assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] = - conn - |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}") - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] = - conn - |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}") - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] = - conn - |> get( - "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{ - follower3_id - }" - ) - |> json_response_and_validate_schema(200) - - res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}") - - assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200) - - assert [link_header] = get_resp_header(res_conn, "link") - assert link_header =~ ~r/min_id=#{follower2_id}/ - assert link_header =~ ~r/max_id=#{follower2_id}/ - end - end - - describe "following" do - setup do: oauth_access(["read:accounts"]) - - test "getting following", %{user: user, conn: conn} do - other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) - - conn = get(conn, "/api/v1/accounts/#{user.id}/following") - - assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200) - assert id == to_string(other_user.id) - end - - test "getting following, hide_follows, other user requesting" do - user = insert(:user, hide_follows: true) - other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) - - conn = - build_conn() - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"])) - |> get("/api/v1/accounts/#{user.id}/following") - - assert [] == json_response_and_validate_schema(conn, 200) - end - - test "getting following, hide_follows, same user requesting" do - user = insert(:user, hide_follows: true) - other_user = insert(:user) - {:ok, user} = User.follow(user, other_user) - - conn = - build_conn() - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"])) - |> get("/api/v1/accounts/#{user.id}/following") - - refute [] == json_response_and_validate_schema(conn, 200) - end - - test "getting following, pagination", %{user: user, conn: conn} do - following1 = insert(:user) - following2 = insert(:user) - following3 = insert(:user) - {:ok, _} = User.follow(user, following1) - {:ok, _} = User.follow(user, following2) - {:ok, _} = User.follow(user, following3) - - res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}") - - assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200) - assert id3 == following3.id - assert id2 == following2.id - - res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}") - - assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200) - assert id2 == following2.id - assert id1 == following1.id - - res_conn = - get( - conn, - "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}" - ) - - assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200) - assert id2 == following2.id - assert id1 == following1.id - - res_conn = - get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}") - - assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200) - assert id2 == following2.id - - assert [link_header] = get_resp_header(res_conn, "link") - assert link_header =~ ~r/min_id=#{following2.id}/ - assert link_header =~ ~r/max_id=#{following2.id}/ - end - end - - describe "follow/unfollow" do - setup do: oauth_access(["follow"]) - - test "following / unfollowing a user", %{conn: conn} do - %{id: other_user_id, nickname: other_user_nickname} = insert(:user) - - assert %{"id" => _id, "following" => true} = - conn - |> post("/api/v1/accounts/#{other_user_id}/follow") - |> json_response_and_validate_schema(200) - - assert %{"id" => _id, "following" => false} = - conn - |> post("/api/v1/accounts/#{other_user_id}/unfollow") - |> json_response_and_validate_schema(200) - - assert %{"id" => ^other_user_id} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/follows", %{"uri" => other_user_nickname}) - |> json_response_and_validate_schema(200) - end - - test "cancelling follow request", %{conn: conn} do - %{id: other_user_id} = insert(:user, %{locked: true}) - - assert %{"id" => ^other_user_id, "following" => false, "requested" => true} = - conn - |> post("/api/v1/accounts/#{other_user_id}/follow") - |> json_response_and_validate_schema(:ok) - - assert %{"id" => ^other_user_id, "following" => false, "requested" => false} = - conn - |> post("/api/v1/accounts/#{other_user_id}/unfollow") - |> json_response_and_validate_schema(:ok) - end - - test "following without reblogs" do - %{conn: conn} = oauth_access(["follow", "read:statuses"]) - followed = insert(:user) - other_user = insert(:user) - - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false}) - - assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) - {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed) - - assert [] == - conn - |> get("/api/v1/timelines/home") - |> json_response(200) - - assert %{"showing_reblogs" => true} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true}) - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^reblog_id}] = - conn - |> get("/api/v1/timelines/home") - |> json_response(200) - end - - test "following with reblogs" do - %{conn: conn} = oauth_access(["follow", "read:statuses"]) - followed = insert(:user) - other_user = insert(:user) - - ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow") - - assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) - {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed) - - assert [%{"id" => ^reblog_id}] = - conn - |> get("/api/v1/timelines/home") - |> json_response(200) - - assert %{"showing_reblogs" => false} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false}) - |> json_response_and_validate_schema(200) - - assert [] == - conn - |> get("/api/v1/timelines/home") - |> json_response(200) - end - - test "following / unfollowing errors", %{user: user, conn: conn} do - # self follow - conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow") - - assert %{"error" => "Can not follow yourself"} = - json_response_and_validate_schema(conn_res, 400) - - # self unfollow - user = User.get_cached_by_id(user.id) - conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow") - - assert %{"error" => "Can not unfollow yourself"} = - json_response_and_validate_schema(conn_res, 400) - - # self follow via uri - user = User.get_cached_by_id(user.id) - - assert %{"error" => "Can not follow yourself"} = - conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/follows", %{"uri" => user.nickname}) - |> json_response_and_validate_schema(400) - - # follow non existing user - conn_res = post(conn, "/api/v1/accounts/doesntexist/follow") - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404) - - # follow non existing user via uri - conn_res = - conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/follows", %{"uri" => "doesntexist"}) - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404) - - # unfollow non existing user - conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow") - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404) - end - end - - describe "mute/unmute" do - setup do: oauth_access(["write:mutes"]) - - test "with notifications", %{conn: conn} do - other_user = insert(:user) - - assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = - conn - |> post("/api/v1/accounts/#{other_user.id}/mute") - |> json_response_and_validate_schema(200) - - conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute") - - assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = - json_response_and_validate_schema(conn, 200) - end - - test "without notifications", %{conn: conn} do - other_user = insert(:user) - - ret_conn = - conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"}) - - assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = - json_response_and_validate_schema(ret_conn, 200) - - conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute") - - assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = - json_response_and_validate_schema(conn, 200) - end - end - - describe "pinned statuses" do - setup do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"}) - %{conn: conn} = oauth_access(["read:statuses"], user: user) - - [conn: conn, user: user, activity: activity] - end - - test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do - {:ok, _} = CommonAPI.pin(activity_id, user) - - assert [%{"id" => ^activity_id, "pinned" => true}] = - conn - |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") - |> json_response_and_validate_schema(200) - end - end - - test "blocking / unblocking a user" do - %{conn: conn} = oauth_access(["follow"]) - other_user = insert(:user) - - ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block") - - assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200) - - conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock") - - assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200) - end - - describe "create account by app" do - setup do - valid_params = %{ - username: "lain", - email: "lain@example.org", - password: "PlzDontHackLain", - agreement: true - } - - [valid_params: valid_params] - end - - setup do: clear_config([:instance, :account_activation_required]) - - test "Account registration via Application", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/apps", %{ - client_name: "client_name", - redirect_uris: "urn:ietf:wg:oauth:2.0:oob", - scopes: "read, write, follow" - }) - - assert %{ - "client_id" => client_id, - "client_secret" => client_secret, - "id" => _, - "name" => "client_name", - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "vapid_key" => _, - "website" => nil - } = json_response_and_validate_schema(conn, 200) - - conn = - post(conn, "/oauth/token", %{ - grant_type: "client_credentials", - client_id: client_id, - client_secret: client_secret - }) - - assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} = - json_response(conn, 200) - - assert token - token_from_db = Repo.get_by(Token, token: token) - assert token_from_db - assert refresh - assert scope == "read write follow" - - conn = - build_conn() - |> put_req_header("content-type", "multipart/form-data") - |> put_req_header("authorization", "Bearer " <> token) - |> post("/api/v1/accounts", %{ - username: "lain", - email: "lain@example.org", - password: "PlzDontHackLain", - bio: "Test Bio", - agreement: true - }) - - %{ - "access_token" => token, - "created_at" => _created_at, - "scope" => ^scope, - "token_type" => "Bearer" - } = json_response_and_validate_schema(conn, 200) - - token_from_db = Repo.get_by(Token, token: token) - assert token_from_db - token_from_db = Repo.preload(token_from_db, :user) - assert token_from_db.user - - assert token_from_db.user.confirmation_pending - end - - test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do - _user = insert(:user, email: "lain@example.org") - app_token = insert(:oauth_token, user: nil) - - res = - conn - |> put_req_header("authorization", "Bearer " <> app_token.token) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/accounts", valid_params) - - assert json_response_and_validate_schema(res, 400) == %{ - "error" => "{\"email\":[\"has already been taken\"]}" - } - end - - test "returns bad_request if missing required params", %{ - conn: conn, - valid_params: valid_params - } do - app_token = insert(:oauth_token, user: nil) - - conn = - conn - |> put_req_header("authorization", "Bearer " <> app_token.token) - |> put_req_header("content-type", "application/json") - - res = post(conn, "/api/v1/accounts", valid_params) - assert json_response_and_validate_schema(res, 200) - - [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}] - |> Stream.zip(Map.delete(valid_params, :email)) - |> Enum.each(fn {ip, {attr, _}} -> - res = - conn - |> Map.put(:remote_ip, ip) - |> post("/api/v1/accounts", Map.delete(valid_params, attr)) - |> json_response_and_validate_schema(400) - - assert res == %{ - "error" => "Missing field: #{attr}.", - "errors" => [ - %{ - "message" => "Missing field: #{attr}", - "source" => %{"pointer" => "/#{attr}"}, - "title" => "Invalid value" - } - ] - } - end) - end - - setup do: clear_config([:instance, :account_activation_required]) - - test "returns bad_request if missing email params when :account_activation_required is enabled", - %{conn: conn, valid_params: valid_params} do - Pleroma.Config.put([:instance, :account_activation_required], true) - - app_token = insert(:oauth_token, user: nil) - - conn = - conn - |> put_req_header("authorization", "Bearer " <> app_token.token) - |> put_req_header("content-type", "application/json") - - res = - conn - |> Map.put(:remote_ip, {127, 0, 0, 5}) - |> post("/api/v1/accounts", Map.delete(valid_params, :email)) - - assert json_response_and_validate_schema(res, 400) == - %{"error" => "Missing parameter: email"} - - res = - conn - |> Map.put(:remote_ip, {127, 0, 0, 6}) - |> post("/api/v1/accounts", Map.put(valid_params, :email, "")) - - assert json_response_and_validate_schema(res, 400) == %{ - "error" => "{\"email\":[\"can't be blank\"]}" - } - end - - test "allow registration without an email", %{conn: conn, valid_params: valid_params} do - app_token = insert(:oauth_token, user: nil) - conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token) - - res = - conn - |> put_req_header("content-type", "application/json") - |> Map.put(:remote_ip, {127, 0, 0, 7}) - |> post("/api/v1/accounts", Map.delete(valid_params, :email)) - - assert json_response_and_validate_schema(res, 200) - end - - test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do - app_token = insert(:oauth_token, user: nil) - conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token) - - res = - conn - |> put_req_header("content-type", "application/json") - |> Map.put(:remote_ip, {127, 0, 0, 8}) - |> post("/api/v1/accounts", Map.put(valid_params, :email, "")) - - assert json_response_and_validate_schema(res, 200) - end - - test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do - res = - conn - |> put_req_header("authorization", "Bearer " <> "invalid-token") - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/accounts", valid_params) - - assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"} - end - - test "registration from trusted app" do - clear_config([Pleroma.Captcha, :enabled], true) - app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"]) - - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "client_credentials", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200) - - response = - build_conn() - |> Plug.Conn.put_req_header("authorization", "Bearer " <> token) - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/accounts", %{ - nickname: "nickanme", - agreement: true, - email: "email@example.com", - fullname: "Lain", - username: "Lain", - password: "some_password", - confirm: "some_password" - }) - |> json_response_and_validate_schema(200) - - assert %{ - "access_token" => access_token, - "created_at" => _, - "scope" => "read write follow push", - "token_type" => "Bearer" - } = response - - response = - build_conn() - |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token) - |> get("/api/v1/accounts/verify_credentials") - |> json_response_and_validate_schema(200) - - assert %{ - "acct" => "Lain", - "bot" => false, - "display_name" => "Lain", - "follow_requests_count" => 0, - "followers_count" => 0, - "following_count" => 0, - "locked" => false, - "note" => "", - "source" => %{ - "fields" => [], - "note" => "", - "pleroma" => %{ - "actor_type" => "Person", - "discoverable" => false, - "no_rich_text" => false, - "show_role" => true - }, - "privacy" => "public", - "sensitive" => false - }, - "statuses_count" => 0, - "username" => "Lain" - } = response - end - end - - describe "create account by app / rate limit" do - setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2}) - - test "respects rate limit setting", %{conn: conn} do - app_token = insert(:oauth_token, user: nil) - - conn = - conn - |> put_req_header("authorization", "Bearer " <> app_token.token) - |> Map.put(:remote_ip, {15, 15, 15, 15}) - |> put_req_header("content-type", "multipart/form-data") - - for i <- 1..2 do - conn = - conn - |> post("/api/v1/accounts", %{ - username: "#{i}lain", - email: "#{i}lain@example.org", - password: "PlzDontHackLain", - agreement: true - }) - - %{ - "access_token" => token, - "created_at" => _created_at, - "scope" => _scope, - "token_type" => "Bearer" - } = json_response_and_validate_schema(conn, 200) - - token_from_db = Repo.get_by(Token, token: token) - assert token_from_db - token_from_db = Repo.preload(token_from_db, :user) - assert token_from_db.user - - assert token_from_db.user.confirmation_pending - end - - conn = - post(conn, "/api/v1/accounts", %{ - username: "6lain", - email: "6lain@example.org", - password: "PlzDontHackLain", - agreement: true - }) - - assert json_response_and_validate_schema(conn, :too_many_requests) == %{ - "error" => "Throttled" - } - end - end - - describe "create account with enabled captcha" do - setup %{conn: conn} do - app_token = insert(:oauth_token, user: nil) - - conn = - conn - |> put_req_header("authorization", "Bearer " <> app_token.token) - |> put_req_header("content-type", "multipart/form-data") - - [conn: conn] - end - - setup do: clear_config([Pleroma.Captcha, :enabled], true) - - test "creates an account and returns 200 if captcha is valid", %{conn: conn} do - %{token: token, answer_data: answer_data} = Pleroma.Captcha.new() - - params = %{ - username: "lain", - email: "lain@example.org", - password: "PlzDontHackLain", - agreement: true, - captcha_solution: Pleroma.Captcha.Mock.solution(), - captcha_token: token, - captcha_answer_data: answer_data - } - - assert %{ - "access_token" => access_token, - "created_at" => _, - "scope" => "read", - "token_type" => "Bearer" - } = - conn - |> post("/api/v1/accounts", params) - |> json_response_and_validate_schema(:ok) - - assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user) - - Cachex.del(:used_captcha_cache, token) - end - - test "returns 400 if any captcha field is not provided", %{conn: conn} do - captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data] - - valid_params = %{ - username: "lain", - email: "lain@example.org", - password: "PlzDontHackLain", - agreement: true, - captcha_solution: "xx", - captcha_token: "xx", - captcha_answer_data: "xx" - } - - for field <- captcha_fields do - expected = %{ - "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}" - } - - assert expected == - conn - |> post("/api/v1/accounts", Map.delete(valid_params, field)) - |> json_response_and_validate_schema(:bad_request) - end - end - - test "returns an error if captcha is invalid", %{conn: conn} do - params = %{ - username: "lain", - email: "lain@example.org", - password: "PlzDontHackLain", - agreement: true, - captcha_solution: "cofe", - captcha_token: "cofe", - captcha_answer_data: "cofe" - } - - assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} == - conn - |> post("/api/v1/accounts", params) - |> json_response_and_validate_schema(:bad_request) - end - end - - describe "GET /api/v1/accounts/:id/lists - account_lists" do - test "returns lists to which the account belongs" do - %{user: user, conn: conn} = oauth_access(["read:lists"]) - other_user = insert(:user) - assert {:ok, %Pleroma.List{id: list_id} = list} = Pleroma.List.create("Test List", user) - {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) - - assert [%{"id" => list_id, "title" => "Test List"}] = - conn - |> get("/api/v1/accounts/#{other_user.id}/lists") - |> json_response_and_validate_schema(200) - end - end - - describe "verify_credentials" do - test "verify_credentials" do - %{user: user, conn: conn} = oauth_access(["read:accounts"]) - [notification | _] = insert_list(7, :notification, user: user) - Pleroma.Notification.set_read_up_to(user, notification.id) - conn = get(conn, "/api/v1/accounts/verify_credentials") - - response = json_response_and_validate_schema(conn, 200) - - assert %{"id" => id, "source" => %{"privacy" => "public"}} = response - assert response["pleroma"]["chat_token"] - assert response["pleroma"]["unread_notifications_count"] == 6 - assert id == to_string(user.id) - end - - test "verify_credentials default scope unlisted" do - user = insert(:user, default_scope: "unlisted") - %{conn: conn} = oauth_access(["read:accounts"], user: user) - - conn = get(conn, "/api/v1/accounts/verify_credentials") - - assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = - json_response_and_validate_schema(conn, 200) - - assert id == to_string(user.id) - end - - test "locked accounts" do - user = insert(:user, default_scope: "private") - %{conn: conn} = oauth_access(["read:accounts"], user: user) - - conn = get(conn, "/api/v1/accounts/verify_credentials") - - assert %{"id" => id, "source" => %{"privacy" => "private"}} = - json_response_and_validate_schema(conn, 200) - - assert id == to_string(user.id) - end - end - - describe "user relationships" do - setup do: oauth_access(["read:follows"]) - - test "returns the relationships for the current user", %{user: user, conn: conn} do - %{id: other_user_id} = other_user = insert(:user) - {:ok, _user} = User.follow(user, other_user) - - assert [%{"id" => ^other_user_id}] = - conn - |> get("/api/v1/accounts/relationships?id=#{other_user.id}") - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^other_user_id}] = - conn - |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}") - |> json_response_and_validate_schema(200) - end - - test "returns an empty list on a bad request", %{conn: conn} do - conn = get(conn, "/api/v1/accounts/relationships", %{}) - - assert [] = json_response_and_validate_schema(conn, 200) - end - end - - test "getting a list of mutes" do - %{user: user, conn: conn} = oauth_access(["read:mutes"]) - other_user = insert(:user) - - {:ok, _user_relationships} = User.mute(user, other_user) - - conn = get(conn, "/api/v1/mutes") - - other_user_id = to_string(other_user.id) - assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200) - end - - test "getting a list of blocks" do - %{user: user, conn: conn} = oauth_access(["read:blocks"]) - other_user = insert(:user) - - {:ok, _user_relationship} = User.block(user, other_user) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/blocks") - - other_user_id = to_string(other_user.id) - assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200) - end -end diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/web/mastodon_api/controllers/app_controller_test.exs deleted file mode 100644 index a0b8b126c..000000000 --- a/test/web/mastodon_api/controllers/app_controller_test.exs +++ /dev/null @@ -1,60 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.AppControllerTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Repo - alias Pleroma.Web.OAuth.App - alias Pleroma.Web.Push - - import Pleroma.Factory - - test "apps/verify_credentials", %{conn: conn} do - token = insert(:oauth_token) - - conn = - conn - |> put_req_header("authorization", "Bearer #{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_and_validate_schema(conn, 200) - end - - test "creates an oauth app", %{conn: conn} do - user = insert(:user) - app_attrs = build(:oauth_app) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> assign(:user, user) - |> post("/api/v1/apps", %{ - client_name: app_attrs.client_name, - redirect_uris: app_attrs.redirect_uris - }) - - [app] = Repo.all(App) - - expected = %{ - "name" => app.client_name, - "website" => app.website, - "client_id" => app.client_id, - "client_secret" => app.client_secret, - "id" => app.id |> to_string(), - "redirect_uri" => app.redirect_uris, - "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key) - } - - assert expected == json_response_and_validate_schema(conn, 200) - end -end diff --git a/test/web/mastodon_api/controllers/auth_controller_test.exs b/test/web/mastodon_api/controllers/auth_controller_test.exs deleted file mode 100644 index a485f8e41..000000000 --- a/test/web/mastodon_api/controllers/auth_controller_test.exs +++ /dev/null @@ -1,152 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - - import Pleroma.Factory - import Swoosh.TestAssertions - - describe "GET /web/login" do - setup %{conn: conn} do - session_opts = [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - - conn = - conn - |> Plug.Session.call(Plug.Session.init(session_opts)) - |> fetch_session() - - test_path = "/web/statuses/test" - %{conn: conn, path: test_path} - end - - test "redirects to the saved path after log in", %{conn: conn, path: path} do - app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") - auth = insert(:oauth_authorization, app: app) - - conn = - conn - |> put_session(:return_to, path) - |> get("/web/login", %{code: auth.token}) - - assert conn.status == 302 - assert redirected_to(conn) == path - end - - test "redirects to the getting-started page when referer is not present", %{conn: conn} do - app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".") - auth = insert(:oauth_authorization, app: app) - - conn = get(conn, "/web/login", %{code: auth.token}) - - assert conn.status == 302 - assert redirected_to(conn) == "/web/getting-started" - end - end - - describe "POST /auth/password, with valid parameters" do - setup %{conn: conn} do - user = insert(:user) - conn = post(conn, "/auth/password?email=#{user.email}") - %{conn: conn, user: user} - end - - test "it returns 204", %{conn: conn} do - assert json_response(conn, :no_content) - end - - test "it creates a PasswordResetToken record for user", %{user: user} do - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - assert token_record - end - - test "it sends an email to user", %{user: user} do - ObanHelpers.perform_all() - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - - email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - end - - describe "POST /auth/password, with nickname" do - test "it returns 204", %{conn: conn} do - user = insert(:user) - - assert conn - |> post("/auth/password?nickname=#{user.nickname}") - |> json_response(:no_content) - - ObanHelpers.perform_all() - token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - - email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - - test "it doesn't fail when a user has no email", %{conn: conn} do - user = insert(:user, %{email: nil}) - - assert conn - |> post("/auth/password?nickname=#{user.nickname}") - |> json_response(:no_content) - end - end - - describe "POST /auth/password, with invalid parameters" do - setup do - user = insert(:user) - {:ok, user: user} - end - - test "it returns 404 when user is not found", %{conn: conn, user: user} do - conn = post(conn, "/auth/password?email=nonexisting_#{user.email}") - assert conn.status == 404 - assert conn.resp_body == "" - end - - test "it returns 400 when user is not local", %{conn: conn, user: user} do - {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false)) - conn = post(conn, "/auth/password?email=#{user.email}") - assert conn.status == 400 - assert conn.resp_body == "" - end - end - - describe "DELETE /auth/sign_out" do - test "redirect to root page", %{conn: conn} do - user = insert(:user) - - conn = - conn - |> assign(:user, user) - |> delete("/auth/sign_out") - - assert conn.status == 302 - assert redirected_to(conn) == "/" - end - end -end diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs deleted file mode 100644 index 3e21e6bf1..000000000 --- a/test/web/mastodon_api/controllers/conversation_controller_test.exs +++ /dev/null @@ -1,209 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - setup do: oauth_access(["read:statuses"]) - - describe "returns a list of conversations" do - setup(%{user: user_one, conn: conn}) do - user_two = insert(:user) - user_three = insert(:user) - - {:ok, user_two} = User.follow(user_two, user_one) - - {:ok, %{user: user_one, user_two: user_two, user_three: user_three, conn: conn}} - end - - test "returns correct conversations", %{ - user: user_one, - user_two: user_two, - user_three: user_three, - conn: conn - } do - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 - {:ok, direct} = create_direct_message(user_one, [user_two, user_three]) - - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 - - {:ok, _follower_only} = - CommonAPI.post(user_one, %{ - status: "Hi @#{user_two.nickname}!", - visibility: "private" - }) - - res_conn = get(conn, "/api/v1/conversations") - - assert response = json_response_and_validate_schema(res_conn, 200) - - assert [ - %{ - "id" => res_id, - "accounts" => res_accounts, - "last_status" => res_last_status, - "unread" => unread - } - ] = 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 == false - assert res_last_status["id"] == direct.id - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 - end - - test "observes limit params", %{ - user: user_one, - user_two: user_two, - user_three: user_three, - conn: conn - } do - {:ok, _} = create_direct_message(user_one, [user_two, user_three]) - {:ok, _} = create_direct_message(user_two, [user_one, user_three]) - {:ok, _} = create_direct_message(user_three, [user_two, user_one]) - - res_conn = get(conn, "/api/v1/conversations?limit=1") - - assert response = json_response_and_validate_schema(res_conn, 200) - - assert Enum.count(response) == 1 - - res_conn = get(conn, "/api/v1/conversations?limit=2") - - assert response = json_response_and_validate_schema(res_conn, 200) - - assert Enum.count(response) == 2 - end - end - - test "filters conversations by recipients", %{user: user_one, conn: conn} do - user_two = insert(:user) - user_three = insert(:user) - {:ok, direct1} = create_direct_message(user_one, [user_two]) - {:ok, _direct2} = create_direct_message(user_one, [user_three]) - {:ok, direct3} = create_direct_message(user_one, [user_two, user_three]) - {:ok, _direct4} = create_direct_message(user_two, [user_three]) - {:ok, direct5} = create_direct_message(user_two, [user_one]) - - assert [conversation1, conversation2] = - conn - |> get("/api/v1/conversations?recipients[]=#{user_two.id}") - |> json_response_and_validate_schema(200) - - assert conversation1["last_status"]["id"] == direct5.id - assert conversation2["last_status"]["id"] == direct1.id - - [conversation1] = - conn - |> get("/api/v1/conversations?recipients[]=#{user_two.id}&recipients[]=#{user_three.id}") - |> json_response_and_validate_schema(200) - - assert conversation1["last_status"]["id"] == direct3.id - end - - test "updates the last_status on reply", %{user: user_one, conn: conn} do - user_two = insert(:user) - {:ok, direct} = create_direct_message(user_one, [user_two]) - - {:ok, direct_reply} = - CommonAPI.post(user_two, %{ - status: "reply", - visibility: "direct", - in_reply_to_status_id: direct.id - }) - - [%{"last_status" => res_last_status}] = - conn - |> get("/api/v1/conversations") - |> json_response_and_validate_schema(200) - - assert res_last_status["id"] == direct_reply.id - end - - test "the user marks a conversation as read", %{user: user_one, conn: conn} do - user_two = insert(:user) - {:ok, direct} = create_direct_message(user_one, [user_two]) - - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1 - - user_two_conn = - build_conn() - |> assign(:user, user_two) - |> assign( - :token, - insert(:oauth_token, user: user_two, scopes: ["read:statuses", "write:conversations"]) - ) - - [%{"id" => direct_conversation_id, "unread" => true}] = - user_two_conn - |> get("/api/v1/conversations") - |> json_response_and_validate_schema(200) - - %{"unread" => false} = - user_two_conn - |> post("/api/v1/conversations/#{direct_conversation_id}/read") - |> json_response_and_validate_schema(200) - - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 - - # The conversation is marked as unread on reply - {:ok, _} = - CommonAPI.post(user_two, %{ - status: "reply", - visibility: "direct", - in_reply_to_status_id: direct.id - }) - - [%{"unread" => true}] = - conn - |> get("/api/v1/conversations") - |> json_response_and_validate_schema(200) - - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 - - # A reply doesn't increment the user's unread_conversation_count if the conversation is unread - {:ok, _} = - CommonAPI.post(user_two, %{ - status: "reply", - visibility: "direct", - in_reply_to_status_id: direct.id - }) - - assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1 - assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0 - end - - test "(vanilla) Mastodon frontend behaviour", %{user: user_one, conn: conn} do - user_two = insert(:user) - {:ok, direct} = create_direct_message(user_one, [user_two]) - - res_conn = get(conn, "/api/v1/statuses/#{direct.id}/context") - - assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) - end - - defp create_direct_message(sender, recips) do - hellos = - recips - |> Enum.map(fn s -> "@#{s.nickname}" end) - |> Enum.join(", ") - - CommonAPI.post(sender, %{ - status: "Hi #{hellos}!", - visibility: "direct" - }) - end -end diff --git a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs b/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs deleted file mode 100644 index ab0027f90..000000000 --- a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs +++ /dev/null @@ -1,23 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do - use Pleroma.Web.ConnCase, async: true - - test "with tags", %{conn: conn} do - assert resp = - conn - |> get("/api/v1/custom_emojis") - |> json_response_and_validate_schema(200) - - assert [emoji | _body] = resp - assert Map.has_key?(emoji, "shortcode") - 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 -end diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/web/mastodon_api/controllers/domain_block_controller_test.exs deleted file mode 100644 index 664654500..000000000 --- a/test/web/mastodon_api/controllers/domain_block_controller_test.exs +++ /dev/null @@ -1,79 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.User - - import Pleroma.Factory - - test "blocking / unblocking a domain" do - %{user: user, conn: conn} = oauth_access(["write:blocks"]) - other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) - - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - - assert %{} == json_response_and_validate_schema(ret_conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - assert User.blocks?(user, other_user) - - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - - assert %{} == json_response_and_validate_schema(ret_conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - refute User.blocks?(user, other_user) - end - - test "blocking a domain via query params" do - %{user: user, conn: conn} = oauth_access(["write:blocks"]) - other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) - - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/domain_blocks?domain=dogwhistle.zone") - - assert %{} == json_response_and_validate_schema(ret_conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - assert User.blocks?(user, other_user) - end - - test "unblocking a domain via query params" do - %{user: user, conn: conn} = oauth_access(["write:blocks"]) - other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) - - User.block_domain(user, "dogwhistle.zone") - user = refresh_record(user) - assert User.blocks?(user, other_user) - - ret_conn = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/v1/domain_blocks?domain=dogwhistle.zone") - - assert %{} == json_response_and_validate_schema(ret_conn, 200) - user = User.get_cached_by_ap_id(user.ap_id) - refute User.blocks?(user, other_user) - end - - test "getting a list of domain blocks" do - %{user: user, conn: conn} = oauth_access(["read:blocks"]) - - {:ok, user} = User.block_domain(user, "bad.site") - {:ok, user} = User.block_domain(user, "even.worse.site") - - assert ["even.worse.site", "bad.site"] == - conn - |> assign(:user, user) - |> get("/api/v1/domain_blocks") - |> json_response_and_validate_schema(200) - end -end diff --git a/test/web/mastodon_api/controllers/filter_controller_test.exs b/test/web/mastodon_api/controllers/filter_controller_test.exs deleted file mode 100644 index f29547d13..000000000 --- a/test/web/mastodon_api/controllers/filter_controller_test.exs +++ /dev/null @@ -1,129 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.MastodonAPI.FilterView - - test "creating a filter" do - %{conn: conn} = oauth_access(["write:filters"]) - - filter = %Pleroma.Filter{ - phrase: "knights", - context: ["home"] - } - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) - - assert response = json_response_and_validate_schema(conn, 200) - assert response["phrase"] == filter.phrase - assert response["context"] == filter.context - assert response["irreversible"] == false - assert response["id"] != nil - assert response["id"] != "" - end - - test "fetching a list of filters" do - %{user: user, conn: conn} = oauth_access(["read:filters"]) - - query_one = %Pleroma.Filter{ - user_id: user.id, - filter_id: 1, - phrase: "knights", - context: ["home"] - } - - query_two = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "who", - context: ["home"] - } - - {:ok, filter_one} = Pleroma.Filter.create(query_one) - {:ok, filter_two} = Pleroma.Filter.create(query_two) - - response = - conn - |> get("/api/v1/filters") - |> json_response_and_validate_schema(200) - - assert response == - render_json( - FilterView, - "index.json", - filters: [filter_two, filter_one] - ) - end - - test "get a filter" do - %{user: user, conn: conn} = oauth_access(["read:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = get(conn, "/api/v1/filters/#{filter.filter_id}") - - assert response = json_response_and_validate_schema(conn, 200) - end - - test "update a filter" do - %{user: user, conn: conn} = oauth_access(["write:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"], - hide: true - } - - {:ok, _filter} = Pleroma.Filter.create(query) - - new = %Pleroma.Filter{ - phrase: "nii", - context: ["home"] - } - - conn = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/filters/#{query.filter_id}", %{ - phrase: new.phrase, - context: new.context - }) - - assert response = json_response_and_validate_schema(conn, 200) - assert response["phrase"] == new.phrase - assert response["context"] == new.context - assert response["irreversible"] == true - end - - test "delete a filter" do - %{user: user, conn: conn} = oauth_access(["write:filters"]) - - query = %Pleroma.Filter{ - user_id: user.id, - filter_id: 2, - phrase: "knight", - context: ["home"] - } - - {:ok, filter} = Pleroma.Filter.create(query) - - conn = delete(conn, "/api/v1/filters/#{filter.filter_id}") - - assert json_response_and_validate_schema(conn, 200) == %{} - end -end diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs deleted file mode 100644 index 6749e0e83..000000000 --- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs +++ /dev/null @@ -1,74 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "locked accounts" do - setup do - user = insert(:user, locked: true) - %{conn: conn} = oauth_access(["follow"], user: user) - %{user: user, conn: conn} - end - - test "/api/v1/follow_requests works", %{user: user, conn: conn} do - other_user = insert(:user) - - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) - {:ok, other_user} = User.follow(other_user, user, :follow_pending) - - assert User.following?(other_user, user) == false - - conn = get(conn, "/api/v1/follow_requests") - - assert [relationship] = json_response_and_validate_schema(conn, 200) - assert to_string(other_user.id) == relationship["id"] - end - - test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do - other_user = insert(:user) - - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) - {:ok, other_user} = User.follow(other_user, user, :follow_pending) - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == false - - conn = post(conn, "/api/v1/follow_requests/#{other_user.id}/authorize") - - assert relationship = json_response_and_validate_schema(conn, 200) - assert to_string(other_user.id) == relationship["id"] - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == true - end - - test "/api/v1/follow_requests/:id/reject works", %{user: user, conn: conn} do - other_user = insert(:user) - - {:ok, _, _, _activity} = CommonAPI.follow(other_user, user) - - user = User.get_cached_by_id(user.id) - - conn = post(conn, "/api/v1/follow_requests/#{other_user.id}/reject") - - assert relationship = json_response_and_validate_schema(conn, 200) - assert to_string(other_user.id) == relationship["id"] - - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - assert User.following?(other_user, user) == false - end - end -end diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/web/mastodon_api/controllers/instance_controller_test.exs deleted file mode 100644 index cc880d82c..000000000 --- a/test/web/mastodon_api/controllers/instance_controller_test.exs +++ /dev/null @@ -1,86 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.User - import Pleroma.Factory - - test "get instance information", %{conn: conn} do - conn = get(conn, "/api/v1/instance") - assert result = json_response_and_validate_schema(conn, 200) - - email = Pleroma.Config.get([:instance, :email]) - # Note: not checking for "max_toot_chars" since it's optional - assert %{ - "uri" => _, - "title" => _, - "description" => _, - "version" => _, - "email" => from_config_email, - "urls" => %{ - "streaming_api" => _ - }, - "stats" => _, - "thumbnail" => _, - "languages" => _, - "registrations" => _, - "poll_limits" => _, - "upload_limit" => _, - "avatar_upload_limit" => _, - "background_upload_limit" => _, - "banner_upload_limit" => _, - "background_image" => _, - "chat_limit" => _, - "description_limit" => _ - } = result - - assert result["pleroma"]["metadata"]["account_activation_required"] != nil - assert result["pleroma"]["metadata"]["features"] - assert result["pleroma"]["metadata"]["federation"] - assert result["pleroma"]["metadata"]["fields_limits"] - assert result["pleroma"]["vapid_public_key"] - - assert email == from_config_email - end - - test "get instance stats", %{conn: conn} do - user = insert(:user, %{local: true}) - - user2 = insert(:user, %{local: true}) - {:ok, _user2} = User.deactivate(user2, !user2.deactivated) - - insert(:user, %{local: false, nickname: "u@peer1.com"}) - insert(:user, %{local: false, nickname: "u@peer2.com"}) - - {:ok, _} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) - - Pleroma.Stats.force_update() - - conn = get(conn, "/api/v1/instance") - - assert result = json_response_and_validate_schema(conn, 200) - - stats = result["stats"] - - assert stats - assert stats["user_count"] == 1 - assert stats["status_count"] == 1 - assert stats["domain_count"] == 2 - end - - test "get peers", %{conn: conn} do - insert(:user, %{local: false, nickname: "u@peer1.com"}) - insert(:user, %{local: false, nickname: "u@peer2.com"}) - - Pleroma.Stats.force_update() - - conn = get(conn, "/api/v1/instance/peers") - - assert result = json_response_and_validate_schema(conn, 200) - - assert ["peer1.com", "peer2.com"] == Enum.sort(result) - end -end diff --git a/test/web/mastodon_api/controllers/list_controller_test.exs b/test/web/mastodon_api/controllers/list_controller_test.exs deleted file mode 100644 index 57a9ef4a4..000000000 --- a/test/web/mastodon_api/controllers/list_controller_test.exs +++ /dev/null @@ -1,158 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ListControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Repo - - import Pleroma.Factory - - test "creating a list" do - %{conn: conn} = oauth_access(["write:lists"]) - - assert %{"title" => "cuties"} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists", %{"title" => "cuties"}) - |> json_response_and_validate_schema(:ok) - end - - test "renders error for invalid params" do - %{conn: conn} = oauth_access(["write:lists"]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists", %{"title" => nil}) - - assert %{"error" => "title - null value where string expected."} = - json_response_and_validate_schema(conn, 400) - end - - test "listing a user's lists" do - %{conn: conn} = oauth_access(["read:lists", "write:lists"]) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists", %{"title" => "cuties"}) - |> json_response_and_validate_schema(:ok) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists", %{"title" => "cofe"}) - |> json_response_and_validate_schema(:ok) - - conn = get(conn, "/api/v1/lists") - - assert [ - %{"id" => _, "title" => "cofe"}, - %{"id" => _, "title" => "cuties"} - ] = json_response_and_validate_schema(conn, :ok) - end - - test "adding users to a list" do - %{user: user, conn: conn} = oauth_access(["write:lists"]) - other_user = insert(:user) - {:ok, list} = Pleroma.List.create("name", user) - - assert %{} == - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]}) - |> json_response_and_validate_schema(:ok) - - %Pleroma.List{following: following} = Pleroma.List.get(list.id, user) - assert following == [other_user.follower_address] - end - - test "removing users from a list" do - %{user: user, conn: conn} = oauth_access(["write:lists"]) - other_user = insert(:user) - third_user = insert(:user) - {:ok, list} = Pleroma.List.create("name", user) - {:ok, list} = Pleroma.List.follow(list, other_user) - {:ok, list} = Pleroma.List.follow(list, third_user) - - assert %{} == - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]}) - |> json_response_and_validate_schema(:ok) - - %Pleroma.List{following: following} = Pleroma.List.get(list.id, user) - assert following == [third_user.follower_address] - end - - test "listing users in a list" do - %{user: user, conn: conn} = oauth_access(["read:lists"]) - other_user = insert(:user) - {:ok, list} = Pleroma.List.create("name", user) - {:ok, list} = Pleroma.List.follow(list, other_user) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]}) - - assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200) - assert id == to_string(other_user.id) - end - - test "retrieving a list" do - %{user: user, conn: conn} = oauth_access(["read:lists"]) - {:ok, list} = Pleroma.List.create("name", user) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/lists/#{list.id}") - - assert %{"id" => id} = json_response_and_validate_schema(conn, 200) - assert id == to_string(list.id) - end - - test "renders 404 if list is not found" do - %{conn: conn} = oauth_access(["read:lists"]) - - conn = get(conn, "/api/v1/lists/666") - - assert %{"error" => "List not found"} = json_response_and_validate_schema(conn, :not_found) - end - - test "renaming a list" do - %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create("name", user) - - assert %{"title" => "newname"} = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"}) - |> json_response_and_validate_schema(:ok) - end - - test "validates title when renaming a list" do - %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create("name", user) - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/json") - |> put("/api/v1/lists/#{list.id}", %{"title" => " "}) - - assert %{"error" => "can't be blank"} == - json_response_and_validate_schema(conn, :unprocessable_entity) - end - - test "deleting a list" do - %{user: user, conn: conn} = oauth_access(["write:lists"]) - {:ok, list} = Pleroma.List.create("name", user) - - conn = delete(conn, "/api/v1/lists/#{list.id}") - - assert %{} = json_response_and_validate_schema(conn, 200) - assert is_nil(Repo.get(Pleroma.List, list.id)) - end -end diff --git a/test/web/mastodon_api/controllers/marker_controller_test.exs b/test/web/mastodon_api/controllers/marker_controller_test.exs deleted file mode 100644 index 6dd40fb4a..000000000 --- a/test/web/mastodon_api/controllers/marker_controller_test.exs +++ /dev/null @@ -1,131 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - describe "GET /api/v1/markers" do - test "gets markers with correct scopes", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: ["read:statuses"]) - insert_list(7, :notification, user: user) - - {:ok, %{"notifications" => marker}} = - Pleroma.Marker.upsert( - user, - %{"notifications" => %{"last_read_id" => "69420"}} - ) - - response = - conn - |> assign(:user, user) - |> assign(:token, token) - |> get("/api/v1/markers?timeline[]=notifications") - |> json_response_and_validate_schema(200) - - assert response == %{ - "notifications" => %{ - "last_read_id" => "69420", - "updated_at" => NaiveDateTime.to_iso8601(marker.updated_at), - "version" => 0, - "pleroma" => %{"unread_count" => 7} - } - } - end - - test "gets markers with missed scopes", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: []) - - Pleroma.Marker.upsert(user, %{"notifications" => %{"last_read_id" => "69420"}}) - - response = - conn - |> assign(:user, user) - |> assign(:token, token) - |> get("/api/v1/markers", %{timeline: ["notifications"]}) - |> json_response_and_validate_schema(403) - - assert response == %{"error" => "Insufficient permissions: read:statuses."} - end - end - - describe "POST /api/v1/markers" do - test "creates a marker with correct scopes", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: ["write:statuses"]) - - response = - conn - |> assign(:user, user) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/markers", %{ - home: %{last_read_id: "777"}, - notifications: %{"last_read_id" => "69420"} - }) - |> json_response_and_validate_schema(200) - - assert %{ - "notifications" => %{ - "last_read_id" => "69420", - "updated_at" => _, - "version" => 0, - "pleroma" => %{"unread_count" => 0} - } - } = response - end - - test "updates exist marker", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: ["write:statuses"]) - - {:ok, %{"notifications" => marker}} = - Pleroma.Marker.upsert( - user, - %{"notifications" => %{"last_read_id" => "69477"}} - ) - - response = - conn - |> assign(:user, user) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/markers", %{ - home: %{last_read_id: "777"}, - notifications: %{"last_read_id" => "69888"} - }) - |> json_response_and_validate_schema(200) - - assert response == %{ - "notifications" => %{ - "last_read_id" => "69888", - "updated_at" => NaiveDateTime.to_iso8601(marker.updated_at), - "version" => 0, - "pleroma" => %{"unread_count" => 0} - } - } - end - - test "creates a marker with missed scopes", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: []) - - response = - conn - |> assign(:user, user) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/markers", %{ - home: %{last_read_id: "777"}, - notifications: %{"last_read_id" => "69420"} - }) - |> json_response_and_validate_schema(403) - - assert response == %{"error" => "Insufficient permissions: write:statuses."} - end - end -end diff --git a/test/web/mastodon_api/controllers/media_controller_test.exs b/test/web/mastodon_api/controllers/media_controller_test.exs deleted file mode 100644 index 906fd940f..000000000 --- a/test/web/mastodon_api/controllers/media_controller_test.exs +++ /dev/null @@ -1,146 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - - describe "Upload media" do - setup do: oauth_access(["write:media"]) - - setup do - image = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - [image: image] - end - - setup do: clear_config([:media_proxy]) - setup do: clear_config([Pleroma.Upload]) - - test "/api/v1/media", %{conn: conn, image: image} do - desc = "Description of the image" - - media = - conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v1/media", %{"file" => image, "description" => desc}) - |> json_response_and_validate_schema(:ok) - - assert media["type"] == "image" - assert media["description"] == desc - assert media["id"] - - object = Object.get_by_id(media["id"]) - assert object.data["actor"] == User.ap_id(conn.assigns[:user]) - end - - test "/api/v2/media", %{conn: conn, user: user, image: image} do - desc = "Description of the image" - - response = - conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/v2/media", %{"file" => image, "description" => desc}) - |> json_response_and_validate_schema(202) - - assert media_id = response["id"] - - %{conn: conn} = oauth_access(["read:media"], user: user) - - media = - conn - |> get("/api/v1/media/#{media_id}") - |> json_response_and_validate_schema(200) - - assert media["type"] == "image" - assert media["description"] == desc - assert media["id"] - - object = Object.get_by_id(media["id"]) - assert object.data["actor"] == user.ap_id - end - end - - describe "Update media description" do - setup do: oauth_access(["write:media"]) - - setup %{user: actor} do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, %Object{} = object} = - ActivityPub.upload( - file, - actor: User.ap_id(actor), - description: "test-m" - ) - - [object: object] - end - - test "/api/v1/media/:id good request", %{conn: conn, object: object} do - media = - conn - |> put_req_header("content-type", "multipart/form-data") - |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"}) - |> json_response_and_validate_schema(:ok) - - assert media["description"] == "test-media" - assert refresh_record(object).data["name"] == "test-media" - end - end - - describe "Get media by id (/api/v1/media/:id)" do - setup do: oauth_access(["read:media"]) - - setup %{user: actor} do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, %Object{} = object} = - ActivityPub.upload( - file, - actor: User.ap_id(actor), - description: "test-media" - ) - - [object: object] - end - - test "it returns media object when requested by owner", %{conn: conn, object: object} do - media = - conn - |> get("/api/v1/media/#{object.id}") - |> json_response_and_validate_schema(:ok) - - assert media["description"] == "test-media" - assert media["type"] == "image" - assert media["id"] - end - - test "it returns 403 if media object requested by non-owner", %{object: object, user: user} do - %{conn: conn, user: other_user} = oauth_access(["read:media"]) - - assert object.data["actor"] == user.ap_id - refute user.id == other_user.id - - conn - |> get("/api/v1/media/#{object.id}") - |> json_response(403) - end - end -end diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs deleted file mode 100644 index 70ef0e8b5..000000000 --- a/test/web/mastodon_api/controllers/notification_controller_test.exs +++ /dev/null @@ -1,626 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Notification - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "does NOT render account/pleroma/relationship by default" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, [_notification]} = Notification.create_notifications(activity) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/notifications") - |> json_response_and_validate_schema(200) - - assert Enum.all?(response, fn n -> - get_in(n, ["account", "pleroma", "relationship"]) == %{} - end) - end - - test "list of notifications" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - {:ok, [_notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/notifications") - - expected_response = - "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{ - user.ap_id - }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" - - assert [%{"status" => %{"content" => response}} | _rest] = - json_response_and_validate_schema(conn, 200) - - assert response == expected_response - end - - test "by default, does not contain pleroma:chat_mention" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, _activity} = CommonAPI.post_chat_message(other_user, user, "hey") - - result = - conn - |> get("/api/v1/notifications") - |> json_response_and_validate_schema(200) - - assert [] == result - - result = - conn - |> get("/api/v1/notifications?include_types[]=pleroma:chat_mention") - |> json_response_and_validate_schema(200) - - assert [_] = result - end - - test "getting a single notification" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - {:ok, [notification]} = Notification.create_notifications(activity) - - conn = get(conn, "/api/v1/notifications/#{notification.id}") - - expected_response = - "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{ - user.ap_id - }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" - - assert %{"status" => %{"content" => response}} = json_response_and_validate_schema(conn, 200) - assert response == expected_response - end - - test "dismissing a single notification (deprecated endpoint)" do - %{user: user, conn: conn} = oauth_access(["write:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - {:ok, [notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/notifications/dismiss", %{"id" => to_string(notification.id)}) - - assert %{} = json_response_and_validate_schema(conn, 200) - end - - test "dismissing a single notification" do - %{user: user, conn: conn} = oauth_access(["write:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - {:ok, [notification]} = Notification.create_notifications(activity) - - conn = - conn - |> assign(:user, user) - |> post("/api/v1/notifications/#{notification.id}/dismiss") - - assert %{} = json_response_and_validate_schema(conn, 200) - end - - test "clearing all notifications" do - %{user: user, conn: conn} = oauth_access(["write:notifications", "read:notifications"]) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - {:ok, [_notification]} = Notification.create_notifications(activity) - - ret_conn = post(conn, "/api/v1/notifications/clear") - - assert %{} = json_response_and_validate_schema(ret_conn, 200) - - ret_conn = get(conn, "/api/v1/notifications") - - assert all = json_response_and_validate_schema(ret_conn, 200) - assert all == [] - end - - test "paginates notifications using min_id, since_id, max_id, and limit" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, activity3} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, activity4} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - notification1_id = get_notification_id_by_activity(activity1) - notification2_id = get_notification_id_by_activity(activity2) - notification3_id = get_notification_id_by_activity(activity3) - notification4_id = get_notification_id_by_activity(activity4) - - conn = assign(conn, :user, user) - - # min_id - result = - conn - |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - - # since_id - result = - conn - |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - # max_id - result = - conn - |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - end - - describe "exclude_visibilities" do - test "filters notifications for mentions" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, public_activity} = - CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "public"}) - - {:ok, direct_activity} = - CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"}) - - {:ok, unlisted_activity} = - CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "unlisted"}) - - {:ok, private_activity} = - CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "private"}) - - query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "private"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200) - assert id == direct_activity.id - - query = params_to_query(%{exclude_visibilities: ["public", "unlisted", "direct"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200) - assert id == private_activity.id - - query = params_to_query(%{exclude_visibilities: ["public", "private", "direct"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200) - assert id == unlisted_activity.id - - query = params_to_query(%{exclude_visibilities: ["unlisted", "private", "direct"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"status" => %{"id" => id}}] = json_response_and_validate_schema(conn_res, 200) - assert id == public_activity.id - end - - test "filters notifications for Like activities" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["read:notifications"]) - - {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"}) - - {:ok, direct_activity} = - CommonAPI.post(other_user, %{status: "@#{user.nickname}", visibility: "direct"}) - - {:ok, unlisted_activity} = - CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"}) - - {:ok, private_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "private"}) - - {:ok, _} = CommonAPI.favorite(user, public_activity.id) - {:ok, _} = CommonAPI.favorite(user, direct_activity.id) - {:ok, _} = CommonAPI.favorite(user, unlisted_activity.id) - {:ok, _} = CommonAPI.favorite(user, private_activity.id) - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=direct") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - assert public_activity.id in activity_ids - assert unlisted_activity.id in activity_ids - assert private_activity.id in activity_ids - refute direct_activity.id in activity_ids - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=unlisted") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - assert public_activity.id in activity_ids - refute unlisted_activity.id in activity_ids - assert private_activity.id in activity_ids - assert direct_activity.id in activity_ids - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=private") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - assert public_activity.id in activity_ids - assert unlisted_activity.id in activity_ids - refute private_activity.id in activity_ids - assert direct_activity.id in activity_ids - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=public") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - refute public_activity.id in activity_ids - assert unlisted_activity.id in activity_ids - assert private_activity.id in activity_ids - assert direct_activity.id in activity_ids - end - - test "filters notifications for Announce activities" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["read:notifications"]) - - {:ok, public_activity} = CommonAPI.post(other_user, %{status: ".", visibility: "public"}) - - {:ok, unlisted_activity} = - CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"}) - - {:ok, _} = CommonAPI.repeat(public_activity.id, user) - {:ok, _} = CommonAPI.repeat(unlisted_activity.id, user) - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=unlisted") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - assert public_activity.id in activity_ids - refute unlisted_activity.id in activity_ids - end - - test "doesn't return less than the requested amount of records when the user's reply is liked" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["read:notifications"]) - - {:ok, mention} = - CommonAPI.post(user, %{status: "@#{other_user.nickname}", visibility: "public"}) - - {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - - {:ok, reply} = - CommonAPI.post(other_user, %{ - status: ".", - visibility: "public", - in_reply_to_status_id: activity.id - }) - - {:ok, _favorite} = CommonAPI.favorite(user, reply.id) - - activity_ids = - conn - |> get("/api/v1/notifications?exclude_visibilities[]=direct&limit=2") - |> json_response_and_validate_schema(200) - |> Enum.map(& &1["status"]["id"]) - - assert [reply.id, mention.id] == activity_ids - end - end - - test "filters notifications using exclude_types" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) - {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) - {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) - - mention_notification_id = get_notification_id_by_activity(mention_activity) - favorite_notification_id = get_notification_id_by_activity(favorite_activity) - reblog_notification_id = get_notification_id_by_activity(reblog_activity) - follow_notification_id = get_notification_id_by_activity(follow_activity) - - query = params_to_query(%{exclude_types: ["mention", "favourite", "reblog"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200) - - query = params_to_query(%{exclude_types: ["favourite", "reblog", "follow"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"id" => ^mention_notification_id}] = - json_response_and_validate_schema(conn_res, 200) - - query = params_to_query(%{exclude_types: ["reblog", "follow", "mention"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"id" => ^favorite_notification_id}] = - json_response_and_validate_schema(conn_res, 200) - - query = params_to_query(%{exclude_types: ["follow", "mention", "favourite"]}) - conn_res = get(conn, "/api/v1/notifications?" <> query) - - assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200) - end - - test "filters notifications using include_types" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) - {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) - {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user) - {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) - - mention_notification_id = get_notification_id_by_activity(mention_activity) - favorite_notification_id = get_notification_id_by_activity(favorite_activity) - reblog_notification_id = get_notification_id_by_activity(reblog_activity) - follow_notification_id = get_notification_id_by_activity(follow_activity) - - conn_res = get(conn, "/api/v1/notifications?include_types[]=follow") - - assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200) - - conn_res = get(conn, "/api/v1/notifications?include_types[]=mention") - - assert [%{"id" => ^mention_notification_id}] = - json_response_and_validate_schema(conn_res, 200) - - conn_res = get(conn, "/api/v1/notifications?include_types[]=favourite") - - assert [%{"id" => ^favorite_notification_id}] = - json_response_and_validate_schema(conn_res, 200) - - conn_res = get(conn, "/api/v1/notifications?include_types[]=reblog") - - assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200) - - result = conn |> get("/api/v1/notifications") |> json_response_and_validate_schema(200) - - assert length(result) == 4 - - query = params_to_query(%{include_types: ["follow", "mention", "favourite", "reblog"]}) - - result = - conn - |> get("/api/v1/notifications?" <> query) - |> json_response_and_validate_schema(200) - - assert length(result) == 4 - end - - test "destroy multiple" do - %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"]) - other_user = insert(:user) - - {:ok, activity1} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, activity2} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - {:ok, activity3} = CommonAPI.post(user, %{status: "hi @#{other_user.nickname}"}) - {:ok, activity4} = CommonAPI.post(user, %{status: "hi @#{other_user.nickname}"}) - - notification1_id = get_notification_id_by_activity(activity1) - notification2_id = get_notification_id_by_activity(activity2) - notification3_id = get_notification_id_by_activity(activity3) - notification4_id = get_notification_id_by_activity(activity4) - - result = - conn - |> get("/api/v1/notifications") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result - - conn2 = - conn - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:notifications"])) - - result = - conn2 - |> get("/api/v1/notifications") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - - query = params_to_query(%{ids: [notification1_id, notification2_id]}) - conn_destroy = delete(conn, "/api/v1/notifications/destroy_multiple?" <> query) - - assert json_response_and_validate_schema(conn_destroy, 200) == %{} - - result = - conn2 - |> get("/api/v1/notifications") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - end - - test "doesn't see notifications after muting user with notifications" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) - - ret_conn = get(conn, "/api/v1/notifications") - - assert length(json_response_and_validate_schema(ret_conn, 200)) == 1 - - {:ok, _user_relationships} = User.mute(user, user2) - - conn = get(conn, "/api/v1/notifications") - - assert json_response_and_validate_schema(conn, 200) == [] - end - - test "see notifications after muting user without notifications" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) - - ret_conn = get(conn, "/api/v1/notifications") - - assert length(json_response_and_validate_schema(ret_conn, 200)) == 1 - - {:ok, _user_relationships} = User.mute(user, user2, false) - - conn = get(conn, "/api/v1/notifications") - - assert length(json_response_and_validate_schema(conn, 200)) == 1 - end - - test "see notifications after muting user with notifications and with_muted parameter" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - user2 = insert(:user) - - {:ok, _, _, _} = CommonAPI.follow(user, user2) - {:ok, _} = CommonAPI.post(user2, %{status: "hey @#{user.nickname}"}) - - ret_conn = get(conn, "/api/v1/notifications") - - assert length(json_response_and_validate_schema(ret_conn, 200)) == 1 - - {:ok, _user_relationships} = User.mute(user, user2) - - conn = get(conn, "/api/v1/notifications?with_muted=true") - - assert length(json_response_and_validate_schema(conn, 200)) == 1 - end - - @tag capture_log: true - test "see move notifications" do - old_user = insert(:user) - new_user = insert(:user, also_known_as: [old_user.ap_id]) - %{user: follower, conn: conn} = oauth_access(["read:notifications"]) - - old_user_url = old_user.ap_id - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", old_user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock(fn - %{method: :get, url: ^old_user_url} -> - %Tesla.Env{status: 200, body: body} - end) - - User.follow(follower, old_user) - Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) - Pleroma.Tests.ObanHelpers.perform_all() - - conn = get(conn, "/api/v1/notifications") - - assert length(json_response_and_validate_schema(conn, 200)) == 1 - end - - describe "link headers" do - test "preserves parameters in link headers" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - other_user = insert(:user) - - {:ok, activity1} = - CommonAPI.post(other_user, %{ - status: "hi @#{user.nickname}", - visibility: "public" - }) - - {:ok, activity2} = - CommonAPI.post(other_user, %{ - status: "hi @#{user.nickname}", - visibility: "public" - }) - - notification1 = Repo.get_by(Notification, activity_id: activity1.id) - notification2 = Repo.get_by(Notification, activity_id: activity2.id) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/notifications?limit=5") - - assert [link_header] = get_resp_header(conn, "link") - assert link_header =~ ~r/limit=5/ - assert link_header =~ ~r/min_id=#{notification2.id}/ - assert link_header =~ ~r/max_id=#{notification1.id}/ - end - end - - describe "from specified user" do - test "account_id" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) - - %{id: account_id} = other_user1 = insert(:user) - other_user2 = insert(:user) - - {:ok, _activity} = CommonAPI.post(other_user1, %{status: "hi @#{user.nickname}"}) - {:ok, _activity} = CommonAPI.post(other_user2, %{status: "bye @#{user.nickname}"}) - - assert [%{"account" => %{"id" => ^account_id}}] = - conn - |> assign(:user, user) - |> get("/api/v1/notifications?account_id=#{account_id}") - |> json_response_and_validate_schema(200) - - assert %{"error" => "Account is not found"} = - conn - |> assign(:user, user) - |> get("/api/v1/notifications?account_id=cofe") - |> json_response_and_validate_schema(404) - end - end - - defp get_notification_id_by_activity(%{id: id}) do - Notification - |> Repo.get_by(activity_id: id) - |> Map.get(:id) - |> to_string() - end - - defp params_to_query(%{} = params) do - Enum.map_join(params, "&", fn - {k, v} when is_list(v) -> Enum.map_join(v, "&", &"#{k}[]=#{&1}") - {k, v} -> k <> "=" <> v - end) - end -end diff --git a/test/web/mastodon_api/controllers/poll_controller_test.exs b/test/web/mastodon_api/controllers/poll_controller_test.exs deleted file mode 100644 index f41de6448..000000000 --- a/test/web/mastodon_api/controllers/poll_controller_test.exs +++ /dev/null @@ -1,171 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.PollControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Object - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "GET /api/v1/polls/:id" do - setup do: oauth_access(["read:statuses"]) - - test "returns poll entity for object id", %{user: user, conn: conn} do - {: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 = get(conn, "/api/v1/polls/#{object.id}") - - response = json_response_and_validate_schema(conn, 200) - id = to_string(object.id) - assert %{"id" => ^id, "expired" => false, "multiple" => false} = response - end - - test "does not expose polls for private statuses", %{conn: conn} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(other_user, %{ - status: "Pleroma does", - poll: %{options: ["what Mastodon't", "n't what Mastodoes"], expires_in: 20}, - visibility: "private" - }) - - object = Object.normalize(activity) - - conn = get(conn, "/api/v1/polls/#{object.id}") - - assert json_response_and_validate_schema(conn, 404) - end - end - - describe "POST /api/v1/polls/:id/votes" do - setup do: oauth_access(["write:statuses"]) - - test "votes are added to the poll", %{conn: conn} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(other_user, %{ - status: "A very delicious sandwich", - poll: %{ - options: ["Lettuce", "Grilled Bacon", "Tomato"], - expires_in: 20, - multiple: true - } - }) - - object = Object.normalize(activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) - - assert json_response_and_validate_schema(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", %{user: user, conn: conn} do - {:ok, activity} = - CommonAPI.post(user, %{ - status: "Am I cute?", - poll: %{options: ["Yes", "No"], expires_in: 20} - }) - - object = Object.normalize(activity) - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]}) - |> json_response_and_validate_schema(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 - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(other_user, %{ - status: "The glass is", - poll: %{options: ["half empty", "half full"], expires_in: 20} - }) - - object = Object.normalize(activity) - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]}) - |> json_response_and_validate_schema(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 - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(other_user, %{ - status: "Am I cute?", - poll: %{options: ["Yes", "No"], expires_in: 20} - }) - - object = Object.normalize(activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]}) - - assert json_response_and_validate_schema(conn, 422) == %{"error" => "Invalid indices"} - end - - test "returns 404 error when object is not exist", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/1/votes", %{"choices" => [0]}) - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - - test "returns 404 when poll is private and not available for user", %{conn: conn} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(other_user, %{ - status: "Am I cute?", - poll: %{options: ["Yes", "No"], expires_in: 20}, - visibility: "private" - }) - - object = Object.normalize(activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]}) - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - end -end diff --git a/test/web/mastodon_api/controllers/report_controller_test.exs b/test/web/mastodon_api/controllers/report_controller_test.exs deleted file mode 100644 index 6636cff96..000000000 --- a/test/web/mastodon_api/controllers/report_controller_test.exs +++ /dev/null @@ -1,95 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - setup do: oauth_access(["write:reports"]) - - setup do - target_user = insert(:user) - - {:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"}) - - [target_user: target_user, activity: activity] - end - - test "submit a basic report", %{conn: conn, target_user: target_user} do - assert %{"action_taken" => false, "id" => _} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{"account_id" => target_user.id}) - |> json_response_and_validate_schema(200) - end - - test "submit a report with statuses and comment", %{ - conn: conn, - target_user: target_user, - activity: activity - } do - assert %{"action_taken" => false, "id" => _} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{ - "account_id" => target_user.id, - "status_ids" => [activity.id], - "comment" => "bad status!", - "forward" => "false" - }) - |> json_response_and_validate_schema(200) - end - - test "account_id is required", %{ - conn: conn, - activity: activity - } do - assert %{"error" => "Missing field: account_id."} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{"status_ids" => [activity.id]}) - |> json_response_and_validate_schema(400) - end - - test "comment must be up to the size specified in the config", %{ - conn: conn, - target_user: target_user - } do - max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000) - comment = String.pad_trailing("a", max_size + 1, "a") - - error = %{"error" => "Comment must be up to #{max_size} characters"} - - assert ^error = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment}) - |> json_response_and_validate_schema(400) - end - - test "returns error when account is not exist", %{ - conn: conn, - activity: activity - } do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"}) - - assert json_response_and_validate_schema(conn, 400) == %{"error" => "Account not found"} - end - - test "doesn't fail if an admin has no email", %{conn: conn, target_user: target_user} do - insert(:user, %{is_admin: true, email: nil}) - - assert %{"action_taken" => false, "id" => _} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/reports", %{"account_id" => target_user.id}) - |> json_response_and_validate_schema(200) - end -end diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs deleted file mode 100644 index 1ff871c89..000000000 --- a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs +++ /dev/null @@ -1,139 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Repo - alias Pleroma.ScheduledActivity - - import Pleroma.Factory - import Ecto.Query - - setup do: clear_config([ScheduledActivity, :enabled]) - - test "shows scheduled activities" do - %{user: user, conn: conn} = oauth_access(["read:statuses"]) - - scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() - scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() - - # min_id - conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") - - result = json_response_and_validate_schema(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result - - # since_id - conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") - - result = json_response_and_validate_schema(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result - - # max_id - conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") - - result = json_response_and_validate_schema(conn_res, 200) - assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result - end - - test "shows a scheduled activity" do - %{user: user, conn: conn} = oauth_access(["read:statuses"]) - scheduled_activity = insert(:scheduled_activity, user: user) - - res_conn = get(conn, "/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{"id" => scheduled_activity_id} = json_response_and_validate_schema(res_conn, 200) - assert scheduled_activity_id == scheduled_activity.id |> to_string() - - res_conn = get(conn, "/api/v1/scheduled_statuses/404") - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404) - end - - test "updates a scheduled activity" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) - %{user: user, conn: conn} = oauth_access(["write:statuses"]) - - scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) - - {:ok, scheduled_activity} = - ScheduledActivity.create( - user, - %{ - scheduled_at: scheduled_at, - params: build(:note).data - } - ) - - job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) - - assert job.args == %{"activity_id" => scheduled_activity.id} - assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(scheduled_at) - - new_scheduled_at = - NaiveDateTime.utc_now() - |> Timex.shift(minutes: 120) - |> Timex.format!("%Y-%m-%dT%H:%M:%S.%fZ", :strftime) - - res_conn = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ - scheduled_at: new_scheduled_at - }) - - assert %{"scheduled_at" => expected_scheduled_at} = - json_response_and_validate_schema(res_conn, 200) - - assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) - job = refresh_record(job) - - assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(new_scheduled_at) - - res_conn = - conn - |> put_req_header("content-type", "application/json") - |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404) - end - - test "deletes a scheduled activity" do - Pleroma.Config.put([ScheduledActivity, :enabled], true) - %{user: user, conn: conn} = oauth_access(["write:statuses"]) - scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) - - {:ok, scheduled_activity} = - ScheduledActivity.create( - user, - %{ - scheduled_at: scheduled_at, - params: build(:note).data - } - ) - - job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) - - assert job.args == %{"activity_id" => scheduled_activity.id} - - res_conn = - conn - |> assign(:user, user) - |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{} = json_response_and_validate_schema(res_conn, 200) - refute Repo.get(ScheduledActivity, scheduled_activity.id) - refute Repo.get(Oban.Job, job.id) - - res_conn = - conn - |> assign(:user, user) - |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404) - end -end diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/web/mastodon_api/controllers/search_controller_test.exs deleted file mode 100644 index 24d1959f8..000000000 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ /dev/null @@ -1,413 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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_all 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 - capture_log(fn -> - results = - conn - |> get("/api/v2/search?q=2hu") - |> json_response_and_validate_schema(200) - - assert results["accounts"] == [] - assert results["statuses"] == [] - end) =~ - "[error] Elixir.Pleroma.Web.MastodonAPI.SearchController search error: %RuntimeError{message: \"Oops\"}" - 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"}) - - results = - conn - |> get("/api/v2/search?#{URI.encode_query(%{q: "2hu #private"})}") - |> json_response_and_validate_schema(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) - - results = - get(conn, "/api/v2/search?q=天子") - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "天子", "url" => "#{Web.base_url()}/tag/天子"} - ] - - [status] = results["statuses"] - assert status["id"] == to_string(activity.id) - end - - @tag capture_log: true - test "constructs hashtags from search query", %{conn: conn} do - results = - conn - |> get("/api/v2/search?#{URI.encode_query(%{q: "some text with #explicit #hashtags"})}") - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "explicit", "url" => "#{Web.base_url()}/tag/explicit"}, - %{"name" => "hashtags", "url" => "#{Web.base_url()}/tag/hashtags"} - ] - - results = - conn - |> get("/api/v2/search?#{URI.encode_query(%{q: "john doe JOHN DOE"})}") - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "john", "url" => "#{Web.base_url()}/tag/john"}, - %{"name" => "doe", "url" => "#{Web.base_url()}/tag/doe"}, - %{"name" => "JohnDoe", "url" => "#{Web.base_url()}/tag/JohnDoe"} - ] - - results = - conn - |> get("/api/v2/search?#{URI.encode_query(%{q: "accident-prone"})}") - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "accident", "url" => "#{Web.base_url()}/tag/accident"}, - %{"name" => "prone", "url" => "#{Web.base_url()}/tag/prone"}, - %{"name" => "AccidentProne", "url" => "#{Web.base_url()}/tag/AccidentProne"} - ] - - results = - conn - |> get("/api/v2/search?#{URI.encode_query(%{q: "https://shpposter.club/users/shpuld"})}") - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "shpuld", "url" => "#{Web.base_url()}/tag/shpuld"} - ] - - results = - conn - |> get( - "/api/v2/search?#{ - URI.encode_query(%{ - q: - "https://www.washingtonpost.com/sports/2020/06/10/" <> - "nascar-ban-display-confederate-flag-all-events-properties/" - }) - }" - ) - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "nascar", "url" => "#{Web.base_url()}/tag/nascar"}, - %{"name" => "ban", "url" => "#{Web.base_url()}/tag/ban"}, - %{"name" => "display", "url" => "#{Web.base_url()}/tag/display"}, - %{"name" => "confederate", "url" => "#{Web.base_url()}/tag/confederate"}, - %{"name" => "flag", "url" => "#{Web.base_url()}/tag/flag"}, - %{"name" => "all", "url" => "#{Web.base_url()}/tag/all"}, - %{"name" => "events", "url" => "#{Web.base_url()}/tag/events"}, - %{"name" => "properties", "url" => "#{Web.base_url()}/tag/properties"}, - %{ - "name" => "NascarBanDisplayConfederateFlagAllEventsProperties", - "url" => - "#{Web.base_url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties" - } - ] - end - - test "supports pagination of hashtags search results", %{conn: conn} do - results = - conn - |> get( - "/api/v2/search?#{ - URI.encode_query(%{q: "#some #text #with #hashtags", limit: 2, offset: 1}) - }" - ) - |> json_response_and_validate_schema(200) - - assert results["hashtags"] == [ - %{"name" => "text", "url" => "#{Web.base_url()}/tag/text"}, - %{"name" => "with", "url" => "#{Web.base_url()}/tag/with"} - ] - end - - test "excludes a blocked users from search results", %{conn: conn} do - user = insert(:user) - user_smith = insert(:user, %{nickname: "Agent", name: "I love 2hu"}) - user_neo = insert(:user, %{nickname: "Agent Neo", name: "Agent"}) - - {:ok, act1} = CommonAPI.post(user, %{status: "This is about 2hu private 天子"}) - {:ok, act2} = CommonAPI.post(user_smith, %{status: "Agent Smith"}) - {:ok, act3} = CommonAPI.post(user_neo, %{status: "Agent Smith"}) - Pleroma.User.block(user, user_smith) - - results = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) - |> get("/api/v2/search?q=Agent") - |> json_response_and_validate_schema(200) - - status_ids = Enum.map(results["statuses"], fn g -> g["id"] end) - - assert act3.id in status_ids - refute act2.id in status_ids - refute act1.id in status_ids - end - end - - describe ".account_search" do - test "account search", %{conn: conn} do - user_two = insert(:user, %{nickname: "shp@shitposter.club"}) - user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"}) - - results = - conn - |> get("/api/v1/accounts/search?q=shp") - |> json_response_and_validate_schema(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 - |> get("/api/v1/accounts/search?q=2hu") - |> json_response_and_validate_schema(200) - - result_ids = for result <- results, do: result["acct"] - - assert user_three.nickname in result_ids - end - - test "returns account if query contains a space", %{conn: conn} do - insert(:user, %{nickname: "shp@shitposter.club"}) - - results = - conn - |> get("/api/v1/accounts/search?q=shp@shitposter.club xxx") - |> json_response_and_validate_schema(200) - - assert length(results) == 1 - 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 - capture_log(fn -> - results = - conn - |> get("/api/v1/search?q=2hu") - |> json_response_and_validate_schema(200) - - assert results["accounts"] == [] - assert results["statuses"] == [] - end) =~ - "[error] Elixir.Pleroma.Web.MastodonAPI.SearchController search error: %RuntimeError{message: \"Oops\"}" - 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"}) - - results = - conn - |> get("/api/v1/search?q=2hu") - |> json_response_and_validate_schema(200) - - [account | _] = results["accounts"] - assert account["id"] == to_string(user_three.id) - - assert results["hashtags"] == ["2hu"] - - [status] = results["statuses"] - assert status["id"] == to_string(activity.id) - end - - test "search fetches remote statuses and prefers them over other results", %{conn: conn} do - capture_log(fn -> - {:ok, %{id: activity_id}} = - CommonAPI.post(insert(:user), %{ - status: "check out https://shitposter.club/notice/2827873" - }) - - results = - conn - |> get("/api/v1/search?q=https://shitposter.club/notice/2827873") - |> json_response_and_validate_schema(200) - - [status, %{"id" => ^activity_id}] = 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 -> - q = Object.normalize(activity).data["id"] - - results = - conn - |> get("/api/v1/search?q=#{q}") - |> json_response_and_validate_schema(200) - - [] = results["statuses"] - end) - end - - test "search fetches remote accounts", %{conn: conn} do - user = insert(:user) - - query = URI.encode_query(%{q: " mike@osada.macgirvin.com ", resolve: true}) - - results = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) - |> get("/api/v1/search?#{query}") - |> json_response_and_validate_schema(200) - - [account] = results["accounts"] - assert account["acct"] == "mike@osada.macgirvin.com" - end - - test "search doesn't fetch remote accounts if resolve is false", %{conn: conn} do - results = - conn - |> get("/api/v1/search?q=mike@osada.macgirvin.com&resolve=false") - |> json_response_and_validate_schema(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_and_validate_schema(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_and_validate_schema(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_and_validate_schema(200) - - assert %{"statuses" => [], "accounts" => [_user_two], "hashtags" => []} = - conn - |> get("/api/v1/search?q=2hu&type=accounts") - |> json_response_and_validate_schema(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_and_validate_schema(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_and_validate_schema(200) - - assert [%{"id" => activity_id2}] = results["statuses"] - assert activity_id2 == activity2.id - end - end -end diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs deleted file mode 100644 index d34f300da..000000000 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ /dev/null @@ -1,1654 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Activity - alias Pleroma.ActivityExpiration - alias Pleroma.Config - alias Pleroma.Conversation.Participation - alias Pleroma.Object - alias Pleroma.Repo - alias Pleroma.ScheduledActivity - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - setup do: clear_config([:instance, :federating]) - setup do: clear_config([:instance, :allow_relay]) - setup do: clear_config([:rich_media, :enabled]) - setup do: clear_config([:mrf, :policies]) - setup do: clear_config([:mrf_keyword, :reject]) - - describe "posting statuses" do - setup do: oauth_access(["write:statuses"]) - - test "posting a status does not increment reblog_count when relaying", %{conn: conn} do - Pleroma.Config.put([:instance, :federating], true) - Pleroma.Config.get([:instance, :allow_relay], true) - - response = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ - "content_type" => "text/plain", - "source" => "Pleroma FE", - "status" => "Hello world", - "visibility" => "public" - }) - |> json_response_and_validate_schema(200) - - assert response["reblogs_count"] == 0 - ObanHelpers.perform_all() - - response = - conn - |> get("api/v1/statuses/#{response["id"]}", %{}) - |> json_response_and_validate_schema(200) - - assert response["reblogs_count"] == 0 - end - - test "posting a status", %{conn: conn} do - idempotency_key = "Pikachu rocks!" - - conn_one = - conn - |> put_req_header("content-type", "application/json") - |> put_req_header("idempotency-key", idempotency_key) - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => "0" - }) - - {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) - # Six hours - assert ttl > :timer.seconds(6 * 60 * 60 - 1) - - assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = - json_response_and_validate_schema(conn_one, 200) - - assert Activity.get_by_id(id) - - conn_two = - conn - |> put_req_header("content-type", "application/json") - |> put_req_header("idempotency-key", idempotency_key) - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => 0 - }) - - assert %{"id" => second_id} = json_response(conn_two, 200) - assert id == second_id - - conn_three = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "cofe", - "spoiler_text" => "2hu", - "sensitive" => "False" - }) - - assert %{"id" => third_id} = json_response_and_validate_schema(conn_three, 200) - refute id == third_id - - # An activity that will expire: - # 2 hours - expires_in = 120 * 60 - - conn_four = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ - "status" => "oolong", - "expires_in" => expires_in - }) - - assert fourth_response = - %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200) - - assert activity = Activity.get_by_id(fourth_id) - assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) - - estimated_expires_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(expires_in) - |> NaiveDateTime.truncate(:second) - - # This assert will fail if the test takes longer than a minute. I sure hope it never does: - assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 - - assert fourth_response["pleroma"]["expires_at"] == - NaiveDateTime.to_iso8601(expiration.scheduled_at) - end - - test "it fails to create a status if `expires_in` is less or equal than an hour", %{ - conn: conn - } do - # 1 hour - expires_in = 60 * 60 - - assert %{"error" => "Expiry date is too soon"} = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ - "status" => "oolong", - "expires_in" => expires_in - }) - |> json_response_and_validate_schema(422) - - # 30 minutes - expires_in = 30 * 60 - - assert %{"error" => "Expiry date is too soon"} = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{ - "status" => "oolong", - "expires_in" => expires_in - }) - |> json_response_and_validate_schema(422) - end - - test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do - Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"]) - Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy]) - - assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{"status" => "GNO/Linux"}) - |> json_response_and_validate_schema(422) - end - - test "posting an undefined status with an attachment", %{user: user, conn: conn} do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "media_ids" => [to_string(upload.id)] - }) - - assert json_response_and_validate_schema(conn, 200) - end - - test "replying to a status", %{user: user, conn: conn} do - {:ok, replied_to} = CommonAPI.post(user, %{status: "cofe"}) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - - assert %{"content" => "xD", "id" => id} = json_response_and_validate_schema(conn, 200) - - activity = Activity.get_by_id(id) - - assert activity.data["context"] == replied_to.data["context"] - assert Activity.get_in_reply_to_activity(activity).id == replied_to.id - end - - test "replying to a direct message with visibility other than direct", %{ - user: user, - conn: conn - } do - {:ok, replied_to} = CommonAPI.post(user, %{status: "suya..", visibility: "direct"}) - - Enum.each(["public", "private", "unlisted"], fn visibility -> - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "@#{user.nickname} hey", - "in_reply_to_id" => replied_to.id, - "visibility" => visibility - }) - - assert json_response_and_validate_schema(conn, 422) == %{ - "error" => "The message visibility must be direct" - } - end) - end - - test "posting a status with an invalid in_reply_to_id", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""}) - - assert %{"content" => "xD", "id" => id} = json_response_and_validate_schema(conn, 200) - assert Activity.get_by_id(id) - end - - test "posting a sensitive status", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true}) - - assert %{"content" => "cofe", "id" => id, "sensitive" => true} = - json_response_and_validate_schema(conn, 200) - - assert Activity.get_by_id(id) - end - - test "posting a fake status", %{conn: conn} do - real_conn = - conn - |> put_req_header("content-type", "application/json") - |> 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" - }) - - real_status = json_response_and_validate_schema(real_conn, 200) - - 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 - |> put_req_header("content-type", "application/json") - |> 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 - }) - - fake_status = json_response_and_validate_schema(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 - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - Config.put([:rich_media, :enabled], true) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "https://example.com/ogp" - }) - - assert %{"id" => id, "card" => %{"title" => "The Rock"}} = - json_response_and_validate_schema(conn, 200) - - assert Activity.get_by_id(id) - end - - test "posting a direct status", %{conn: conn} do - user2 = insert(:user) - content = "direct cofe @#{user2.nickname}" - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) - - assert %{"id" => id} = response = json_response_and_validate_schema(conn, 200) - assert response["visibility"] == "direct" - assert response["pleroma"]["direct_conversation_id"] - 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 - - describe "posting scheduled statuses" do - setup do: oauth_access(["write:statuses"]) - - test "creates a scheduled activity", %{conn: conn} do - scheduled_at = - NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - |> NaiveDateTime.to_iso8601() - |> Kernel.<>("Z") - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"scheduled_at" => expected_scheduled_at} = - json_response_and_validate_schema(conn, 200) - - assert expected_scheduled_at == CommonAPI.Utils.to_masto_date(scheduled_at) - assert [] == Repo.all(Activity) - end - - test "ignores nil values", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "not scheduled", - "scheduled_at" => nil - }) - - assert result = json_response_and_validate_schema(conn, 200) - assert Activity.get_by_id(result["id"]) - end - - test "creates a scheduled activity with a media attachment", %{user: user, conn: conn} do - scheduled_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(120), :millisecond) - |> NaiveDateTime.to_iso8601() - |> Kernel.<>("Z") - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "media_ids" => [to_string(upload.id)], - "status" => "scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"media_attachments" => [media_attachment]} = - json_response_and_validate_schema(conn, 200) - - assert %{"type" => "image"} = media_attachment - end - - test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", - %{conn: conn} do - scheduled_at = - NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) - |> NaiveDateTime.to_iso8601() - |> Kernel.<>("Z") - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "not scheduled", - "scheduled_at" => scheduled_at - }) - - assert %{"content" => "not scheduled"} = json_response_and_validate_schema(conn, 200) - assert [] == Repo.all(ScheduledActivity) - end - - test "returns error when daily user limit is exceeded", %{user: user, conn: conn} do - today = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(6), :millisecond) - |> NaiveDateTime.to_iso8601() - # TODO - |> Kernel.<>("Z") - - attrs = %{params: %{}, scheduled_at: today} - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, attrs) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) - - assert %{"error" => "daily limit exceeded"} == json_response_and_validate_schema(conn, 422) - end - - test "returns error when total user limit is exceeded", %{user: user, conn: conn} do - today = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(6), :millisecond) - |> NaiveDateTime.to_iso8601() - |> Kernel.<>("Z") - - tomorrow = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.hours(36), :millisecond) - |> NaiveDateTime.to_iso8601() - |> Kernel.<>("Z") - - attrs = %{params: %{}, scheduled_at: today} - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, attrs) - {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) - - assert %{"error" => "total limit exceeded"} == json_response_and_validate_schema(conn, 422) - end - end - - describe "posting polls" do - setup do: oauth_access(["write:statuses"]) - - test "posting a poll", %{conn: conn} do - time = NaiveDateTime.utc_now() - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "Who is the #bestgrill?", - "poll" => %{ - "options" => ["Rei", "Asuka", "Misato"], - "expires_in" => 420 - } - }) - - response = json_response_and_validate_schema(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"] - - question = Object.get_by_id(response["poll"]["id"]) - - # closed contains utc timezone - assert question.data["closed"] =~ "Z" - end - - test "option limit is enforced", %{conn: conn} do - limit = Config.get([:instance, :poll_limits, :max_options]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "desu~", - "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1} - }) - - %{"error" => error} = json_response_and_validate_schema(conn, 422) - assert error == "Poll can't contain more than #{limit} options" - end - - test "option character limit is enforced", %{conn: conn} do - limit = Config.get([:instance, :poll_limits, :max_option_chars]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{ - "status" => "...", - "poll" => %{ - "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)], - "expires_in" => 1 - } - }) - - %{"error" => error} = json_response_and_validate_schema(conn, 422) - assert error == "Poll options cannot be longer than #{limit} characters each" - end - - test "minimal date limit is enforced", %{conn: conn} do - limit = Config.get([:instance, :poll_limits, :min_expiration]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> 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_and_validate_schema(conn, 422) - assert error == "Expiration date is too soon" - end - - test "maximum date limit is enforced", %{conn: conn} do - limit = Config.get([:instance, :poll_limits, :max_expiration]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> 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_and_validate_schema(conn, 422) - assert error == "Expiration date is too far in the future" - end - end - - test "get a status" do - %{conn: conn} = oauth_access(["read:statuses"]) - activity = insert(:note_activity) - - conn = get(conn, "/api/v1/statuses/#{activity.id}") - - assert %{"id" => id} = json_response_and_validate_schema(conn, 200) - assert id == to_string(activity.id) - end - - defp local_and_remote_activities do - local = insert(:note_activity) - remote = insert(:note_activity, local: false) - {:ok, local: local, remote: remote} - end - - describe "status with restrict unauthenticated activities for local and remote" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :local], true) - - setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - - assert json_response_and_validate_schema(res_conn, :not_found) == %{ - "error" => "Record not found" - } - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - - assert json_response_and_validate_schema(res_conn, :not_found) == %{ - "error" => "Record not found" - } - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - describe "status with restrict unauthenticated activities for local" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :local], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - - assert json_response_and_validate_schema(res_conn, :not_found) == %{ - "error" => "Record not found" - } - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - describe "status with restrict unauthenticated activities for remote" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - - assert json_response_and_validate_schema(res_conn, :not_found) == %{ - "error" => "Record not found" - } - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - res_conn = get(conn, "/api/v1/statuses/#{local.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - - res_conn = get(conn, "/api/v1/statuses/#{remote.id}") - assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200) - end - end - - test "getting a status that doesn't exist returns 404" do - %{conn: conn} = oauth_access(["read:statuses"]) - activity = insert(:note_activity) - - conn = get(conn, "/api/v1/statuses/#{String.downcase(activity.id)}") - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - - test "get a direct status" do - %{user: user, conn: conn} = oauth_access(["read:statuses"]) - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{status: "@#{other_user.nickname}", visibility: "direct"}) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/statuses/#{activity.id}") - - [participation] = Participation.for_user(user) - - res = json_response_and_validate_schema(conn, 200) - assert res["pleroma"]["direct_conversation_id"] == participation.id - end - - test "get statuses by IDs" do - %{conn: conn} = oauth_access(["read:statuses"]) - %{id: id1} = insert(:note_activity) - %{id: id2} = insert(:note_activity) - - query_string = "ids[]=#{id1}&ids[]=#{id2}" - conn = get(conn, "/api/v1/statuses/?#{query_string}") - - assert [%{"id" => ^id1}, %{"id" => ^id2}] = - Enum.sort_by(json_response_and_validate_schema(conn, :ok), & &1["id"]) - end - - describe "getting statuses by ids with restricted unauthenticated for local and remote" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :local], true) - - setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - assert json_response_and_validate_schema(res_conn, 200) == [] - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "getting statuses by ids with restricted unauthenticated for local" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :local], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - remote_id = remote.id - assert [%{"id" => ^remote_id}] = json_response_and_validate_schema(res_conn, 200) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "getting statuses by ids with restricted unauthenticated for remote" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true) - - test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - local_id = local.id - assert [%{"id" => ^local_id}] = json_response_and_validate_schema(res_conn, 200) - end - - test "if user is authenticated", %{local: local, remote: remote} do - %{conn: conn} = oauth_access(["read"]) - - res_conn = get(conn, "/api/v1/statuses?ids[]=#{local.id}&ids[]=#{remote.id}") - - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "deleting a status" do - test "when you created it" do - %{user: author, conn: conn} = oauth_access(["write:statuses"]) - activity = insert(:note_activity, user: author) - object = Object.normalize(activity) - - content = object.data["content"] - source = object.data["source"] - - result = - conn - |> assign(:user, author) - |> delete("/api/v1/statuses/#{activity.id}") - |> json_response_and_validate_schema(200) - - assert match?(%{"content" => ^content, "text" => ^source}, result) - - refute Activity.get_by_id(activity.id) - end - - test "when it doesn't exist" do - %{user: author, conn: conn} = oauth_access(["write:statuses"]) - activity = insert(:note_activity, user: author) - - conn = - conn - |> assign(:user, author) - |> delete("/api/v1/statuses/#{String.downcase(activity.id)}") - - assert %{"error" => "Record not found"} == json_response_and_validate_schema(conn, 404) - end - - test "when you didn't create it" do - %{conn: conn} = oauth_access(["write:statuses"]) - activity = insert(:note_activity) - - conn = delete(conn, "/api/v1/statuses/#{activity.id}") - - assert %{"error" => "Record not found"} == json_response_and_validate_schema(conn, 404) - - assert Activity.get_by_id(activity.id) == activity - end - - test "when you're an admin or moderator", %{conn: conn} do - activity1 = insert(:note_activity) - activity2 = insert(:note_activity) - admin = insert(:user, is_admin: true) - moderator = insert(:user, is_moderator: true) - - res_conn = - conn - |> assign(:user, admin) - |> assign(:token, insert(:oauth_token, user: admin, scopes: ["write:statuses"])) - |> delete("/api/v1/statuses/#{activity1.id}") - - assert %{} = json_response_and_validate_schema(res_conn, 200) - - res_conn = - conn - |> assign(:user, moderator) - |> assign(:token, insert(:oauth_token, user: moderator, scopes: ["write:statuses"])) - |> delete("/api/v1/statuses/#{activity2.id}") - - assert %{} = json_response_and_validate_schema(res_conn, 200) - - refute Activity.get_by_id(activity1.id) - refute Activity.get_by_id(activity2.id) - end - end - - describe "reblogging" do - setup do: oauth_access(["write:statuses"]) - - test "reblogs and returns the reblogged status", %{conn: conn} do - activity = insert(:note_activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/reblog") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, - "reblogged" => true - } = json_response_and_validate_schema(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 404 if the reblogged status doesn't exist", %{conn: conn} do - activity = insert(:note_activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{String.downcase(activity.id)}/reblog") - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404) - end - - test "reblogs privately and returns the reblogged status", %{conn: conn} do - activity = insert(:note_activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post( - "/api/v1/statuses/#{activity.id}/reblog", - %{"visibility" => "private"} - ) - - assert %{ - "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, - "reblogged" => true, - "visibility" => "private" - } = json_response_and_validate_schema(conn, 200) - - assert to_string(activity.id) == id - end - - test "reblogged status for another user" do - activity = insert(:note_activity) - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - {:ok, _} = CommonAPI.favorite(user2, activity.id) - {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) - {:ok, reblog_activity1} = CommonAPI.repeat(activity.id, user1) - {:ok, _} = CommonAPI.repeat(activity.id, user2) - - conn_res = - build_conn() - |> assign(:user, user3) - |> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"])) - |> get("/api/v1/statuses/#{reblog_activity1.id}") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, - "reblogged" => false, - "favourited" => false, - "bookmarked" => false - } = json_response_and_validate_schema(conn_res, 200) - - conn_res = - build_conn() - |> assign(:user, user2) - |> assign(:token, insert(:oauth_token, user: user2, scopes: ["read:statuses"])) - |> get("/api/v1/statuses/#{reblog_activity1.id}") - - assert %{ - "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, - "reblogged" => true, - "favourited" => true, - "bookmarked" => true - } = json_response_and_validate_schema(conn_res, 200) - - assert to_string(activity.id) == id - end - end - - describe "unreblogging" do - setup do: oauth_access(["write:statuses"]) - - test "unreblogs and returns the unreblogged status", %{user: user, conn: conn} do - activity = insert(:note_activity) - - {:ok, _} = CommonAPI.repeat(activity.id, user) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/unreblog") - - assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = - json_response_and_validate_schema(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 404 error when activity does not exist", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/foo/unreblog") - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - end - - describe "favoriting" do - setup do: oauth_access(["write:favourites"]) - - test "favs a status and returns it", %{conn: conn} do - activity = insert(:note_activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/favourite") - - assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = - json_response_and_validate_schema(conn, 200) - - assert to_string(activity.id) == id - end - - test "favoriting twice will just return 200", %{conn: conn} do - activity = insert(:note_activity) - - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/favourite") - - assert conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/favourite") - |> json_response_and_validate_schema(200) - end - - test "returns 404 error for a wrong id", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/1/favourite") - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - end - - describe "unfavoriting" do - setup do: oauth_access(["write:favourites"]) - - test "unfavorites a status and returns it", %{user: user, conn: conn} do - activity = insert(:note_activity) - - {:ok, _} = CommonAPI.favorite(user, activity.id) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/unfavourite") - - assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = - json_response_and_validate_schema(conn, 200) - - assert to_string(activity.id) == id - end - - test "returns 404 error for a wrong id", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/1/unfavourite") - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - end - - describe "pinned statuses" do - setup do: oauth_access(["write:accounts"]) - - setup %{user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"}) - - %{activity: activity} - end - - setup do: clear_config([:instance, :max_pinned_statuses], 1) - - test "pin status", %{conn: conn, user: user, activity: activity} do - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "pinned" => true} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/pin") - |> json_response_and_validate_schema(200) - - assert [%{"id" => ^id_str, "pinned" => true}] = - conn - |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") - |> json_response_and_validate_schema(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 - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{dm.id}/pin") - - assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not pin"} - end - - test "unpin status", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.pin(activity.id, user) - user = refresh_record(user) - - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "pinned" => false} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unpin") - |> json_response_and_validate_schema(200) - - assert [] = - conn - |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") - |> json_response_and_validate_schema(200) - end - - test "/unpin: returns 400 error when activity is not exist", %{conn: conn} do - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/1/unpin") - - assert json_response_and_validate_schema(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!!!"}) - - id_str_one = to_string(activity_one.id) - - assert %{"id" => ^id_str_one, "pinned" => true} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{id_str_one}/pin") - |> json_response_and_validate_schema(200) - - user = refresh_record(user) - - assert %{"error" => "You have already pinned the maximum number of statuses"} = - conn - |> assign(:user, user) - |> post("/api/v1/statuses/#{activity_two.id}/pin") - |> json_response_and_validate_schema(400) - end - end - - describe "cards" do - setup do - Config.put([:rich_media, :enabled], true) - - oauth_access(["read:statuses"]) - end - - test "returns rich-media card", %{conn: conn, user: user} do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - - {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"}) - - card_data = %{ - "image" => "http://ia.media-imdb.com/images/rock.jpg", - "provider_name" => "example.com", - "provider_url" => "https://example.com", - "title" => "The Rock", - "type" => "link", - "url" => "https://example.com/ogp", - "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" => "https://example.com/ogp", - "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_and_validate_schema(200) - - assert response == card_data - - # works with private posts - {:ok, activity} = - CommonAPI.post(user, %{status: "https://example.com/ogp", visibility: "direct"}) - - response_two = - conn - |> get("/api/v1/statuses/#{activity.id}/card") - |> json_response_and_validate_schema(200) - - assert response_two == card_data - end - - test "replaces missing description with an empty string", %{conn: conn, user: user} do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - - {:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"}) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/card") - |> json_response_and_validate_schema(:ok) - - assert response == %{ - "type" => "link", - "title" => "Pleroma", - "description" => "", - "image" => nil, - "provider_name" => "example.com", - "provider_url" => "https://example.com", - "url" => "https://example.com/ogp-missing-data", - "pleroma" => %{ - "opengraph" => %{ - "title" => "Pleroma", - "type" => "website", - "url" => "https://example.com/ogp-missing-data" - } - } - } - end - end - - test "bookmarks" do - bookmarks_uri = "/api/v1/bookmarks" - - %{conn: conn} = oauth_access(["write:bookmarks", "read:bookmarks"]) - author = insert(:user) - - {:ok, activity1} = CommonAPI.post(author, %{status: "heweoo?"}) - {:ok, activity2} = CommonAPI.post(author, %{status: "heweoo!"}) - - response1 = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity1.id}/bookmark") - - assert json_response_and_validate_schema(response1, 200)["bookmarked"] == true - - response2 = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity2.id}/bookmark") - - assert json_response_and_validate_schema(response2, 200)["bookmarked"] == true - - bookmarks = get(conn, bookmarks_uri) - - assert [ - json_response_and_validate_schema(response2, 200), - json_response_and_validate_schema(response1, 200) - ] == - json_response_and_validate_schema(bookmarks, 200) - - response1 = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity1.id}/unbookmark") - - assert json_response_and_validate_schema(response1, 200)["bookmarked"] == false - - bookmarks = get(conn, bookmarks_uri) - - assert [json_response_and_validate_schema(response2, 200)] == - json_response_and_validate_schema(bookmarks, 200) - end - - describe "conversation muting" do - setup do: oauth_access(["write:mutes"]) - - setup do - post_user = insert(:user) - {:ok, activity} = CommonAPI.post(post_user, %{status: "HIE"}) - %{activity: activity} - end - - test "mute conversation", %{conn: conn, activity: activity} do - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "muted" => true} = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/mute") - |> json_response_and_validate_schema(200) - end - - test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/mute") - - assert json_response_and_validate_schema(conn, 400) == %{ - "error" => "conversation is already muted" - } - end - - test "unmute conversation", %{conn: conn, user: user, activity: activity} do - {:ok, _} = CommonAPI.add_mute(user, activity) - - id_str = to_string(activity.id) - - assert %{"id" => ^id_str, "muted" => false} = - conn - # |> assign(:user, user) - |> post("/api/v1/statuses/#{activity.id}/unmute") - |> json_response_and_validate_schema(200) - end - end - - test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - - {:ok, replied_to} = CommonAPI.post(user1, %{status: "cofe"}) - - # Reply to status from another user - conn1 = - conn - |> assign(:user, user2) - |> assign(:token, insert(:oauth_token, user: user2, scopes: ["write:statuses"])) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - - assert %{"content" => "xD", "id" => id} = json_response_and_validate_schema(conn1, 200) - - activity = Activity.get_by_id_with_object(id) - - assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] - assert Activity.get_in_reply_to_activity(activity).id == replied_to.id - - # Reblog from the third user - conn2 = - conn - |> assign(:user, user3) - |> assign(:token, insert(:oauth_token, user: user3, scopes: ["write:statuses"])) - |> put_req_header("content-type", "application/json") - |> post("/api/v1/statuses/#{activity.id}/reblog") - - assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = - json_response_and_validate_schema(conn2, 200) - - assert to_string(activity.id) == id - - # Getting third user status - conn3 = - conn - |> assign(:user, user3) - |> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"])) - |> get("api/v1/timelines/home") - - [reblogged_activity] = json_response(conn3, 200) - - assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id - - replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) - assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id - end - - describe "GET /api/v1/statuses/:id/favourited_by" do - setup do: oauth_access(["read:accounts"]) - - setup %{user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "test"}) - - %{activity: activity} - end - - test "returns users who have favorited the status", %{conn: conn, activity: activity} do - other_user = insert(:user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response_and_validate_schema(: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_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "does not return users who have favorited the status but are blocked", %{ - conn: %{assigns: %{user: user}} = conn, - activity: activity - } do - other_user = insert(:user) - {:ok, _user_relationship} = User.block(user, other_user) - - {:ok, _} = CommonAPI.favorite(other_user, activity.id) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "does not fail on an unauthenticated request", %{activity: activity} do - other_user = insert(:user) - {:ok, _} = CommonAPI.favorite(other_user, activity.id) - - response = - build_conn() - |> get("/api/v1/statuses/#{activity.id}/favourited_by") - |> json_response_and_validate_schema(:ok) - - [%{"id" => id}] = response - assert id == other_user.id - end - - test "requires authentication for private posts", %{user: user} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "@#{other_user.nickname} wanna get some #cofe together?", - visibility: "direct" - }) - - {:ok, _} = CommonAPI.favorite(other_user, activity.id) - - favourited_by_url = "/api/v1/statuses/#{activity.id}/favourited_by" - - build_conn() - |> get(favourited_by_url) - |> json_response_and_validate_schema(404) - - conn = - build_conn() - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"])) - - conn - |> assign(:token, nil) - |> get(favourited_by_url) - |> json_response_and_validate_schema(404) - - response = - conn - |> get(favourited_by_url) - |> json_response_and_validate_schema(200) - - [%{"id" => id}] = response - assert id == other_user.id - end - end - - describe "GET /api/v1/statuses/:id/reblogged_by" do - setup do: oauth_access(["read:accounts"]) - - setup %{user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "test"}) - - %{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_and_validate_schema(: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_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "does not return users who have reblogged the status but are blocked", %{ - conn: %{assigns: %{user: user}} = conn, - activity: activity - } do - other_user = insert(:user) - {:ok, _user_relationship} = User.block(user, other_user) - - {:ok, _} = CommonAPI.repeat(activity.id, other_user) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "does not return users who have reblogged the status privately", %{ - conn: conn - } do - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "my secret post"}) - - {:ok, _} = CommonAPI.repeat(activity.id, other_user, %{visibility: "private"}) - - response = - conn - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "does not fail on an unauthenticated request", %{activity: activity} do - other_user = insert(:user) - {:ok, _} = CommonAPI.repeat(activity.id, other_user) - - response = - build_conn() - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response_and_validate_schema(:ok) - - [%{"id" => id}] = response - assert id == other_user.id - end - - test "requires authentication for private posts", %{user: user} do - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "@#{other_user.nickname} wanna get some #cofe together?", - visibility: "direct" - }) - - build_conn() - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response_and_validate_schema(404) - - response = - build_conn() - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"])) - |> get("/api/v1/statuses/#{activity.id}/reblogged_by") - |> json_response_and_validate_schema(200) - - assert [] == response - end - end - - test "context" do - user = insert(:user) - - {:ok, %{id: id1}} = CommonAPI.post(user, %{status: "1"}) - {:ok, %{id: id2}} = CommonAPI.post(user, %{status: "2", in_reply_to_status_id: id1}) - {:ok, %{id: id3}} = CommonAPI.post(user, %{status: "3", in_reply_to_status_id: id2}) - {:ok, %{id: id4}} = CommonAPI.post(user, %{status: "4", in_reply_to_status_id: id3}) - {:ok, %{id: id5}} = CommonAPI.post(user, %{status: "5", in_reply_to_status_id: id4}) - - response = - build_conn() - |> get("/api/v1/statuses/#{id3}/context") - |> json_response_and_validate_schema(:ok) - - assert %{ - "ancestors" => [%{"id" => ^id1}, %{"id" => ^id2}], - "descendants" => [%{"id" => ^id4}, %{"id" => ^id5}] - } = response - end - - test "favorites paginate correctly" do - %{user: user, conn: conn} = oauth_access(["read:favourites"]) - other_user = insert(:user) - {:ok, first_post} = CommonAPI.post(other_user, %{status: "bla"}) - {:ok, second_post} = CommonAPI.post(other_user, %{status: "bla"}) - {:ok, third_post} = CommonAPI.post(other_user, %{status: "bla"}) - - {:ok, _first_favorite} = CommonAPI.favorite(user, third_post.id) - {:ok, _second_favorite} = CommonAPI.favorite(user, first_post.id) - {:ok, third_favorite} = CommonAPI.favorite(user, second_post.id) - - result = - conn - |> get("/api/v1/favourites?limit=1") - - assert [%{"id" => post_id}] = json_response_and_validate_schema(result, 200) - assert post_id == second_post.id - - # Using the header for pagination works correctly - [next, _] = get_resp_header(result, "link") |> hd() |> String.split(", ") - [_, max_id] = Regex.run(~r/max_id=([^&]+)/, next) - - assert max_id == third_favorite.id - - result = - conn - |> get("/api/v1/favourites?max_id=#{max_id}") - - assert [%{"id" => first_post_id}, %{"id" => third_post_id}] = - json_response_and_validate_schema(result, 200) - - assert first_post_id == first_post.id - assert third_post_id == third_post.id - end - - test "returns the favorites of a user" do - %{user: user, conn: conn} = oauth_access(["read:favourites"]) - other_user = insert(:user) - - {:ok, _} = CommonAPI.post(other_user, %{status: "bla"}) - {:ok, activity} = CommonAPI.post(other_user, %{status: "trees are happy"}) - - {:ok, last_like} = CommonAPI.favorite(user, activity.id) - - first_conn = get(conn, "/api/v1/favourites") - - assert [status] = json_response_and_validate_schema(first_conn, 200) - assert status["id"] == to_string(activity.id) - - assert [{"link", _link_header}] = - Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end) - - # Honours query params - {:ok, second_activity} = - CommonAPI.post(other_user, %{ - status: "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful." - }) - - {:ok, _} = CommonAPI.favorite(user, second_activity.id) - - second_conn = get(conn, "/api/v1/favourites?since_id=#{last_like.id}") - - assert [second_status] = json_response_and_validate_schema(second_conn, 200) - assert second_status["id"] == to_string(second_activity.id) - - third_conn = get(conn, "/api/v1/favourites?limit=0") - - assert [] = json_response_and_validate_schema(third_conn, 200) - end - - test "expires_at is nil for another user" do - %{conn: conn, user: user} = oauth_access(["read:statuses"]) - {:ok, activity} = CommonAPI.post(user, %{status: "foobar", expires_in: 1_000_000}) - - expires_at = - activity.id - |> ActivityExpiration.get_by_activity_id() - |> Map.get(:scheduled_at) - |> NaiveDateTime.to_iso8601() - - assert %{"pleroma" => %{"expires_at" => ^expires_at}} = - conn - |> get("/api/v1/statuses/#{activity.id}") - |> json_response_and_validate_schema(:ok) - - %{conn: conn} = oauth_access(["read:statuses"]) - - assert %{"pleroma" => %{"expires_at" => nil}} = - conn - |> get("/api/v1/statuses/#{activity.id}") - |> json_response_and_validate_schema(:ok) - end -end diff --git a/test/web/mastodon_api/controllers/subscription_controller_test.exs b/test/web/mastodon_api/controllers/subscription_controller_test.exs deleted file mode 100644 index d36bb1ae8..000000000 --- a/test/web/mastodon_api/controllers/subscription_controller_test.exs +++ /dev/null @@ -1,199 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Web.Push - alias Pleroma.Web.Push.Subscription - - @sub %{ - "endpoint" => "https://example.com/example/1234", - "keys" => %{ - "auth" => "8eDyX_uCN0XRhSbY5hs7Hg==", - "p256dh" => - "BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA=" - } - } - @server_key Keyword.get(Push.vapid_config(), :public_key) - - setup do - user = insert(:user) - token = insert(:oauth_token, user: user, scopes: ["push"]) - - conn = - build_conn() - |> assign(:user, user) - |> assign(:token, token) - |> put_req_header("content-type", "application/json") - - %{conn: conn, user: user, token: token} - end - - defmacro assert_error_when_disable_push(do: yield) do - quote do - vapid_details = Application.get_env(:web_push_encryption, :vapid_details, []) - Application.put_env(:web_push_encryption, :vapid_details, []) - - assert %{"error" => "Web push subscription is disabled on this Pleroma instance"} == - unquote(yield) - - Application.put_env(:web_push_encryption, :vapid_details, vapid_details) - end - end - - describe "creates push subscription" do - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> post("/api/v1/push/subscription", %{subscription: @sub}) - |> json_response_and_validate_schema(403) - end - end - - test "successful creation", %{conn: conn} do - result = - conn - |> post("/api/v1/push/subscription", %{ - "data" => %{ - "alerts" => %{"mention" => true, "test" => true, "pleroma:chat_mention" => true} - }, - "subscription" => @sub - }) - |> json_response_and_validate_schema(200) - - [subscription] = Pleroma.Repo.all(Subscription) - - assert %{ - "alerts" => %{"mention" => true, "pleroma:chat_mention" => true}, - "endpoint" => subscription.endpoint, - "id" => to_string(subscription.id), - "server_key" => @server_key - } == result - end - end - - describe "gets a user subscription" do - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> get("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(403) - end - end - - test "returns error when user hasn't subscription", %{conn: conn} do - res = - conn - |> get("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(404) - - assert %{"error" => "Record not found"} == res - end - - test "returns a user subsciption", %{conn: conn, user: user, token: token} do - subscription = - insert(:push_subscription, - user: user, - token: token, - data: %{"alerts" => %{"mention" => true}} - ) - - res = - conn - |> get("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(200) - - expect = %{ - "alerts" => %{"mention" => true}, - "endpoint" => "https://example.com/example/1234", - "id" => to_string(subscription.id), - "server_key" => @server_key - } - - assert expect == res - end - end - - describe "updates a user subsciption" do - setup %{conn: conn, user: user, token: token} do - subscription = - insert(:push_subscription, - user: user, - token: token, - data: %{"alerts" => %{"mention" => true}} - ) - - %{conn: conn, user: user, token: token, subscription: subscription} - end - - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}}) - |> json_response_and_validate_schema(403) - end - end - - test "returns updated subsciption", %{conn: conn, subscription: subscription} do - res = - conn - |> put("/api/v1/push/subscription", %{ - data: %{"alerts" => %{"mention" => false, "follow" => true}} - }) - |> json_response_and_validate_schema(200) - - expect = %{ - "alerts" => %{"follow" => true, "mention" => false}, - "endpoint" => "https://example.com/example/1234", - "id" => to_string(subscription.id), - "server_key" => @server_key - } - - assert expect == res - end - end - - describe "deletes the user subscription" do - test "returns error when push disabled ", %{conn: conn} do - assert_error_when_disable_push do - conn - |> delete("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(403) - end - end - - test "returns error when user hasn't subscription", %{conn: conn} do - res = - conn - |> delete("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(404) - - assert %{"error" => "Record not found"} == res - end - - test "returns empty result and delete user subsciption", %{ - conn: conn, - user: user, - token: token - } do - subscription = - insert(:push_subscription, - user: user, - token: token, - data: %{"alerts" => %{"mention" => true}} - ) - - res = - conn - |> delete("/api/v1/push/subscription", %{}) - |> json_response_and_validate_schema(200) - - assert %{} == res - refute Pleroma.Repo.get(Subscription, subscription.id) - end - end -end diff --git a/test/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/web/mastodon_api/controllers/suggestion_controller_test.exs deleted file mode 100644 index 7f08e187c..000000000 --- a/test/web/mastodon_api/controllers/suggestion_controller_test.exs +++ /dev/null @@ -1,18 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do - use Pleroma.Web.ConnCase - - setup do: oauth_access(["read"]) - - test "returns empty result", %{conn: conn} do - res = - conn - |> get("/api/v1/suggestions") - |> json_response_and_validate_schema(200) - - assert res == [] - end -end diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs deleted file mode 100644 index 50e0d783d..000000000 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ /dev/null @@ -1,495 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - import Tesla.Mock - - alias Pleroma.Config - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - describe "home" do - setup do: oauth_access(["read:statuses"]) - - test "does NOT embed account/pleroma/relationship in statuses", %{ - user: user, - conn: conn - } do - other_user = insert(:user) - - {:ok, _} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) - - response = - conn - |> assign(:user, user) - |> get("/api/v1/timelines/home") - |> json_response_and_validate_schema(200) - - assert Enum.all?(response, fn n -> - get_in(n, ["account", "pleroma", "relationship"]) == %{} - end) - end - - test "the home timeline when the direct messages are excluded", %{user: user, conn: conn} do - {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"}) - {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) - - {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"}) - - {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) - - conn = get(conn, "/api/v1/timelines/home?exclude_visibilities[]=direct") - - assert status_ids = json_response_and_validate_schema(conn, :ok) |> Enum.map(& &1["id"]) - assert public_activity.id in status_ids - assert unlisted_activity.id in status_ids - assert private_activity.id in status_ids - refute direct_activity.id in status_ids - end - end - - describe "public" do - @tag capture_log: true - test "the public timeline", %{conn: conn} do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "test"}) - - _activity = insert(:note_activity, local: false) - - conn = get(conn, "/api/v1/timelines/public?local=False") - - assert length(json_response_and_validate_schema(conn, :ok)) == 2 - - conn = get(build_conn(), "/api/v1/timelines/public?local=True") - - assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok) - - conn = get(build_conn(), "/api/v1/timelines/public?local=1") - - assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok) - - # does not contain repeats - {:ok, _} = CommonAPI.repeat(activity.id, user) - - conn = get(build_conn(), "/api/v1/timelines/public?local=true") - - assert [_] = json_response_and_validate_schema(conn, :ok) - end - - test "the public timeline includes only public statuses for an authenticated user" do - %{user: user, conn: conn} = oauth_access(["read:statuses"]) - - {:ok, _activity} = CommonAPI.post(user, %{status: "test"}) - {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "private"}) - {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "unlisted"}) - {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "direct"}) - - res_conn = get(conn, "/api/v1/timelines/public") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - end - - test "doesn't return replies if follower is posting with blocked user" do - %{conn: conn, user: blocker} = oauth_access(["read:statuses"]) - [blockee, friend] = insert_list(2, :user) - {:ok, blocker} = User.follow(blocker, friend) - {:ok, _} = User.block(blocker, blockee) - - conn = assign(conn, :user, blocker) - - {:ok, %{id: activity_id} = activity} = CommonAPI.post(friend, %{status: "hey!"}) - - {:ok, reply_from_blockee} = - CommonAPI.post(blockee, %{status: "heya", in_reply_to_status_id: activity}) - - {:ok, _reply_from_friend} = - CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee}) - - res_conn = get(conn, "/api/v1/timelines/public") - [%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200) - end - - test "doesn't return replies if follow is posting with users from blocked domain" do - %{conn: conn, user: blocker} = oauth_access(["read:statuses"]) - friend = insert(:user) - blockee = insert(:user, ap_id: "https://example.com/users/blocked") - {:ok, blocker} = User.follow(blocker, friend) - {:ok, blocker} = User.block_domain(blocker, "example.com") - - conn = assign(conn, :user, blocker) - - {:ok, %{id: activity_id} = activity} = CommonAPI.post(friend, %{status: "hey!"}) - - {:ok, reply_from_blockee} = - CommonAPI.post(blockee, %{status: "heya", in_reply_to_status_id: activity}) - - {:ok, _reply_from_friend} = - CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee}) - - res_conn = get(conn, "/api/v1/timelines/public") - - activities = json_response_and_validate_schema(res_conn, 200) - [%{"id" => ^activity_id}] = activities - end - end - - defp local_and_remote_activities do - insert(:note_activity) - insert(:note_activity, local: false) - :ok - end - - describe "public with restrict unauthenticated timeline for local and federated timelines" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :timelines, :local], true) - - setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], true) - - test "if user is unauthenticated", %{conn: conn} do - res_conn = get(conn, "/api/v1/timelines/public?local=true") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "authorization required for timeline view" - } - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "authorization required for timeline view" - } - end - - test "if user is authenticated" do - %{conn: conn} = oauth_access(["read:statuses"]) - - res_conn = get(conn, "/api/v1/timelines/public?local=true") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "public with restrict unauthenticated timeline for local" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :timelines, :local], true) - - test "if user is unauthenticated", %{conn: conn} do - res_conn = get(conn, "/api/v1/timelines/public?local=true") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "authorization required for timeline view" - } - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - - test "if user is authenticated", %{conn: _conn} do - %{conn: conn} = oauth_access(["read:statuses"]) - - res_conn = get(conn, "/api/v1/timelines/public?local=true") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "public with restrict unauthenticated timeline for remote" do - setup do: local_and_remote_activities() - - setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], true) - - test "if user is unauthenticated", %{conn: conn} do - res_conn = get(conn, "/api/v1/timelines/public?local=true") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - - assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ - "error" => "authorization required for timeline view" - } - end - - test "if user is authenticated", %{conn: _conn} do - %{conn: conn} = oauth_access(["read:statuses"]) - - res_conn = get(conn, "/api/v1/timelines/public?local=true") - assert length(json_response_and_validate_schema(res_conn, 200)) == 1 - - res_conn = get(conn, "/api/v1/timelines/public?local=false") - assert length(json_response_and_validate_schema(res_conn, 200)) == 2 - end - end - - describe "direct" do - test "direct timeline", %{conn: conn} do - user_one = insert(:user) - user_two = insert(:user) - - {:ok, user_two} = User.follow(user_two, user_one) - - {:ok, direct} = - CommonAPI.post(user_one, %{ - status: "Hi @#{user_two.nickname}!", - visibility: "direct" - }) - - {:ok, _follower_only} = - CommonAPI.post(user_one, %{ - status: "Hi @#{user_two.nickname}!", - visibility: "private" - }) - - conn_user_two = - conn - |> assign(:user, user_two) - |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"])) - - # Only direct should be visible here - res_conn = get(conn_user_two, "api/v1/timelines/direct") - - assert [status] = json_response_and_validate_schema(res_conn, :ok) - - assert %{"visibility" => "direct"} = status - assert status["url"] != direct.data["id"] - - # User should be able to see their own direct message - res_conn = - build_conn() - |> assign(:user, user_one) - |> assign(:token, insert(:oauth_token, user: user_one, scopes: ["read:statuses"])) - |> get("api/v1/timelines/direct") - - [status] = json_response_and_validate_schema(res_conn, :ok) - - assert %{"visibility" => "direct"} = status - - # Both should be visible here - res_conn = get(conn_user_two, "api/v1/timelines/home") - - [_s1, _s2] = json_response_and_validate_schema(res_conn, :ok) - - # Test pagination - Enum.each(1..20, fn _ -> - {:ok, _} = - CommonAPI.post(user_one, %{ - status: "Hi @#{user_two.nickname}!", - visibility: "direct" - }) - end) - - res_conn = get(conn_user_two, "api/v1/timelines/direct") - - statuses = json_response_and_validate_schema(res_conn, :ok) - assert length(statuses) == 20 - - max_id = List.last(statuses)["id"] - - res_conn = get(conn_user_two, "api/v1/timelines/direct?max_id=#{max_id}") - - assert [status] = json_response_and_validate_schema(res_conn, :ok) - - assert status["url"] != direct.data["id"] - end - - test "doesn't include DMs from blocked users" do - %{user: blocker, conn: conn} = oauth_access(["read:statuses"]) - blocked = insert(:user) - other_user = insert(:user) - {:ok, _user_relationship} = User.block(blocker, blocked) - - {:ok, _blocked_direct} = - CommonAPI.post(blocked, %{ - status: "Hi @#{blocker.nickname}!", - visibility: "direct" - }) - - {:ok, direct} = - CommonAPI.post(other_user, %{ - status: "Hi @#{blocker.nickname}!", - visibility: "direct" - }) - - res_conn = get(conn, "api/v1/timelines/direct") - - [status] = json_response_and_validate_schema(res_conn, :ok) - assert status["id"] == direct.id - end - end - - describe "list" do - setup do: oauth_access(["read:lists"]) - - test "list timeline", %{user: user, conn: conn} do - other_user = insert(:user) - {: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) - - conn = get(conn, "/api/v1/timelines/list/#{list.id}") - - assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok) - - assert id == to_string(activity_two.id) - end - - test "list timeline does not leak non-public statuses for unfollowed users", %{ - user: user, - conn: conn - } do - other_user = insert(:user) - {:ok, activity_one} = CommonAPI.post(other_user, %{status: "Marisa is cute."}) - - {:ok, _activity_two} = - CommonAPI.post(other_user, %{ - status: "Marisa is cute.", - visibility: "private" - }) - - {:ok, list} = Pleroma.List.create("name", user) - {:ok, list} = Pleroma.List.follow(list, other_user) - - conn = get(conn, "/api/v1/timelines/list/#{list.id}") - - assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok) - - assert id == to_string(activity_one.id) - end - end - - describe "hashtag" do - setup do: oauth_access(["n/a"]) - - @tag capture_log: true - test "hashtag timeline", %{conn: conn} do - following = insert(:user) - - {:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"}) - - nconn = get(conn, "/api/v1/timelines/tag/2hu") - - assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok) - - assert id == to_string(activity.id) - - # works for different capitalization too - nconn = get(conn, "/api/v1/timelines/tag/2HU") - - assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok) - - assert id == to_string(activity.id) - end - - test "multi-hashtag timeline", %{conn: conn} do - user = insert(:user) - - {:ok, activity_test} = CommonAPI.post(user, %{status: "#test"}) - {:ok, activity_test1} = CommonAPI.post(user, %{status: "#test #test1"}) - {:ok, activity_none} = CommonAPI.post(user, %{status: "#test #none"}) - - any_test = get(conn, "/api/v1/timelines/tag/test?any[]=test1") - - [status_none, status_test1, status_test] = json_response_and_validate_schema(any_test, :ok) - - assert to_string(activity_test.id) == status_test["id"] - assert to_string(activity_test1.id) == status_test1["id"] - assert to_string(activity_none.id) == status_none["id"] - - restricted_test = get(conn, "/api/v1/timelines/tag/test?all[]=test1&none[]=none") - - assert [status_test1] == json_response_and_validate_schema(restricted_test, :ok) - - all_test = get(conn, "/api/v1/timelines/tag/test?all[]=none") - - assert [status_none] == json_response_and_validate_schema(all_test, :ok) - end - end - - describe "hashtag timeline handling of :restrict_unauthenticated setting" do - setup do - user = insert(:user) - {:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"}) - {:ok, _activity2} = CommonAPI.post(user, %{status: "test #tag1"}) - - activity1 - |> Ecto.Changeset.change(%{local: false}) - |> Pleroma.Repo.update() - - base_uri = "/api/v1/timelines/tag/tag1" - error_response = %{"error" => "authorization required for timeline view"} - - %{base_uri: base_uri, error_response: error_response} - end - - defp ensure_authenticated_access(base_uri) do - %{conn: auth_conn} = oauth_access(["read:statuses"]) - - res_conn = get(auth_conn, "#{base_uri}?local=true") - assert length(json_response(res_conn, 200)) == 1 - - res_conn = get(auth_conn, "#{base_uri}?local=false") - assert length(json_response(res_conn, 200)) == 2 - end - - test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{ - conn: conn, - base_uri: base_uri, - error_response: error_response - } do - clear_config([:restrict_unauthenticated, :timelines, :local], true) - clear_config([:restrict_unauthenticated, :timelines, :federated], true) - - for local <- [true, false] do - res_conn = get(conn, "#{base_uri}?local=#{local}") - - assert json_response(res_conn, :unauthorized) == error_response - end - - ensure_authenticated_access(base_uri) - end - - test "with `%{local: false, federated: true}`, forbids unauthenticated access to federated timeline", - %{conn: conn, base_uri: base_uri, error_response: error_response} do - clear_config([:restrict_unauthenticated, :timelines, :local], false) - clear_config([:restrict_unauthenticated, :timelines, :federated], true) - - res_conn = get(conn, "#{base_uri}?local=true") - assert length(json_response(res_conn, 200)) == 1 - - res_conn = get(conn, "#{base_uri}?local=false") - assert json_response(res_conn, :unauthorized) == error_response - - ensure_authenticated_access(base_uri) - end - - test "with `%{local: true, federated: false}`, forbids unauthenticated access to public timeline" <> - "(but not to local public activities which are delivered as part of federated timeline)", - %{conn: conn, base_uri: base_uri, error_response: error_response} do - clear_config([:restrict_unauthenticated, :timelines, :local], true) - clear_config([:restrict_unauthenticated, :timelines, :federated], false) - - res_conn = get(conn, "#{base_uri}?local=true") - assert json_response(res_conn, :unauthorized) == error_response - - # Note: local activities get delivered as part of federated timeline - res_conn = get(conn, "#{base_uri}?local=false") - assert length(json_response(res_conn, 200)) == 2 - - ensure_authenticated_access(base_uri) - 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 deleted file mode 100644 index bb4bc4396..000000000 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ /dev/null @@ -1,34 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do - use Pleroma.Web.ConnCase - - describe "empty_array/2 (stubs)" do - test "GET /api/v1/accounts/:id/identity_proofs" do - %{user: user, conn: conn} = oauth_access(["read:accounts"]) - - assert [] == - conn - |> get("/api/v1/accounts/#{user.id}/identity_proofs") - |> json_response(200) - end - - test "GET /api/v1/endorsements" do - %{conn: conn} = oauth_access(["read:accounts"]) - - assert [] == - conn - |> get("/api/v1/endorsements") - |> json_response(200) - end - - test "GET /api/v1/trends", %{conn: conn} do - assert [] == - conn - |> get("/api/v1/trends") - |> json_response(200) - end - end -end diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs deleted file mode 100644 index c08be37d4..000000000 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ /dev/null @@ -1,104 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do - use Pleroma.Web.ConnCase - - alias Pleroma.Notification - alias Pleroma.ScheduledActivity - alias Pleroma.User - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.MastodonAPI - - import Pleroma.Factory - - describe "follow/3" do - test "returns error when followed user is deactivated" do - follower = insert(:user) - user = insert(:user, local: true, deactivated: true) - {:error, error} = MastodonAPI.follow(follower, user) - assert error == :rejected - end - - test "following for user" do - follower = insert(:user) - user = insert(:user) - {:ok, follower} = MastodonAPI.follow(follower, user) - assert User.following?(follower, user) - end - - test "returns ok if user already followed" do - follower = insert(:user) - user = insert(:user) - {:ok, follower} = User.follow(follower, user) - {:ok, follower} = MastodonAPI.follow(follower, refresh_record(user)) - assert User.following?(follower, user) - end - end - - describe "get_followers/2" do - test "returns user followers" do - follower1_user = insert(:user) - follower2_user = insert(:user) - user = insert(:user) - {:ok, _follower1_user} = User.follow(follower1_user, user) - {:ok, follower2_user} = User.follow(follower2_user, user) - - assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user] - end - end - - describe "get_friends/2" do - test "returns user friends" do - user = insert(:user) - followed_one = insert(:user) - followed_two = insert(:user) - followed_three = insert(:user) - - {:ok, user} = User.follow(user, followed_one) - {:ok, user} = User.follow(user, followed_two) - {:ok, user} = User.follow(user, followed_three) - res = MastodonAPI.get_friends(user) - - assert length(res) == 3 - assert Enum.member?(res, refresh_record(followed_three)) - assert Enum.member?(res, refresh_record(followed_two)) - assert Enum.member?(res, refresh_record(followed_one)) - end - end - - describe "get_notifications/2" do - test "returns notifications for user" do - user = insert(:user) - subscriber = insert(:user) - - User.subscribe(subscriber, user) - - {:ok, status} = CommonAPI.post(user, %{status: "Akariiiin"}) - - {:ok, status1} = CommonAPI.post(user, %{status: "Magi"}) - {:ok, [notification]} = Notification.create_notifications(status) - {:ok, [notification1]} = Notification.create_notifications(status1) - res = MastodonAPI.get_notifications(subscriber) - - assert Enum.member?(Enum.map(res, & &1.id), notification.id) - assert Enum.member?(Enum.map(res, & &1.id), notification1.id) - end - end - - describe "get_scheduled_activities/2" do - test "returns user scheduled activities" do - user = insert(:user) - - today = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(6), :millisecond) - |> NaiveDateTime.to_iso8601() - - attrs = %{params: %{}, scheduled_at: today} - {:ok, schedule} = ScheduledActivity.create(user, attrs) - assert MastodonAPI.get_scheduled_activities(user) == [schedule] - end - end -end diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs deleted file mode 100644 index 8f37efa3c..000000000 --- a/test/web/mastodon_api/views/account_view_test.exs +++ /dev/null @@ -1,570 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.AccountViewTest do - use Pleroma.DataCase - - alias Pleroma.Config - alias Pleroma.User - alias Pleroma.UserRelationship - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.AccountView - - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instances_favicons, :enabled]) - - test "Represent a user account" do - background_image = %{ - "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}] - } - - user = - insert(:user, %{ - follower_count: 3, - note_count: 5, - background: background_image, - nickname: "shp@shitposter.club", - name: ":karjalanpiirakka: shp", - bio: - "<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"", - inserted_at: ~N[2017-08-15 15:47:06.597036], - emoji: %{"karjalanpiirakka" => "/file.png"}, - raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"" - }) - - expected = %{ - id: to_string(user.id), - username: "shp", - acct: user.nickname, - display_name: user.name, - locked: false, - created_at: "2017-08-15T15:47:06.000Z", - followers_count: 3, - following_count: 0, - statuses_count: 5, - note: "<span>valid html</span>. a<br/>b<br/>c<br/>d<br/>f '&<>"", - url: user.ap_id, - avatar: "http://localhost:4001/images/avi.png", - avatar_static: "http://localhost:4001/images/avi.png", - header: "http://localhost:4001/images/banner.png", - header_static: "http://localhost:4001/images/banner.png", - emojis: [ - %{ - static_url: "/file.png", - url: "/file.png", - shortcode: "karjalanpiirakka", - visible_in_picker: false - } - ], - fields: [], - bot: false, - source: %{ - note: "valid html. a\nb\nc\nd\nf '&<>\"", - sensitive: false, - pleroma: %{ - actor_type: "Person", - discoverable: false - }, - fields: [] - }, - pleroma: %{ - ap_id: user.ap_id, - background_image: "https://example.com/images/asuka_hospital.png", - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", - confirmation_pending: false, - tags: [], - is_admin: false, - is_moderator: false, - hide_favorites: true, - hide_followers: false, - hide_follows: false, - hide_followers_count: false, - hide_follows_count: false, - relationship: %{}, - skip_thread_containment: false, - accepts_chat_messages: nil - } - } - - assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - end - - test "Favicon is nil when :instances_favicons is disabled" do - user = insert(:user) - - Config.put([:instances_favicons, :enabled], true) - - assert %{ - pleroma: %{ - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" - } - } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - - Config.put([:instances_favicons, :enabled], false) - - assert %{pleroma: %{favicon: nil}} = - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - end - - test "Represent the user account for the account owner" do - user = insert(:user) - - notification_settings = %{ - block_from_strangers: false, - hide_notification_contents: false - } - - privacy = user.default_scope - - assert %{ - pleroma: %{notification_settings: ^notification_settings, allow_following_move: true}, - source: %{privacy: ^privacy} - } = AccountView.render("show.json", %{user: user, for: user}) - end - - test "Represent a Service(bot) account" do - user = - insert(:user, %{ - follower_count: 3, - note_count: 5, - actor_type: "Service", - nickname: "shp@shitposter.club", - inserted_at: ~N[2017-08-15 15:47:06.597036] - }) - - expected = %{ - id: to_string(user.id), - username: "shp", - acct: user.nickname, - display_name: user.name, - locked: false, - created_at: "2017-08-15T15:47:06.000Z", - followers_count: 3, - following_count: 0, - statuses_count: 5, - note: user.bio, - url: user.ap_id, - avatar: "http://localhost:4001/images/avi.png", - avatar_static: "http://localhost:4001/images/avi.png", - header: "http://localhost:4001/images/banner.png", - header_static: "http://localhost:4001/images/banner.png", - emojis: [], - fields: [], - bot: true, - source: %{ - note: user.bio, - sensitive: false, - pleroma: %{ - actor_type: "Service", - discoverable: false - }, - fields: [] - }, - pleroma: %{ - ap_id: user.ap_id, - background_image: nil, - favicon: - "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", - confirmation_pending: false, - tags: [], - is_admin: false, - is_moderator: false, - hide_favorites: true, - hide_followers: false, - hide_follows: false, - hide_followers_count: false, - hide_follows_count: false, - relationship: %{}, - skip_thread_containment: false, - accepts_chat_messages: nil - } - } - - assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - end - - test "Represent a Funkwhale channel" do - {:ok, user} = - User.get_or_fetch_by_ap_id( - "https://channels.tests.funkwhale.audio/federation/actors/compositions" - ) - - assert represented = - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - - assert represented.acct == "compositions@channels.tests.funkwhale.audio" - assert represented.url == "https://channels.tests.funkwhale.audio/channels/compositions" - end - - test "Represent a deactivated user for an admin" do - admin = insert(:user, is_admin: true) - deactivated_user = insert(:user, deactivated: true) - represented = AccountView.render("show.json", %{user: deactivated_user, for: admin}) - assert represented[:pleroma][:deactivated] == true - end - - test "Represent a smaller mention" do - user = insert(:user) - - expected = %{ - id: to_string(user.id), - acct: user.nickname, - username: user.nickname, - url: user.ap_id - } - - assert expected == AccountView.render("mention.json", %{user: user}) - end - - test "demands :for or :skip_visibility_check option for account rendering" do - clear_config([:restrict_unauthenticated, :profiles, :local], false) - - user = insert(:user) - user_id = user.id - - assert %{id: ^user_id} = AccountView.render("show.json", %{user: user, for: nil}) - assert %{id: ^user_id} = AccountView.render("show.json", %{user: user, for: user}) - - assert %{id: ^user_id} = - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - - assert_raise RuntimeError, ~r/:skip_visibility_check or :for option is required/, fn -> - AccountView.render("show.json", %{user: user}) - end - end - - describe "relationship" do - defp test_relationship_rendering(user, other_user, expected_result) do - opts = %{user: user, target: other_user, relationships: nil} - assert expected_result == AccountView.render("relationship.json", opts) - - relationships_opt = UserRelationship.view_relationships_option(user, [other_user]) - opts = Map.put(opts, :relationships, relationships_opt) - assert expected_result == AccountView.render("relationship.json", opts) - - assert [expected_result] == - AccountView.render("relationships.json", %{user: user, targets: [other_user]}) - end - - @blank_response %{ - following: false, - followed_by: false, - blocking: false, - blocked_by: false, - muting: false, - muting_notifications: false, - subscribing: false, - requested: false, - domain_blocking: false, - showing_reblogs: true, - endorsed: false - } - - test "represent a relationship for the following and followed user" do - user = insert(:user) - other_user = insert(:user) - - {:ok, user} = User.follow(user, other_user) - {:ok, other_user} = User.follow(other_user, user) - {:ok, _subscription} = User.subscribe(user, other_user) - {:ok, _user_relationships} = User.mute(user, other_user, true) - {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, other_user) - - expected = - Map.merge( - @blank_response, - %{ - following: true, - followed_by: true, - muting: true, - muting_notifications: true, - subscribing: true, - showing_reblogs: false, - id: to_string(other_user.id) - } - ) - - test_relationship_rendering(user, other_user, expected) - end - - test "represent a relationship for the blocking and blocked user" do - user = insert(:user) - other_user = insert(:user) - - {:ok, user} = User.follow(user, other_user) - {:ok, _subscription} = User.subscribe(user, other_user) - {:ok, _user_relationship} = User.block(user, other_user) - {:ok, _user_relationship} = User.block(other_user, user) - - expected = - Map.merge( - @blank_response, - %{following: false, blocking: true, blocked_by: true, id: to_string(other_user.id)} - ) - - test_relationship_rendering(user, other_user, expected) - end - - test "represent a relationship for the user blocking a domain" do - user = insert(:user) - other_user = insert(:user, ap_id: "https://bad.site/users/other_user") - - {:ok, user} = User.block_domain(user, "bad.site") - - expected = - Map.merge( - @blank_response, - %{domain_blocking: true, blocking: false, id: to_string(other_user.id)} - ) - - test_relationship_rendering(user, other_user, expected) - end - - test "represent a relationship for the user with a pending follow request" do - user = insert(:user) - other_user = insert(:user, locked: true) - - {:ok, user, other_user, _} = CommonAPI.follow(user, other_user) - user = User.get_cached_by_id(user.id) - other_user = User.get_cached_by_id(other_user.id) - - expected = - Map.merge( - @blank_response, - %{requested: true, following: false, id: to_string(other_user.id)} - ) - - test_relationship_rendering(user, other_user, expected) - end - end - - test "returns the settings store if the requesting user is the represented user and it's requested specifically" do - user = insert(:user, pleroma_settings_store: %{fe: "test"}) - - result = - AccountView.render("show.json", %{user: user, for: user, with_pleroma_settings: true}) - - assert result.pleroma.settings_store == %{:fe => "test"} - - result = AccountView.render("show.json", %{user: user, for: nil, with_pleroma_settings: true}) - assert result.pleroma[:settings_store] == nil - - result = AccountView.render("show.json", %{user: user, for: user}) - assert result.pleroma[:settings_store] == nil - end - - test "doesn't sanitize display names" do - user = insert(:user, name: "<marquee> username </marquee>") - result = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - assert result.display_name == "<marquee> username </marquee>" - end - - test "never display nil user follow counts" do - user = insert(:user, following_count: 0, follower_count: 0) - result = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - - assert result.following_count == 0 - assert result.followers_count == 0 - end - - describe "hiding follows/following" do - test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do - user = - insert(:user, %{ - hide_followers: true, - hide_followers_count: true, - hide_follows: true, - hide_follows_count: true - }) - - other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{ - followers_count: 0, - following_count: 0, - pleroma: %{hide_follows_count: true, hide_followers_count: true} - } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - end - - test "shows when follows/followers are hidden" do - user = insert(:user, hide_followers: true, hide_follows: true) - other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{ - followers_count: 1, - following_count: 1, - pleroma: %{hide_follows: true, hide_followers: true} - } = AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - end - - test "shows actual follower/following count to the account owner" do - user = insert(:user, hide_followers: true, hide_follows: true) - other_user = insert(:user) - {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) - - assert User.following?(user, other_user) - assert Pleroma.FollowingRelationship.follower_count(other_user) == 1 - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{ - followers_count: 1, - following_count: 1 - } = AccountView.render("show.json", %{user: user, for: user}) - end - - test "shows unread_conversation_count only to the account owner" do - user = insert(:user) - other_user = insert(:user) - - {:ok, _activity} = - CommonAPI.post(other_user, %{ - status: "Hey @#{user.nickname}.", - visibility: "direct" - }) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert AccountView.render("show.json", %{user: user, for: other_user})[:pleroma][ - :unread_conversation_count - ] == nil - - assert AccountView.render("show.json", %{user: user, for: user})[:pleroma][ - :unread_conversation_count - ] == 1 - end - - test "shows unread_count only to the account owner" do - user = insert(:user) - insert_list(7, :notification, user: user) - other_user = insert(:user) - - user = User.get_cached_by_ap_id(user.ap_id) - - assert AccountView.render( - "show.json", - %{user: user, for: other_user} - )[:pleroma][:unread_notifications_count] == nil - - assert AccountView.render( - "show.json", - %{user: user, for: user} - )[:pleroma][:unread_notifications_count] == 7 - end - end - - describe "follow requests counter" do - test "shows zero when no follow requests are pending" do - user = insert(:user) - - assert %{follow_requests_count: 0} = - AccountView.render("show.json", %{user: user, for: user}) - - other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{follow_requests_count: 0} = - AccountView.render("show.json", %{user: user, for: user}) - end - - test "shows non-zero when follow requests are pending" do - user = insert(:user, locked: true) - - assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) - - other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{locked: true, follow_requests_count: 1} = - AccountView.render("show.json", %{user: user, for: user}) - end - - test "decreases when accepting a follow request" do - user = insert(:user, locked: true) - - assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) - - other_user = insert(:user) - {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{locked: true, follow_requests_count: 1} = - AccountView.render("show.json", %{user: user, for: user}) - - {:ok, _other_user} = CommonAPI.accept_follow_request(other_user, user) - - assert %{locked: true, follow_requests_count: 0} = - AccountView.render("show.json", %{user: user, for: user}) - end - - test "decreases when rejecting a follow request" do - user = insert(:user, locked: true) - - assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) - - other_user = insert(:user) - {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) - - assert %{locked: true, follow_requests_count: 1} = - AccountView.render("show.json", %{user: user, for: user}) - - {:ok, _other_user} = CommonAPI.reject_follow_request(other_user, user) - - assert %{locked: true, follow_requests_count: 0} = - AccountView.render("show.json", %{user: user, for: user}) - end - - test "shows non-zero when historical unapproved requests are present" do - user = insert(:user, locked: true) - - assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) - - other_user = insert(:user) - {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) - - {:ok, user} = User.update_and_set_cache(user, %{locked: false}) - - assert %{locked: false, follow_requests_count: 1} = - AccountView.render("show.json", %{user: user, for: user}) - end - end - - test "uses mediaproxy urls when it's enabled" do - clear_config([:media_proxy, :enabled], true) - - user = - insert(:user, - avatar: %{"url" => [%{"href" => "https://evil.website/avatar.png"}]}, - banner: %{"url" => [%{"href" => "https://evil.website/banner.png"}]}, - emoji: %{"joker_smile" => "https://evil.website/society.png"} - ) - - AccountView.render("show.json", %{user: user, skip_visibility_check: true}) - |> Enum.all?(fn - {key, url} when key in [:avatar, :avatar_static, :header, :header_static] -> - String.starts_with?(url, Pleroma.Web.base_url()) - - {:emojis, emojis} -> - Enum.all?(emojis, fn %{url: url, static_url: static_url} -> - String.starts_with?(url, Pleroma.Web.base_url()) && - String.starts_with?(static_url, Pleroma.Web.base_url()) - end) - - _ -> - true - end) - |> assert() - end -end diff --git a/test/web/mastodon_api/views/conversation_view_test.exs b/test/web/mastodon_api/views/conversation_view_test.exs deleted file mode 100644 index 2e8203c9b..000000000 --- a/test/web/mastodon_api/views/conversation_view_test.exs +++ /dev/null @@ -1,44 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do - use Pleroma.DataCase - - alias Pleroma.Conversation.Participation - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.ConversationView - - import Pleroma.Factory - - test "represents a Mastodon Conversation entity" do - user = insert(:user) - other_user = insert(:user) - - {:ok, parent} = CommonAPI.post(user, %{status: "parent"}) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "hey @#{other_user.nickname}", - visibility: "direct", - in_reply_to_id: parent.id - }) - - {:ok, _reply_activity} = - CommonAPI.post(user, %{status: "hu", visibility: "public", in_reply_to_id: parent.id}) - - [participation] = Participation.for_user_with_last_activity_id(user) - - assert participation - - conversation = - ConversationView.render("participation.json", %{participation: participation, for: user}) - - assert conversation.id == participation.id |> to_string() - assert conversation.last_status.id == activity.id - - assert [account] = conversation.accounts - assert account.id == other_user.id - assert conversation.last_status.pleroma.direct_conversation_id == participation.id - end -end diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/web/mastodon_api/views/list_view_test.exs deleted file mode 100644 index ca99242cb..000000000 --- a/test/web/mastodon_api/views/list_view_test.exs +++ /dev/null @@ -1,32 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ListViewTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.MastodonAPI.ListView - - test "show" do - user = insert(:user) - title = "mortal enemies" - {:ok, list} = Pleroma.List.create(title, user) - - expected = %{ - id: to_string(list.id), - title: title - } - - assert expected == ListView.render("show.json", %{list: list}) - end - - test "index" do - user = insert(:user) - - {:ok, list} = Pleroma.List.create("my list", user) - {:ok, list2} = Pleroma.List.create("cofe", user) - - assert [%{id: _, title: "my list"}, %{id: _, title: "cofe"}] = - ListView.render("index.json", lists: [list, list2]) - end -end diff --git a/test/web/mastodon_api/views/marker_view_test.exs b/test/web/mastodon_api/views/marker_view_test.exs deleted file mode 100644 index 48a0a6d33..000000000 --- a/test/web/mastodon_api/views/marker_view_test.exs +++ /dev/null @@ -1,29 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do - use Pleroma.DataCase - alias Pleroma.Web.MastodonAPI.MarkerView - import Pleroma.Factory - - test "returns markers" do - marker1 = insert(:marker, timeline: "notifications", last_read_id: "17", unread_count: 5) - marker2 = insert(:marker, timeline: "home", last_read_id: "42") - - assert MarkerView.render("markers.json", %{markers: [marker1, marker2]}) == %{ - "home" => %{ - last_read_id: "42", - updated_at: NaiveDateTime.to_iso8601(marker2.updated_at), - version: 0, - pleroma: %{unread_count: 0} - }, - "notifications" => %{ - last_read_id: "17", - updated_at: NaiveDateTime.to_iso8601(marker1.updated_at), - version: 0, - pleroma: %{unread_count: 5} - } - } - end -end diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs deleted file mode 100644 index 8e0e58538..000000000 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ /dev/null @@ -1,231 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.MastodonAPI.AccountView - alias Pleroma.Web.MastodonAPI.NotificationView - alias Pleroma.Web.MastodonAPI.StatusView - alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView - import Pleroma.Factory - - defp test_notifications_rendering(notifications, user, expected_result) do - result = NotificationView.render("index.json", %{notifications: notifications, for: user}) - - assert expected_result == result - - result = - NotificationView.render("index.json", %{ - notifications: notifications, - for: user, - relationships: nil - }) - - assert expected_result == result - end - - test "ChatMessage notification" do - user = insert(:user) - recipient = insert(:user) - {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "what's up my dude") - - {:ok, [notification]} = Notification.create_notifications(activity) - - object = Object.normalize(activity) - chat = Chat.get(recipient.id, user.ap_id) - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "pleroma:chat_mention", - account: AccountView.render("show.json", %{user: user, for: recipient}), - chat_message: MessageReferenceView.render("show.json", %{chat_message_reference: cm_ref}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], recipient, [expected]) - end - - test "Mention notification" do - user = insert(:user) - mentioned_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{mentioned_user.nickname}"}) - {:ok, [notification]} = Notification.create_notifications(activity) - user = User.get_cached_by_id(user.id) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "mention", - account: - AccountView.render("show.json", %{ - user: user, - for: mentioned_user - }), - status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], mentioned_user, [expected]) - end - - test "Favourite notification" do - user = insert(:user) - another_user = insert(:user) - {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id) - {:ok, [notification]} = Notification.create_notifications(favorite_activity) - create_activity = Activity.get_by_id(create_activity.id) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "favourite", - account: AccountView.render("show.json", %{user: another_user, for: user}), - status: StatusView.render("show.json", %{activity: create_activity, for: user}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], user, [expected]) - end - - test "Reblog notification" do - user = insert(:user) - another_user = insert(:user) - {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, another_user) - {:ok, [notification]} = Notification.create_notifications(reblog_activity) - reblog_activity = Activity.get_by_id(create_activity.id) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "reblog", - account: AccountView.render("show.json", %{user: another_user, for: user}), - status: StatusView.render("show.json", %{activity: reblog_activity, for: user}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], user, [expected]) - end - - test "Follow notification" do - follower = insert(:user) - followed = insert(:user) - {:ok, follower, followed, _activity} = CommonAPI.follow(follower, followed) - notification = Notification |> Repo.one() |> Repo.preload(:activity) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "follow", - account: AccountView.render("show.json", %{user: follower, for: followed}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], followed, [expected]) - - User.perform(:delete, follower) - refute Repo.one(Notification) - end - - @tag capture_log: true - test "Move notification" do - old_user = insert(:user) - new_user = insert(:user, also_known_as: [old_user.ap_id]) - follower = insert(:user) - - old_user_url = old_user.ap_id - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", old_user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock(fn - %{method: :get, url: ^old_user_url} -> - %Tesla.Env{status: 200, body: body} - end) - - User.follow(follower, old_user) - Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) - Pleroma.Tests.ObanHelpers.perform_all() - - old_user = refresh_record(old_user) - new_user = refresh_record(new_user) - - [notification] = Notification.for_user(follower) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "move", - account: AccountView.render("show.json", %{user: old_user, for: follower}), - target: AccountView.render("show.json", %{user: new_user, for: follower}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], follower, [expected]) - end - - test "EmojiReact notification" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - {:ok, _activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - - activity = Repo.get(Activity, activity.id) - - [notification] = Notification.for_user(user) - - assert notification - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: false}, - type: "pleroma:emoji_reaction", - emoji: "☕", - account: AccountView.render("show.json", %{user: other_user, for: user}), - status: StatusView.render("show.json", %{activity: activity, for: user}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], user, [expected]) - end - - test "muted notification" do - user = insert(:user) - another_user = insert(:user) - - {:ok, _} = Pleroma.UserRelationship.create_mute(user, another_user) - {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id) - {:ok, [notification]} = Notification.create_notifications(favorite_activity) - create_activity = Activity.get_by_id(create_activity.id) - - expected = %{ - id: to_string(notification.id), - pleroma: %{is_seen: false, is_muted: true}, - type: "favourite", - account: AccountView.render("show.json", %{user: another_user, for: user}), - status: StatusView.render("show.json", %{activity: create_activity, for: user}), - created_at: Utils.to_masto_date(notification.inserted_at) - } - - test_notifications_rendering([notification], user, [expected]) - end -end diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/web/mastodon_api/views/poll_view_test.exs deleted file mode 100644 index 76672f36c..000000000 --- a/test/web/mastodon_api/views/poll_view_test.exs +++ /dev/null @@ -1,138 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.PollViewTest do - use Pleroma.DataCase - - alias Pleroma.Object - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.MastodonAPI.PollView - - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - 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: to_string(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, - voters_count: nil - } - - result = PollView.render("show.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 - } - }) - - voter = insert(:user) - - object = Object.normalize(activity) - - {:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1]) - - assert match?( - %{ - multiple: true, - voters_count: 1, - votes_count: 2 - }, - PollView.render("show.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"}]} = PollView.render("show.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 = PollView.render("show.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 - - test "does not crash on polls with no end date" do - object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i") - result = PollView.render("show.json", %{object: object}) - - assert result[:expires_at] == nil - assert result[:expired] == false - end -end diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/web/mastodon_api/views/scheduled_activity_view_test.exs deleted file mode 100644 index fbfd873ef..000000000 --- a/test/web/mastodon_api/views/scheduled_activity_view_test.exs +++ /dev/null @@ -1,68 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do - use Pleroma.DataCase - alias Pleroma.ScheduledActivity - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.MastodonAPI.ScheduledActivityView - alias Pleroma.Web.MastodonAPI.StatusView - import Pleroma.Factory - - test "A scheduled activity with a media attachment" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hi"}) - - scheduled_at = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(:timer.minutes(10), :millisecond) - |> NaiveDateTime.to_iso8601() - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - attrs = %{ - params: %{ - "media_ids" => [upload.id], - "status" => "hi", - "sensitive" => true, - "spoiler_text" => "spoiler", - "visibility" => "unlisted", - "in_reply_to_id" => to_string(activity.id) - }, - scheduled_at: scheduled_at - } - - {:ok, scheduled_activity} = ScheduledActivity.create(user, attrs) - result = ScheduledActivityView.render("show.json", %{scheduled_activity: scheduled_activity}) - - expected = %{ - id: to_string(scheduled_activity.id), - media_attachments: - %{media_ids: [upload.id]} - |> Utils.attachments_from_ids() - |> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})), - params: %{ - in_reply_to_id: to_string(activity.id), - media_ids: [upload.id], - poll: nil, - scheduled_at: nil, - sensitive: true, - spoiler_text: "spoiler", - text: "hi", - visibility: "unlisted" - }, - scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at) - } - - assert expected == result - end -end diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs deleted file mode 100644 index 8703d5ba7..000000000 --- a/test/web/mastodon_api/views/status_view_test.exs +++ /dev/null @@ -1,658 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.StatusViewTest do - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Bookmark - alias Pleroma.Conversation.Participation - alias Pleroma.HTML - alias Pleroma.Object - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.UserRelationship - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.MastodonAPI.AccountView - alias Pleroma.Web.MastodonAPI.StatusView - - import Pleroma.Factory - import Tesla.Mock - import OpenApiSpex.TestAssertions - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - test "has an emoji reaction list" do - user = insert(:user) - other_user = insert(:user) - third_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"}) - - {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕") - {:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵") - {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - activity = Repo.get(Activity, activity.id) - status = StatusView.render("show.json", activity: activity) - - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - - assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 2, me: false}, - %{name: "🍵", count: 1, me: false} - ] - - status = StatusView.render("show.json", activity: activity, for: user) - - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - - assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 2, me: true}, - %{name: "🍵", count: 1, me: false} - ] - end - - test "works correctly with badly formatted emojis" do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "yo"}) - - activity - |> Object.normalize(false) - |> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}}) - - activity = Activity.get_by_id(activity.id) - - status = StatusView.render("show.json", activity: activity, for: user) - - assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 1, me: true} - ] - end - - test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"}) - [participation] = Participation.for_user(user) - - status = - StatusView.render("show.json", - activity: activity, - with_direct_conversation_id: true, - for: user - ) - - assert status[:pleroma][:direct_conversation_id] == participation.id - - status = StatusView.render("show.json", activity: activity, for: user) - assert status[:pleroma][:direct_conversation_id] == nil - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "returns the direct conversation id when given the `direct_conversation_id` option" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"}) - [participation] = Participation.for_user(user) - - status = - StatusView.render("show.json", - activity: activity, - direct_conversation_id: participation.id, - for: user - ) - - assert status[:pleroma][:direct_conversation_id] == participation.id - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "returns a temporary ap_id based user for activities missing db users" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"}) - - Repo.delete(user) - Cachex.clear(:user_cache) - - finger_url = - "https://localhost/.well-known/webfinger?resource=acct:#{user.nickname}@localhost" - - Tesla.Mock.mock_global(fn - %{method: :get, url: "http://localhost/.well-known/host-meta"} -> - %Tesla.Env{status: 404, body: ""} - - %{method: :get, url: "https://localhost/.well-known/host-meta"} -> - %Tesla.Env{status: 404, body: ""} - - %{ - method: :get, - url: ^finger_url - } -> - %Tesla.Env{status: 404, body: ""} - end) - - %{account: ms_user} = StatusView.render("show.json", activity: activity) - - assert ms_user.acct == "erroruser@example.com" - end - - test "tries to get a user by nickname if fetching by ap_id doesn't work" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"}) - - {:ok, user} = - user - |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"}) - |> Repo.update() - - Cachex.clear(:user_cache) - - result = StatusView.render("show.json", activity: activity) - - assert result[:account][:id] == to_string(user.id) - assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "a note with null content" do - note = insert(:note_activity) - note_object = Object.normalize(note) - - data = - note_object.data - |> Map.put("content", nil) - - Object.change(note_object, %{data: data}) - |> Object.update_and_set_cache() - - User.get_cached_by_ap_id(note.data["actor"]) - - status = StatusView.render("show.json", %{activity: note}) - - assert status.content == "" - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - end - - 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(object_data["context"]) - - status = StatusView.render("show.json", %{activity: note}) - - created_at = - (object_data["published"] || "") - |> String.replace(~r/\.\d+Z/, ".000Z") - - expected = %{ - id: to_string(note.id), - uri: object_data["id"], - url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note), - account: AccountView.render("show.json", %{user: user, skip_visibility_check: true}), - in_reply_to_id: nil, - in_reply_to_account_id: nil, - card: nil, - reblog: nil, - content: HTML.filter_tags(object_data["content"]), - text: nil, - created_at: created_at, - reblogs_count: 0, - replies_count: 0, - favourites_count: 0, - reblogged: false, - bookmarked: false, - favourited: false, - muted: false, - pinned: false, - sensitive: false, - poll: nil, - spoiler_text: HTML.filter_tags(object_data["summary"]), - visibility: "public", - media_attachments: [], - mentions: [], - tags: [ - %{ - name: "#{object_data["tag"]}", - url: "/tag/#{object_data["tag"]}" - } - ], - application: %{ - name: "Web", - website: nil - }, - language: nil, - emojis: [ - %{ - shortcode: "2hu", - url: "corndog.png", - static_url: "corndog.png", - visible_in_picker: false - } - ], - pleroma: %{ - local: true, - conversation_id: convo_id, - in_reply_to_account_acct: nil, - content: %{"text/plain" => HTML.strip_tags(object_data["content"])}, - spoiler_text: %{"text/plain" => HTML.strip_tags(object_data["summary"])}, - expires_at: nil, - direct_conversation_id: nil, - thread_muted: false, - emoji_reactions: [], - parent_visible: false - } - } - - assert status == expected - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "tells if the message is muted for some reason" do - user = insert(:user) - other_user = insert(:user) - - {:ok, _user_relationships} = User.mute(user, other_user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "test"}) - - relationships_opt = UserRelationship.view_relationships_option(user, [other_user]) - - opts = %{activity: activity} - status = StatusView.render("show.json", opts) - assert status.muted == false - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - - status = StatusView.render("show.json", Map.put(opts, :relationships, relationships_opt)) - assert status.muted == false - - for_opts = %{activity: activity, for: user} - status = StatusView.render("show.json", for_opts) - assert status.muted == true - - status = StatusView.render("show.json", Map.put(for_opts, :relationships, relationships_opt)) - assert status.muted == true - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "tells if the message is thread muted" do - user = insert(:user) - other_user = insert(:user) - - {:ok, _user_relationships} = User.mute(user, other_user) - - {:ok, activity} = CommonAPI.post(other_user, %{status: "test"}) - status = StatusView.render("show.json", %{activity: activity, for: user}) - - assert status.pleroma.thread_muted == false - - {:ok, activity} = CommonAPI.add_mute(user, activity) - - status = StatusView.render("show.json", %{activity: activity, for: user}) - - assert status.pleroma.thread_muted == true - end - - test "tells if the status is bookmarked" do - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Cute girls doing cute things"}) - status = StatusView.render("show.json", %{activity: activity}) - - assert status.bookmarked == false - - status = StatusView.render("show.json", %{activity: activity, for: user}) - - assert status.bookmarked == false - - {:ok, _bookmark} = Bookmark.create(user.id, activity.id) - - activity = Activity.get_by_id_with_object(activity.id) - - status = StatusView.render("show.json", %{activity: activity, for: user}) - - assert status.bookmarked == true - end - - test "a reply" do - note = insert(:note_activity) - user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "he", in_reply_to_status_id: note.id}) - - status = StatusView.render("show.json", %{activity: activity}) - - assert status.in_reply_to_id == to_string(note.id) - - [status] = StatusView.render("index.json", %{activities: [activity], as: :activity}) - - assert status.in_reply_to_id == to_string(note.id) - end - - test "contains mentions" do - user = insert(:user) - mentioned = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "hi @#{mentioned.nickname}"}) - - status = StatusView.render("show.json", %{activity: activity}) - - assert status.mentions == - Enum.map([mentioned], fn u -> AccountView.render("mention.json", %{user: u}) end) - - assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) - 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("show.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("show.json", %{activity: activity}) - - assert length(mentions) == 1 - assert mention.url == recipient.ap_id - end - - test "attachments" do - object = %{ - "type" => "Image", - "url" => [ - %{ - "mediaType" => "image/png", - "href" => "someurl" - } - ], - "uuid" => 6 - } - - expected = %{ - id: "1638338801", - type: "image", - url: "someurl", - remote_url: "someurl", - preview_url: "someurl", - text_url: "someurl", - description: nil, - pleroma: %{mime_type: "image/png"} - } - - api_spec = Pleroma.Web.ApiSpec.spec() - - assert expected == StatusView.render("attachment.json", %{attachment: object}) - assert_schema(expected, "Attachment", api_spec) - - # If theres a "id", use that instead of the generated one - object = Map.put(object, "id", 2) - result = StatusView.render("attachment.json", %{attachment: object}) - - assert %{id: "2"} = result - assert_schema(result, "Attachment", api_spec) - end - - test "put the url advertised in the Activity in to the url attribute" do - id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810" - [activity] = Activity.search(nil, id) - - status = StatusView.render("show.json", %{activity: activity}) - - assert status.uri == id - assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" - end - - test "a reblog" do - user = insert(:user) - activity = insert(:note_activity) - - {:ok, reblog} = CommonAPI.repeat(activity.id, user) - - represented = StatusView.render("show.json", %{for: user, activity: reblog}) - - assert represented[:id] == to_string(reblog.id) - assert represented[:reblog][:id] == to_string(activity.id) - assert represented[:emojis] == [] - assert_schema(represented, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "a peertube video" do - user = insert(:user) - - {:ok, object} = - Pleroma.Object.Fetcher.fetch_object_from_id( - "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" - ) - - %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) - - represented = StatusView.render("show.json", %{for: user, activity: activity}) - - assert represented[:id] == to_string(activity.id) - assert length(represented[:media_attachments]) == 1 - assert_schema(represented, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "funkwhale audio" do - user = insert(:user) - - {:ok, object} = - Pleroma.Object.Fetcher.fetch_object_from_id( - "https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871" - ) - - %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) - - represented = StatusView.render("show.json", %{for: user, activity: activity}) - - assert represented[:id] == to_string(activity.id) - assert length(represented[:media_attachments]) == 1 - end - - test "a Mobilizon event" do - user = insert(:user) - - {:ok, object} = - Pleroma.Object.Fetcher.fetch_object_from_id( - "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39" - ) - - %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) - - represented = StatusView.render("show.json", %{for: user, activity: activity}) - - assert represented[:id] == to_string(activity.id) - end - - describe "build_tags/1" do - test "it returns a a dictionary tags" do - object_tags = [ - "fediverse", - "mastodon", - "nextcloud", - %{ - "href" => "https://kawen.space/users/lain", - "name" => "@lain@kawen.space", - "type" => "Mention" - } - ] - - assert StatusView.build_tags(object_tags) == [ - %{name: "fediverse", url: "/tag/fediverse"}, - %{name: "mastodon", url: "/tag/mastodon"}, - %{name: "nextcloud", url: "/tag/nextcloud"} - ] - end - end - - describe "rich media cards" do - test "a rich media card without a site name renders correctly" do - page_url = "http://example.com" - - card = %{ - url: page_url, - image: page_url <> "/example.jpg", - title: "Example website" - } - - %{provider_name: "example.com"} = - StatusView.render("card.json", %{page_url: page_url, rich_media: card}) - end - - test "a rich media card without a site name or image renders correctly" do - page_url = "http://example.com" - - card = %{ - url: page_url, - title: "Example website" - } - - %{provider_name: "example.com"} = - StatusView.render("card.json", %{page_url: page_url, rich_media: card}) - end - - test "a rich media card without an image renders correctly" do - page_url = "http://example.com" - - card = %{ - url: page_url, - site_name: "Example site name", - title: "Example website" - } - - %{provider_name: "example.com"} = - StatusView.render("card.json", %{page_url: page_url, rich_media: card}) - end - - test "a rich media card with all relevant data renders correctly" do - page_url = "http://example.com" - - card = %{ - url: page_url, - site_name: "Example site name", - title: "Example website", - image: page_url <> "/example.jpg", - description: "Example description" - } - - %{provider_name: "example.com"} = - StatusView.render("card.json", %{page_url: page_url, rich_media: card}) - end - end - - test "does not embed 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("show.json", %{activity: activity, for: other_user}) - - assert result[:account][:pleroma][:relationship] == %{} - assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec()) - end - - test "does not embed a relationship in the account in reposts" do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "˙˙ɐʎns" - }) - - {:ok, activity} = CommonAPI.repeat(activity.id, other_user) - - result = StatusView.render("show.json", %{activity: activity, for: user}) - - assert result[:account][:pleroma][:relationship] == %{} - assert result[:reblog][:account][:pleroma][:relationship] == %{} - assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec()) - 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("show.json", activity: activity) - - assert status.visibility == "list" - end - - test "has a field for parent visibility" do - user = insert(:user) - poster = insert(:user) - - {:ok, invisible} = CommonAPI.post(poster, %{status: "hey", visibility: "private"}) - - {:ok, visible} = - CommonAPI.post(poster, %{status: "hey", visibility: "private", in_reply_to_id: invisible.id}) - - status = StatusView.render("show.json", activity: visible, for: user) - refute status.pleroma.parent_visible - - status = StatusView.render("show.json", activity: visible, for: poster) - assert status.pleroma.parent_visible - end -end diff --git a/test/web/mastodon_api/views/subscription_view_test.exs b/test/web/mastodon_api/views/subscription_view_test.exs deleted file mode 100644 index 981524c0e..000000000 --- a/test/web/mastodon_api/views/subscription_view_test.exs +++ /dev/null @@ -1,23 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MastodonAPI.SubscriptionViewTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.MastodonAPI.SubscriptionView, as: View - alias Pleroma.Web.Push - - test "Represent a subscription" do - subscription = insert(:push_subscription, data: %{"alerts" => %{"mention" => true}}) - - expected = %{ - alerts: %{"mention" => true}, - endpoint: subscription.endpoint, - id: to_string(subscription.id), - server_key: Keyword.get(Push.vapid_config(), :public_key) - } - - assert expected == View.render("show.json", %{subscription: subscription}) - end -end diff --git a/test/web/media_proxy/invalidation_test.exs b/test/web/media_proxy/invalidation_test.exs deleted file mode 100644 index 926ae74ca..000000000 --- a/test/web/media_proxy/invalidation_test.exs +++ /dev/null @@ -1,64 +0,0 @@ -defmodule Pleroma.Web.MediaProxy.InvalidationTest do - use ExUnit.Case - use Pleroma.Tests.Helpers - - alias Pleroma.Config - alias Pleroma.Web.MediaProxy.Invalidation - - import ExUnit.CaptureLog - import Mock - import Tesla.Mock - - setup do: clear_config([:media_proxy]) - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - describe "Invalidation.Http" do - test "perform request to clear cache" do - Config.put([:media_proxy, :enabled], false) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], Invalidation.Http) - - Config.put([Invalidation.Http], method: :purge, headers: [{"x-refresh", 1}]) - image_url = "http://example.com/media/example.jpg" - Pleroma.Web.MediaProxy.put_in_banned_urls(image_url) - - mock(fn - %{ - method: :purge, - url: "http://example.com/media/example.jpg", - headers: [{"x-refresh", 1}] - } -> - %Tesla.Env{status: 200} - end) - - assert capture_log(fn -> - assert Pleroma.Web.MediaProxy.in_banned_urls(image_url) - assert Invalidation.purge([image_url]) == {:ok, [image_url]} - assert Pleroma.Web.MediaProxy.in_banned_urls(image_url) - end) =~ "Running cache purge: [\"#{image_url}\"]" - end - end - - describe "Invalidation.Script" do - test "run script to clear cache" do - Config.put([:media_proxy, :enabled], false) - Config.put([:media_proxy, :invalidation, :enabled], true) - Config.put([:media_proxy, :invalidation, :provider], Invalidation.Script) - Config.put([Invalidation.Script], script_path: "purge-nginx") - - image_url = "http://example.com/media/example.jpg" - Pleroma.Web.MediaProxy.put_in_banned_urls(image_url) - - with_mocks [{System, [], [cmd: fn _, _ -> {"ok", 0} end]}] do - assert capture_log(fn -> - assert Pleroma.Web.MediaProxy.in_banned_urls(image_url) - assert Invalidation.purge([image_url]) == {:ok, [image_url]} - assert Pleroma.Web.MediaProxy.in_banned_urls(image_url) - end) =~ "Running cache purge: [\"#{image_url}\"]" - end - end - end -end diff --git a/test/web/media_proxy/invalidations/http_test.exs b/test/web/media_proxy/invalidations/http_test.exs deleted file mode 100644 index a1bef5237..000000000 --- a/test/web/media_proxy/invalidations/http_test.exs +++ /dev/null @@ -1,39 +0,0 @@ -defmodule Pleroma.Web.MediaProxy.Invalidation.HttpTest do - use ExUnit.Case - alias Pleroma.Web.MediaProxy.Invalidation - - import ExUnit.CaptureLog - import Tesla.Mock - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - test "logs hasn't error message when request is valid" do - mock(fn - %{method: :purge, url: "http://example.com/media/example.jpg"} -> - %Tesla.Env{status: 200} - end) - - refute capture_log(fn -> - assert Invalidation.Http.purge( - ["http://example.com/media/example.jpg"], - [] - ) == {:ok, ["http://example.com/media/example.jpg"]} - end) =~ "Error while cache purge" - end - - test "it write error message in logs when request invalid" do - mock(fn - %{method: :purge, url: "http://example.com/media/example1.jpg"} -> - %Tesla.Env{status: 404} - end) - - assert capture_log(fn -> - assert Invalidation.Http.purge( - ["http://example.com/media/example1.jpg"], - [] - ) == {:ok, ["http://example.com/media/example1.jpg"]} - end) =~ "Error while cache purge: url - http://example.com/media/example1.jpg" - end -end diff --git a/test/web/media_proxy/invalidations/script_test.exs b/test/web/media_proxy/invalidations/script_test.exs deleted file mode 100644 index 51833ab18..000000000 --- a/test/web/media_proxy/invalidations/script_test.exs +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do - use ExUnit.Case - alias Pleroma.Web.MediaProxy.Invalidation - - import ExUnit.CaptureLog - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - test "it logger error when script not found" do - assert capture_log(fn -> - assert Invalidation.Script.purge( - ["http://example.com/media/example.jpg"], - script_path: "./example" - ) == {:error, "%ErlangError{original: :enoent}"} - end) =~ "Error while cache purge: %ErlangError{original: :enoent}" - - capture_log(fn -> - assert Invalidation.Script.purge( - ["http://example.com/media/example.jpg"], - [] - ) == {:error, "\"not found script path\""} - end) - end -end diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs deleted file mode 100644 index d4db44c63..000000000 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ /dev/null @@ -1,121 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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.Web.MediaProxy - alias Pleroma.Web.MediaProxy.MediaProxyController - alias Plug.Conn - - setup do - on_exit(fn -> Cachex.clear(:banned_urls_cache) end) - end - - test "it returns 404 when MediaProxy disabled", %{conn: conn} do - clear_config([:media_proxy, :enabled], false) - - assert %Conn{ - status: 404, - resp_body: "Not Found" - } = get(conn, "/proxy/hhgfh/eeeee") - - assert %Conn{ - status: 404, - resp_body: "Not Found" - } = get(conn, "/proxy/hhgfh/eeee/fff") - end - - describe "" do - setup do - clear_config([:media_proxy, :enabled], true) - clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000") - [url: MediaProxy.encode_url("https://google.fn/test.png")] - end - - test "it returns 403 for invalid signature", %{conn: conn, url: url} do - Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000") - %{path: path} = URI.parse(url) - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, path) - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, "/proxy/hhgfh/eeee") - - assert %Conn{ - status: 403, - resp_body: "Forbidden" - } = get(conn, "/proxy/hhgfh/eeee/fff") - end - - test "redirects on valid url when filename is invalidated", %{conn: conn, url: url} do - invalid_url = String.replace(url, "test.png", "test-file.png") - response = get(conn, invalid_url) - assert response.status == 302 - assert redirected_to(response) == url - end - - test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do - with_mock Pleroma.ReverseProxy, - call: fn _conn, _url, _opts -> %Conn{status: :success} end do - assert %Conn{status: :success} = get(conn, url) - end - end - - test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do - MediaProxy.put_in_banned_urls("https://google.fn/test.png") - - with_mock Pleroma.ReverseProxy, - call: fn _conn, _url, _opts -> %Conn{status: :success} end do - assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url) - end - end - end - - describe "filename_matches/3" do - test "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 "encoded url are tried to match for proxy as `conn.request_path` encodes the url" do - # conn.request_path will return encoded url - request_path = "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg" - - assert MediaProxyController.filename_matches( - true, - request_path, - "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg" - ) == :ok - end - end -end diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs deleted file mode 100644 index 72885cfdd..000000000 --- a/test/web/media_proxy/media_proxy_test.exs +++ /dev/null @@ -1,175 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MediaProxyTest do - use ExUnit.Case - use Pleroma.Tests.Helpers - - alias Pleroma.Web.Endpoint - alias Pleroma.Web.MediaProxy - - describe "when enabled" do - setup do: clear_config([:media_proxy, :enabled], true) - - test "ignores invalid url" do - assert MediaProxy.url(nil) == nil - assert MediaProxy.url("") == nil - end - - test "ignores relative url" do - assert MediaProxy.url("/local") == "/local" - assert MediaProxy.url("/") == "/" - end - - test "ignores local url" do - local_url = Endpoint.url() <> "/hello" - local_root = Endpoint.url() - assert MediaProxy.url(local_url) == local_url - assert MediaProxy.url(local_root) == local_root - end - - test "encodes and decodes URL" do - url = "https://pleroma.soykaf.com/static/logo.png" - encoded = MediaProxy.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 = MediaProxy.url(url) - assert decode_result(encoded) == url - end - - test "encodes and decodes URL without an extension" do - url = "https://pleroma.soykaf.com/path/" - encoded = MediaProxy.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 = MediaProxy.url(url) - assert String.ends_with?(encoded, "/logo.png") - assert decode_result(encoded) == url - end - - test "validates signature" do - encoded = MediaProxy.url("https://pleroma.social") - - clear_config( - [Endpoint, :secret_key_base], - "00000000000000000000000000000000000000000000000" - ) - - [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/") - assert MediaProxy.decode_url(sig, base64) == {:error, :invalid_signature} - end - - test "uses the configured base_url" do - base_url = "https://cache.pleroma.social" - clear_config([:media_proxy, :base_url], base_url) - - url = "https://pleroma.soykaf.com/static/logo.png" - encoded = MediaProxy.url(url) - - assert String.starts_with?(encoded, base_url) - end - - # Some sites expect ASCII encoded characters in the URL to be preserved even if - # unnecessary. - # Issues: https://git.pleroma.social/pleroma/pleroma/issues/580 - # https://git.pleroma.social/pleroma/pleroma/issues/1055 - test "preserve ASCII encoding" do - url = - "https://pleroma.com/%20/%21/%22/%23/%24/%25/%26/%27/%28/%29/%2A/%2B/%2C/%2D/%2E/%2F/%30/%31/%32/%33/%34/%35/%36/%37/%38/%39/%3A/%3B/%3C/%3D/%3E/%3F/%40/%41/%42/%43/%44/%45/%46/%47/%48/%49/%4A/%4B/%4C/%4D/%4E/%4F/%50/%51/%52/%53/%54/%55/%56/%57/%58/%59/%5A/%5B/%5C/%5D/%5E/%5F/%60/%61/%62/%63/%64/%65/%66/%67/%68/%69/%6A/%6B/%6C/%6D/%6E/%6F/%70/%71/%72/%73/%74/%75/%76/%77/%78/%79/%7A/%7B/%7C/%7D/%7E/%7F/%80/%81/%82/%83/%84/%85/%86/%87/%88/%89/%8A/%8B/%8C/%8D/%8E/%8F/%90/%91/%92/%93/%94/%95/%96/%97/%98/%99/%9A/%9B/%9C/%9D/%9E/%9F/%C2%A0/%A1/%A2/%A3/%A4/%A5/%A6/%A7/%A8/%A9/%AA/%AB/%AC/%C2%AD/%AE/%AF/%B0/%B1/%B2/%B3/%B4/%B5/%B6/%B7/%B8/%B9/%BA/%BB/%BC/%BD/%BE/%BF/%C0/%C1/%C2/%C3/%C4/%C5/%C6/%C7/%C8/%C9/%CA/%CB/%CC/%CD/%CE/%CF/%D0/%D1/%D2/%D3/%D4/%D5/%D6/%D7/%D8/%D9/%DA/%DB/%DC/%DD/%DE/%DF/%E0/%E1/%E2/%E3/%E4/%E5/%E6/%E7/%E8/%E9/%EA/%EB/%EC/%ED/%EE/%EF/%F0/%F1/%F2/%F3/%F4/%F5/%F6/%F7/%F8/%F9/%FA/%FB/%FC/%FD/%FE/%FF" - - encoded = MediaProxy.url(url) - assert decode_result(encoded) == url - end - - # This includes unsafe/reserved characters which are not interpreted as part of the URL - # and would otherwise have to be ASCII encoded. It is our role to ensure the proxied URL - # is unmodified, so we are testing these characters anyway. - test "preserve non-unicode characters per RFC3986" do - url = - "https://pleroma.com/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-._~:/?#[]@!$&'()*+,;=|^`{}" - - encoded = MediaProxy.url(url) - assert decode_result(encoded) == url - end - - test "preserve unicode characters" do - url = "https://ko.wikipedia.org/wiki/위키백과:대문" - - encoded = MediaProxy.url(url) - assert decode_result(encoded) == url - end - end - - describe "when disabled" do - setup do: clear_config([:media_proxy, :enabled], false) - - test "does not encode remote urls" do - assert MediaProxy.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} = MediaProxy.decode_url(sig, base64) - decoded - end - - describe "whitelist" do - setup do: clear_config([:media_proxy, :enabled], true) - - test "mediaproxy whitelist" do - clear_config([:media_proxy, :whitelist], ["https://google.com", "https://feld.me"]) - url = "https://feld.me/foo.png" - - unencoded = MediaProxy.url(url) - assert unencoded == url - end - - # TODO: delete after removing support bare domains for media proxy whitelist - test "mediaproxy whitelist bare domains whitelist (deprecated)" do - clear_config([:media_proxy, :whitelist], ["google.com", "feld.me"]) - url = "https://feld.me/foo.png" - - unencoded = MediaProxy.url(url) - assert unencoded == url - end - - test "does not change whitelisted urls" do - clear_config([:media_proxy, :whitelist], ["mycdn.akamai.com"]) - clear_config([:media_proxy, :base_url], "https://cache.pleroma.social") - - media_url = "https://mycdn.akamai.com" - - url = "#{media_url}/static/logo.png" - encoded = MediaProxy.url(url) - - assert String.starts_with?(encoded, media_url) - end - - test "ensure Pleroma.Upload base_url is always whitelisted" do - media_url = "https://media.pleroma.social" - clear_config([Pleroma.Upload, :base_url], media_url) - - url = "#{media_url}/static/logo.png" - encoded = MediaProxy.url(url) - - assert String.starts_with?(encoded, media_url) - end - end -end diff --git a/test/web/metadata/feed_test.exs b/test/web/metadata/feed_test.exs deleted file mode 100644 index e6e5cc5ed..000000000 --- a/test/web/metadata/feed_test.exs +++ /dev/null @@ -1,18 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Metadata.Providers.FeedTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.Metadata.Providers.Feed - - test "it renders a link to user's atom feed" do - user = insert(:user, nickname: "lain") - - assert Feed.build_tags(%{user: user}) == [ - {:link, - [rel: "alternate", type: "application/atom+xml", href: "/users/lain/feed.atom"], []} - ] - end -end diff --git a/test/web/metadata/metadata_test.exs b/test/web/metadata/metadata_test.exs deleted file mode 100644 index 3f8b29e58..000000000 --- a/test/web/metadata/metadata_test.exs +++ /dev/null @@ -1,25 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MetadataTest do - use Pleroma.DataCase, async: true - - import Pleroma.Factory - - describe "restrict indexing remote users" do - test "for remote user" do - user = insert(:user, local: false) - - assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~ - "<meta content=\"noindex, noarchive\" name=\"robots\">" - end - - test "for local user" do - user = insert(:user) - - refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~ - "<meta content=\"noindex, noarchive\" name=\"robots\">" - end - end -end diff --git a/test/web/metadata/opengraph_test.exs b/test/web/metadata/opengraph_test.exs deleted file mode 100644 index 218540e6c..000000000 --- a/test/web/metadata/opengraph_test.exs +++ /dev/null @@ -1,96 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.Metadata.Providers.OpenGraph - - setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) - - test "it renders all supported types of attachments and skips unknown types" do - user = insert(:user) - - 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"} - ] - }, - %{ - "url" => [ - %{ - "mediaType" => "audio/basic", - "href" => "http://www.gnu.org/music/free-software-song.au" - } - ] - } - ] - } - }) - - result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) - - assert Enum.all?( - [ - {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []}, - {:meta, - [property: "og:audio", content: "http://www.gnu.org/music/free-software-song.au"], - []}, - {:meta, [property: "og:video", content: "https://pleroma.gov/about/juche.webm"], - []} - ], - fn element -> element in result end - ) - end - - test "it does not render attachments if post is nsfw" do - Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false) - user = insert(:user, avatar: %{"url" => [%{"href" => "https://pleroma.gov/tenshi.png"}]}) - - note = - insert(:note, %{ - data: %{ - "actor" => user.ap_id, - "id" => "https://pleroma.gov/objects/whatever", - "content" => "#cuteposting #nsfw #hambaga", - "tag" => ["cuteposting", "nsfw", "hambaga"], - "sensitive" => true, - "attachment" => [ - %{ - "url" => [ - %{"mediaType" => "image/png", "href" => "https://misskey.microsoft/corndog.png"} - ] - } - ] - } - }) - - result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user}) - - assert {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []} in result - - refute {:meta, [property: "og:image", content: "https://misskey.microsoft/corndog.png"], []} in result - end -end diff --git a/test/web/metadata/player_view_test.exs b/test/web/metadata/player_view_test.exs deleted file mode 100644 index e6c990242..000000000 --- a/test/web/metadata/player_view_test.exs +++ /dev/null @@ -1,33 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 deleted file mode 100644 index 4107a8459..000000000 --- a/test/web/metadata/rel_me_test.exs +++ /dev/null @@ -1,22 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 - alias Pleroma.Web.Metadata.Providers.RelMe - - test "it renders all links with rel='me' from user bio" do - bio = - ~s(<a href="https://some-link.com">https://some-link.com</a> <a rel="me" href="https://another-link.com">https://another-link.com</a> - <link href="http://some.com"> <link rel="me" href="http://some3.com>") - - user = insert(:user, %{bio: bio}) - - assert RelMe.build_tags(%{user: user}) == [ - {:link, [rel: "me", href: "http://some3.com>"], []}, - {:link, [rel: "me", href: "https://another-link.com"], []} - ] - end -end diff --git a/test/web/metadata/restrict_indexing_test.exs b/test/web/metadata/restrict_indexing_test.exs deleted file mode 100644 index aad0bac42..000000000 --- a/test/web/metadata/restrict_indexing_test.exs +++ /dev/null @@ -1,21 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do - use ExUnit.Case, async: true - - describe "build_tags/1" do - test "for remote user" do - assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ - user: %Pleroma.User{local: false} - }) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}] - end - - test "for local user" do - assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ - user: %Pleroma.User{local: true} - }) == [] - end - end -end diff --git a/test/web/metadata/twitter_card_test.exs b/test/web/metadata/twitter_card_test.exs deleted file mode 100644 index 10931b5ba..000000000 --- a/test/web/metadata/twitter_card_test.exs +++ /dev/null @@ -1,150 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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 - - setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) - - 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 uses summary twittercard if post has no attachment" 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" - } - }) - - 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"], []} - ] == result - end - - test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabled" 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"], []} - ] == 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/metadata/utils_test.exs b/test/web/metadata/utils_test.exs deleted file mode 100644 index 8183256d8..000000000 --- a/test/web/metadata/utils_test.exs +++ /dev/null @@ -1,32 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Metadata.UtilsTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.Metadata.Utils - - describe "scrub_html_and_truncate/1" do - test "it returns text without encode HTML" do - user = insert(:user) - - note = - insert(:note, %{ - data: %{ - "actor" => user.ap_id, - "id" => "https://pleroma.gov/objects/whatever", - "content" => "Pleroma's really cool!" - } - }) - - assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!" - end - end - - describe "scrub_html_and_truncate/2" do - test "it returns text without encode HTML" do - assert Utils.scrub_html_and_truncate("Pleroma's really cool!") == "Pleroma's really cool!" - end - end -end diff --git a/test/web/mongooseim/mongoose_im_controller_test.exs b/test/web/mongooseim/mongoose_im_controller_test.exs deleted file mode 100644 index 5176cde84..000000000 --- a/test/web/mongooseim/mongoose_im_controller_test.exs +++ /dev/null @@ -1,81 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.MongooseIMController do - use Pleroma.Web.ConnCase - import Pleroma.Factory - - test "/user_exists", %{conn: conn} do - _user = insert(:user, nickname: "lain") - _remote_user = insert(:user, nickname: "alice", local: false) - _deactivated_user = insert(:user, nickname: "konata", deactivated: true) - - res = - conn - |> get(mongoose_im_path(conn, :user_exists), user: "lain") - |> json_response(200) - - assert res == true - - res = - conn - |> get(mongoose_im_path(conn, :user_exists), user: "alice") - |> json_response(404) - - assert res == false - - res = - conn - |> get(mongoose_im_path(conn, :user_exists), user: "bob") - |> json_response(404) - - assert res == false - - res = - conn - |> get(mongoose_im_path(conn, :user_exists), user: "konata") - |> json_response(404) - - assert res == false - end - - test "/check_password", %{conn: conn} do - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("cool")) - - _deactivated_user = - insert(:user, - nickname: "konata", - deactivated: true, - password_hash: Pbkdf2.hash_pwd_salt("cool") - ) - - res = - conn - |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "cool") - |> json_response(200) - - assert res == true - - res = - conn - |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "uncool") - |> json_response(403) - - assert res == false - - res = - conn - |> get(mongoose_im_path(conn, :check_password), user: "konata", pass: "cool") - |> json_response(404) - - assert res == false - - res = - conn - |> get(mongoose_im_path(conn, :check_password), user: "nobody", pass: "cool") - |> json_response(404) - - assert res == false - end -end diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs deleted file mode 100644 index 06b33607f..000000000 --- a/test/web/node_info_test.exs +++ /dev/null @@ -1,188 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.NodeInfoTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Config - - setup do: clear_config([:mrf_simple]) - setup do: clear_config(:instance) - - test "GET /.well-known/nodeinfo", %{conn: conn} do - links = - conn - |> get("/.well-known/nodeinfo") - |> json_response(200) - |> Map.fetch!("links") - - Enum.each(links, fn link -> - href = Map.fetch!(link, "href") - - conn - |> get(href) - |> json_response(200) - end) - end - - test "nodeinfo shows staff accounts", %{conn: conn} do - moderator = insert(:user, local: true, is_moderator: true) - admin = insert(:user, local: true, is_admin: true) - - conn = - conn - |> get("/nodeinfo/2.1.json") - - assert result = json_response(conn, 200) - - assert moderator.ap_id in result["metadata"]["staffAccounts"] - assert admin.ap_id in result["metadata"]["staffAccounts"] - end - - test "nodeinfo shows restricted nicknames", %{conn: conn} do - conn = - conn - |> get("/nodeinfo/2.1.json") - - assert result = json_response(conn, 200) - - assert Config.get([Pleroma.User, :restricted_nicknames]) == - result["metadata"]["restrictedNicknames"] - end - - test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do - conn - |> get("/.well-known/nodeinfo") - |> json_response(200) - - conn = - conn - |> get("/nodeinfo/2.1.json") - - assert result = json_response(conn, 200) - assert Pleroma.Application.repository() == result["software"]["repository"] - end - - test "returns fieldsLimits field", %{conn: conn} do - clear_config([:instance, :max_account_fields], 10) - clear_config([:instance, :max_remote_account_fields], 15) - clear_config([:instance, :account_field_name_length], 255) - clear_config([:instance, :account_field_value_length], 2048) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert response["metadata"]["fieldsLimits"]["maxFields"] == 10 - assert response["metadata"]["fieldsLimits"]["maxRemoteFields"] == 15 - assert response["metadata"]["fieldsLimits"]["nameLength"] == 255 - assert response["metadata"]["fieldsLimits"]["valueLength"] == 2048 - end - - test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do - clear_config([:instance, :safe_dm_mentions], true) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert "safe_dm_mentions" in response["metadata"]["features"] - - Config.put([:instance, :safe_dm_mentions], false) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - refute "safe_dm_mentions" in response["metadata"]["features"] - end - - describe "`metadata/federation/enabled`" do - setup do: clear_config([:instance, :federating]) - - test "it shows if federation is enabled/disabled", %{conn: conn} do - Config.put([:instance, :federating], true) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert response["metadata"]["federation"]["enabled"] == true - - Config.put([:instance, :federating], false) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert response["metadata"]["federation"]["enabled"] == false - end - end - - test "it shows default features flags", %{conn: conn} do - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - default_features = [ - "pleroma_api", - "mastodon_api", - "mastodon_api_streaming", - "polls", - "pleroma_explicit_addressing", - "shareable_emoji_packs", - "multifetch", - "pleroma_emoji_reactions", - "pleroma:api/v1/notifications:include_types_filter", - "pleroma_chat_messages" - ] - - assert MapSet.subset?( - MapSet.new(default_features), - MapSet.new(response["metadata"]["features"]) - ) - end - - test "it shows MRF transparency data if enabled", %{conn: conn} do - clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) - clear_config([:mrf, :transparency], true) - - simple_config = %{"reject" => ["example.com"]} - clear_config(:mrf_simple, simple_config) - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert response["metadata"]["federation"]["mrf_simple"] == simple_config - end - - test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do - clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) - clear_config([:mrf, :transparency], true) - clear_config([:mrf, :transparency_exclusions], ["other.site"]) - - simple_config = %{"reject" => ["example.com", "other.site"]} - clear_config(:mrf_simple, simple_config) - - expected_config = %{"reject" => ["example.com"]} - - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) - - assert response["metadata"]["federation"]["mrf_simple"] == expected_config - assert response["metadata"]["federation"]["exclusions"] == true - end -end diff --git a/test/web/oauth/app_test.exs b/test/web/oauth/app_test.exs deleted file mode 100644 index 899af648e..000000000 --- a/test/web/oauth/app_test.exs +++ /dev/null @@ -1,33 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.AppTest do - use Pleroma.DataCase - - alias Pleroma.Web.OAuth.App - import Pleroma.Factory - - describe "get_or_make/2" do - test "gets exist app" do - attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} - app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) - {:ok, %App{} = exist_app} = App.get_or_make(attrs, []) - assert exist_app == app - end - - test "make app" do - attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} - {:ok, %App{} = app} = App.get_or_make(attrs, ["write"]) - assert app.scopes == ["write"] - end - - test "gets exist app and updates scopes" do - attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} - app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) - {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"]) - assert exist_app.id == app.id - assert exist_app.scopes == ["read", "write", "follow", "push"] - end - end -end diff --git a/test/web/oauth/authorization_test.exs b/test/web/oauth/authorization_test.exs deleted file mode 100644 index d74b26cf8..000000000 --- a/test/web/oauth/authorization_test.exs +++ /dev/null @@ -1,77 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.AuthorizationTest do - use Pleroma.DataCase - alias Pleroma.Web.OAuth.App - alias Pleroma.Web.OAuth.Authorization - import Pleroma.Factory - - setup do - {:ok, app} = - Repo.insert( - App.register_changeset(%App{}, %{ - client_name: "client", - scopes: ["read", "write"], - redirect_uris: "url" - }) - ) - - %{app: app} - end - - test "create an authorization token for a valid app", %{app: app} do - user = insert(:user) - - {:ok, auth1} = Authorization.create_authorization(app, user) - assert auth1.scopes == app.scopes - - {:ok, auth2} = Authorization.create_authorization(app, user, ["read"]) - assert auth2.scopes == ["read"] - - for auth <- [auth1, auth2] do - assert auth.user_id == user.id - assert auth.app_id == app.id - assert String.length(auth.token) > 10 - assert auth.used == false - end - end - - test "use up a token", %{app: app} do - user = insert(:user) - - {:ok, auth} = Authorization.create_authorization(app, user) - - {:ok, auth} = Authorization.use_token(auth) - - assert auth.used == true - - assert {:error, "already used"} == Authorization.use_token(auth) - - expired_auth = %Authorization{ - user_id: user.id, - app_id: app.id, - valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -10), - token: "mytoken", - used: false - } - - {:ok, expired_auth} = Repo.insert(expired_auth) - - assert {:error, "token expired"} == Authorization.use_token(expired_auth) - end - - test "delete authorizations", %{app: app} do - user = insert(:user) - - {:ok, auth} = Authorization.create_authorization(app, user) - {:ok, auth} = Authorization.use_token(auth) - - Authorization.delete_user_authorizations(user) - - {_, invalid} = Authorization.use_token(auth) - - assert auth != invalid - end -end diff --git a/test/web/oauth/ldap_authorization_test.exs b/test/web/oauth/ldap_authorization_test.exs deleted file mode 100644 index 011642c08..000000000 --- a/test/web/oauth/ldap_authorization_test.exs +++ /dev/null @@ -1,182 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do - use Pleroma.Web.ConnCase - alias Pleroma.Repo - alias Pleroma.Web.OAuth.Token - import Pleroma.Factory - import ExUnit.CaptureLog - import Mock - - @skip if !Code.ensure_loaded?(:eldap), do: :skip - - setup_all do: clear_config([:ldap, :enabled], true) - - setup_all do: clear_config(Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.LDAPAuthenticator) - - @tag @skip - test "authorizes the existing user using LDAP credentials" do - password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - app = insert(:oauth_app, scopes: ["read", "write"]) - - host = Pleroma.Config.get([:ldap, :host]) |> to_charlist - port = Pleroma.Config.get([:ldap, :port]) - - with_mocks [ - {:eldap, [], - [ - open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, - simple_bind: fn _connection, _dn, ^password -> :ok end, - close: fn _connection -> - send(self(), :close_connection) - :ok - end - ]} - ] do - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token} = json_response(conn, 200) - - token = Repo.get_by(Token, token: token) - - assert token.user_id == user.id - assert_received :close_connection - end - end - - @tag @skip - test "creates a new user after successful LDAP authorization" do - password = "testpassword" - user = build(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - host = Pleroma.Config.get([:ldap, :host]) |> to_charlist - port = Pleroma.Config.get([:ldap, :port]) - - with_mocks [ - {:eldap, [], - [ - open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, - simple_bind: fn _connection, _dn, ^password -> :ok end, - equalityMatch: fn _type, _value -> :ok end, - wholeSubtree: fn -> :ok end, - search: fn _connection, _options -> - {:ok, - {:eldap_search_result, [{:eldap_entry, '', [{'mail', [to_charlist(user.email)]}]}], - []}} - end, - close: fn _connection -> - send(self(), :close_connection) - :ok - end - ]} - ] do - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token} = json_response(conn, 200) - - token = Repo.get_by(Token, token: token) |> Repo.preload(:user) - - assert token.user.nickname == user.nickname - assert_received :close_connection - end - end - - @tag @skip - test "falls back to the default authorization when LDAP is unavailable" do - password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - app = insert(:oauth_app, scopes: ["read", "write"]) - - host = Pleroma.Config.get([:ldap, :host]) |> to_charlist - port = Pleroma.Config.get([:ldap, :port]) - - with_mocks [ - {:eldap, [], - [ - open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:error, 'connect failed'} end, - simple_bind: fn _connection, _dn, ^password -> :ok end, - close: fn _connection -> - send(self(), :close_connection) - :ok - end - ]} - ] do - log = - capture_log(fn -> - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token} = json_response(conn, 200) - - token = Repo.get_by(Token, token: token) - - assert token.user_id == user.id - end) - - assert log =~ "Could not open LDAP connection: 'connect failed'" - refute_received :close_connection - end - end - - @tag @skip - test "disallow authorization for wrong LDAP credentials" do - password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - app = insert(:oauth_app, scopes: ["read", "write"]) - - host = Pleroma.Config.get([:ldap, :host]) |> to_charlist - port = Pleroma.Config.get([:ldap, :port]) - - with_mocks [ - {:eldap, [], - [ - open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, - simple_bind: fn _connection, _dn, ^password -> {:error, :invalidCredentials} end, - close: fn _connection -> - send(self(), :close_connection) - :ok - end - ]} - ] do - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"error" => "Invalid credentials"} = json_response(conn, 400) - assert_received :close_connection - end - end -end diff --git a/test/web/oauth/mfa_controller_test.exs b/test/web/oauth/mfa_controller_test.exs deleted file mode 100644 index 3c341facd..000000000 --- a/test/web/oauth/mfa_controller_test.exs +++ /dev/null @@ -1,306 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.MFAControllerTest do - use Pleroma.Web.ConnCase - import Pleroma.Factory - - alias Pleroma.MFA - alias Pleroma.MFA.BackupCodes - alias Pleroma.MFA.TOTP - alias Pleroma.Repo - alias Pleroma.Web.OAuth.Authorization - alias Pleroma.Web.OAuth.OAuthController - - setup %{conn: conn} do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - backup_codes: [Pbkdf2.hash_pwd_salt("test-code")], - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - app = insert(:oauth_app) - {:ok, conn: conn, user: user, app: app} - end - - describe "show" do - setup %{conn: conn, user: user, app: app} do - mfa_token = - insert(:mfa_token, - user: user, - authorization: build(:oauth_authorization, app: app, scopes: ["write"]) - ) - - {:ok, conn: conn, mfa_token: mfa_token} - end - - test "GET /oauth/mfa renders mfa forms", %{conn: conn, mfa_token: mfa_token} do - conn = - get( - conn, - "/oauth/mfa", - %{ - "mfa_token" => mfa_token.token, - "state" => "a_state", - "redirect_uri" => "http://localhost:8080/callback" - } - ) - - assert response = html_response(conn, 200) - assert response =~ "Two-factor authentication" - assert response =~ mfa_token.token - assert response =~ "http://localhost:8080/callback" - end - - test "GET /oauth/mfa renders mfa recovery forms", %{conn: conn, mfa_token: mfa_token} do - conn = - get( - conn, - "/oauth/mfa", - %{ - "mfa_token" => mfa_token.token, - "state" => "a_state", - "redirect_uri" => "http://localhost:8080/callback", - "challenge_type" => "recovery" - } - ) - - assert response = html_response(conn, 200) - assert response =~ "Two-factor recovery" - assert response =~ mfa_token.token - assert response =~ "http://localhost:8080/callback" - end - end - - describe "verify" do - setup %{conn: conn, user: user, app: app} do - mfa_token = - insert(:mfa_token, - user: user, - authorization: build(:oauth_authorization, app: app, scopes: ["write"]) - ) - - {:ok, conn: conn, user: user, mfa_token: mfa_token, app: app} - end - - test "POST /oauth/mfa/verify, verify totp code", %{ - conn: conn, - user: user, - mfa_token: mfa_token, - app: app - } do - otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret) - - conn = - conn - |> post("/oauth/mfa/verify", %{ - "mfa" => %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "totp", - "code" => otp_token, - "state" => "a_state", - "redirect_uri" => OAuthController.default_redirect_uri(app) - } - }) - - target = redirected_to(conn) - target_url = %URI{URI.parse(target) | query: nil} |> URI.to_string() - query = URI.parse(target).query |> URI.query_decoder() |> Map.new() - assert %{"state" => "a_state", "code" => code} = query - assert target_url == OAuthController.default_redirect_uri(app) - auth = Repo.get_by(Authorization, token: code) - assert auth.scopes == ["write"] - end - - test "POST /oauth/mfa/verify, verify recovery code", %{ - conn: conn, - mfa_token: mfa_token, - app: app - } do - conn = - conn - |> post("/oauth/mfa/verify", %{ - "mfa" => %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "recovery", - "code" => "test-code", - "state" => "a_state", - "redirect_uri" => OAuthController.default_redirect_uri(app) - } - }) - - target = redirected_to(conn) - target_url = %URI{URI.parse(target) | query: nil} |> URI.to_string() - query = URI.parse(target).query |> URI.query_decoder() |> Map.new() - assert %{"state" => "a_state", "code" => code} = query - assert target_url == OAuthController.default_redirect_uri(app) - auth = Repo.get_by(Authorization, token: code) - assert auth.scopes == ["write"] - end - end - - describe "challenge/totp" do - test "returns access token with valid code", %{conn: conn, user: user, app: app} do - otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret) - - mfa_token = - insert(:mfa_token, - user: user, - authorization: build(:oauth_authorization, app: app, scopes: ["write"]) - ) - - response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "totp", - "code" => otp_token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(:ok) - - ap_id = user.ap_id - - assert match?( - %{ - "access_token" => _, - "expires_in" => 600, - "me" => ^ap_id, - "refresh_token" => _, - "scope" => "write", - "token_type" => "Bearer" - }, - response - ) - end - - test "returns errors when mfa token invalid", %{conn: conn, user: user, app: app} do - otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret) - - response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => "XXX", - "challenge_type" => "totp", - "code" => otp_token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(400) - - assert response == %{"error" => "Invalid code"} - end - - test "returns error when otp code is invalid", %{conn: conn, user: user, app: app} do - mfa_token = insert(:mfa_token, user: user) - - response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "totp", - "code" => "XXX", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(400) - - assert response == %{"error" => "Invalid code"} - end - - test "returns error when client credentails is wrong ", %{conn: conn, user: user} do - otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret) - mfa_token = insert(:mfa_token, user: user) - - response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "totp", - "code" => otp_token, - "client_id" => "xxx", - "client_secret" => "xxx" - }) - |> json_response(400) - - assert response == %{"error" => "Invalid code"} - end - end - - describe "challenge/recovery" do - setup %{conn: conn} do - app = insert(:oauth_app) - {:ok, conn: conn, app: app} - end - - test "returns access token with valid code", %{conn: conn, app: app} do - otp_secret = TOTP.generate_secret() - - [code | _] = backup_codes = BackupCodes.generate() - - hashed_codes = - backup_codes - |> Enum.map(&Pbkdf2.hash_pwd_salt(&1)) - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - backup_codes: hashed_codes, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - mfa_token = - insert(:mfa_token, - user: user, - authorization: build(:oauth_authorization, app: app, scopes: ["write"]) - ) - - response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "recovery", - "code" => code, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(:ok) - - ap_id = user.ap_id - - assert match?( - %{ - "access_token" => _, - "expires_in" => 600, - "me" => ^ap_id, - "refresh_token" => _, - "scope" => "write", - "token_type" => "Bearer" - }, - response - ) - - error_response = - conn - |> post("/oauth/mfa/challenge", %{ - "mfa_token" => mfa_token.token, - "challenge_type" => "recovery", - "code" => code, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(400) - - assert error_response == %{"error" => "Invalid code"} - end - end -end diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs deleted file mode 100644 index d389e4ce0..000000000 --- a/test/web/oauth/oauth_controller_test.exs +++ /dev/null @@ -1,1205 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.OAuthControllerTest do - use Pleroma.Web.ConnCase - import Pleroma.Factory - - alias Pleroma.MFA - alias Pleroma.MFA.TOTP - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.OAuth.Authorization - alias Pleroma.Web.OAuth.OAuthController - alias Pleroma.Web.OAuth.Token - - @session_opts [ - store: :cookie, - key: "_test", - signing_salt: "cooldude" - ] - setup do: clear_config([:instance, :account_activation_required]) - - describe "in OAuth consumer mode, " do - setup do - [ - app: insert(:oauth_app), - conn: - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - ] - end - - setup do: clear_config([:auth, :oauth_consumer_strategies], ~w(twitter facebook)) - - test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{ - app: app, - conn: conn - } do - conn = - get( - conn, - "/oauth/authorize", - %{ - "response_type" => "code", - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "scope" => "read" - } - ) - - assert response = html_response(conn, 200) - assert response =~ "Sign in with Twitter" - assert response =~ o_auth_path(conn, :prepare_request) - end - - test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %{ - app: app, - conn: conn - } do - conn = - get( - conn, - "/oauth/prepare_request", - %{ - "provider" => "twitter", - "authorization" => %{ - "scope" => "read follow", - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "a_state" - } - } - ) - - assert response = html_response(conn, 302) - - redirect_query = URI.parse(redirected_to(conn)).query - assert %{"state" => state_param} = URI.decode_query(redirect_query) - assert {:ok, state_components} = Poison.decode(state_param) - - expected_client_id = app.client_id - expected_redirect_uri = app.redirect_uris - - assert %{ - "scope" => "read follow", - "client_id" => ^expected_client_id, - "redirect_uri" => ^expected_redirect_uri, - "state" => "a_state" - } = state_components - end - - 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" => redirect_uri, - "state" => "" - } - - conn = - conn - |> assign(:ueberauth_auth, %{provider: registration.provider, uid: registration.uid}) - |> get( - "/oauth/twitter/callback", - %{ - "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", - "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", - "provider" => "twitter", - "state" => Poison.encode!(state_params) - } - ) - - assert response = html_response(conn, 302) - assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ - end - - test "with user-unbound registration, GET /oauth/<provider>/callback renders registration_details page", - %{app: app, conn: conn} do - user = insert(:user) - - state_params = %{ - "scope" => "read write", - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "a_state" - } - - conn = - conn - |> assign(:ueberauth_auth, %{ - provider: "twitter", - uid: "171799000", - info: %{nickname: user.nickname, email: user.email, name: user.name, description: nil} - }) - |> get( - "/oauth/twitter/callback", - %{ - "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", - "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", - "provider" => "twitter", - "state" => Poison.encode!(state_params) - } - ) - - assert response = html_response(conn, 200) - assert response =~ ~r/name="op" type="submit" value="register"/ - assert response =~ ~r/name="op" type="submit" value="connect"/ - assert response =~ user.email - assert response =~ user.nickname - end - - test "on authentication error, GET /oauth/<provider>/callback redirects to `redirect_uri`", %{ - app: app, - conn: conn - } do - state_params = %{ - "scope" => Enum.join(app.scopes, " "), - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "" - } - - conn = - conn - |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]}) - |> get( - "/oauth/twitter/callback", - %{ - "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", - "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", - "provider" => "twitter", - "state" => Poison.encode!(state_params) - } - ) - - assert response = html_response(conn, 302) - assert redirected_to(conn) == app.redirect_uris - assert get_flash(conn, :error) == "Failed to authenticate: (error description)." - end - - test "GET /oauth/registration_details renders registration details form", %{ - app: app, - conn: conn - } do - conn = - get( - conn, - "/oauth/registration_details", - %{ - "authorization" => %{ - "scopes" => app.scopes, - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "a_state", - "nickname" => nil, - "email" => "john@doe.com" - } - } - ) - - assert response = html_response(conn, 200) - assert response =~ ~r/name="op" type="submit" value="register"/ - assert response =~ ~r/name="op" type="submit" value="connect"/ - end - - test "with valid params, POST /oauth/register?op=register redirects to `redirect_uri` with `code`", - %{ - app: app, - conn: conn - } do - registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil}) - redirect_uri = OAuthController.default_redirect_uri(app) - - conn = - conn - |> put_session(:registration_id, registration.id) - |> post( - "/oauth/register", - %{ - "op" => "register", - "authorization" => %{ - "scopes" => app.scopes, - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "a_state", - "nickname" => "availablenick", - "email" => "available@email.com" - } - } - ) - - assert response = html_response(conn, 302) - 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", - %{ - app: app, - conn: conn - } do - another_user = insert(:user) - registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil}) - - params = %{ - "op" => "register", - "authorization" => %{ - "scopes" => app.scopes, - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "a_state", - "nickname" => "availablenickname", - "email" => "available@email.com" - } - } - - for {bad_param, bad_param_value} <- - [{"nickname", another_user.nickname}, {"email", another_user.email}] do - bad_registration_attrs = %{ - "authorization" => Map.put(params["authorization"], bad_param, bad_param_value) - } - - bad_params = Map.merge(params, bad_registration_attrs) - - conn = - conn - |> put_session(:registration_id, registration.id) - |> post("/oauth/register", bad_params) - - assert html_response(conn, 403) =~ ~r/name="op" type="submit" value="register"/ - assert get_flash(conn, :error) == "Error: #{bad_param} has already been taken." - end - end - - test "with valid params, POST /oauth/register?op=connect redirects to `redirect_uri` with `code`", - %{ - app: app, - conn: conn - } do - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("testpassword")) - registration = insert(:registration, user: nil) - redirect_uri = OAuthController.default_redirect_uri(app) - - conn = - conn - |> put_session(:registration_id, registration.id) - |> post( - "/oauth/register", - %{ - "op" => "connect", - "authorization" => %{ - "scopes" => app.scopes, - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "a_state", - "name" => user.nickname, - "password" => "testpassword" - } - } - ) - - assert response = html_response(conn, 302) - 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: Pbkdf2.hash_pwd_salt("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", - %{ - app: app, - conn: conn - } do - user = insert(:user) - registration = insert(:registration, user: nil) - - params = %{ - "op" => "connect", - "authorization" => %{ - "scopes" => app.scopes, - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "a_state", - "name" => user.nickname, - "password" => "wrong password" - } - } - - conn = - conn - |> put_session(:registration_id, registration.id) - |> post("/oauth/register", params) - - assert html_response(conn, 401) =~ ~r/name="op" type="submit" value="connect"/ - assert get_flash(conn, :error) == "Invalid Username/Password" - end - end - - describe "GET /oauth/authorize" do - setup do - [ - app: insert(:oauth_app, redirect_uris: "https://redirect.url"), - conn: - build_conn() - |> Plug.Session.call(Plug.Session.init(@session_opts)) - |> fetch_session() - ] - end - - test "renders authentication page", %{app: app, conn: conn} do - conn = - get( - conn, - "/oauth/authorize", - %{ - "response_type" => "code", - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "scope" => "read" - } - ) - - assert html_response(conn, 200) =~ ~s(type="submit") - end - - test "properly handles internal calls with `authorization`-wrapped params", %{ - app: app, - conn: conn - } do - conn = - get( - conn, - "/oauth/authorize", - %{ - "authorization" => %{ - "response_type" => "code", - "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "scope" => "read" - } - } - ) - - assert html_response(conn, 200) =~ ~s(type="submit") - end - - test "renders authentication page if user is already authenticated but `force_login` is tru-ish", - %{app: app, conn: conn} do - token = insert(:oauth_token, app: app) - - 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), - "scope" => "read", - "force_login" => "true" - } - ) - - assert html_response(conn, 200) =~ ~s(type="submit") - end - - test "renders authentication page if user is already authenticated but user request with another client", - %{ - app: app, - conn: conn - } do - token = insert(:oauth_token, app: app) - - conn = - conn - |> put_session(:oauth_token, token.token) - |> get( - "/oauth/authorize", - %{ - "response_type" => "code", - "client_id" => "another_client_id", - "redirect_uri" => OAuthController.default_redirect_uri(app), - "scope" => "read" - } - ) - - assert html_response(conn, 200) =~ ~s(type="submit") - end - - 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: app) - - 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: app) - - 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: app) - - conn = - conn - |> put_session(:oauth_token, token.token) - |> get( - "/oauth/authorize", - %{ - "response_type" => "code", - "client_id" => app.client_id, - "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", - "scope" => "read" - } - ) - - assert html_response(conn, 200) =~ "Authorization exists" - end - end - - describe "POST /oauth/authorize" do - test "redirects with oauth authorization, " <> - "granting requested app-supported scopes to both admin- and non-admin users" do - app_scopes = ["read", "write", "admin", "secret_scope"] - app = insert(:oauth_app, scopes: app_scopes) - redirect_uri = OAuthController.default_redirect_uri(app) - - non_admin = insert(:user, is_admin: false) - admin = insert(:user, is_admin: true) - scopes_subset = ["read:subscope", "write", "admin"] - - # In case scope param is missing, expecting _all_ app-supported scopes to be granted - for user <- [non_admin, admin], - {requested_scopes, expected_scopes} <- - %{scopes_subset => scopes_subset, nil: app_scopes} do - conn = - post( - build_conn(), - "/oauth/authorize", - %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "scope" => requested_scopes, - "state" => "statepassed" - } - } - ) - - target = redirected_to(conn) - assert target =~ redirect_uri - - query = URI.parse(target).query |> URI.query_decoder() |> Map.new() - - assert %{"state" => "statepassed", "code" => code} = query - auth = Repo.get_by(Authorization, token: code) - assert auth - assert auth.scopes == expected_scopes - end - end - - test "redirect to on two-factor auth page" do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - app = insert(:oauth_app, scopes: ["read", "write", "follow"]) - - conn = - build_conn() - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => app.redirect_uris, - "scope" => "read write", - "state" => "statepassed" - } - }) - - result = html_response(conn, 200) - - mfa_token = Repo.get_by(MFA.Token, user_id: user.id) - assert result =~ app.redirect_uris - assert result =~ "statepassed" - assert result =~ mfa_token.token - assert result =~ "Two-factor authentication" - end - - 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 - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "wrong", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "statepassed", - "scope" => Enum.join(app.scopes, " ") - } - }) - |> html_response(:unauthorized) - - # Keep the details - assert result =~ app.client_id - assert result =~ redirect_uri - - # Error message - assert result =~ "Invalid Username/Password" - end - - test "returns 401 for missing scopes" do - user = insert(:user, is_admin: false) - app = insert(:oauth_app, scopes: ["read", "write", "admin"]) - redirect_uri = OAuthController.default_redirect_uri(app) - - result = - build_conn() - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "statepassed", - "scope" => "" - } - }) - |> html_response(:unauthorized) - - # Keep the details - assert result =~ app.client_id - assert result =~ redirect_uri - - # Error message - assert result =~ "This action is outside the authorized scopes" - end - - test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - redirect_uri = OAuthController.default_redirect_uri(app) - - result = - conn - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "statepassed", - "scope" => "read write follow" - } - }) - |> html_response(:unauthorized) - - # Keep the details - assert result =~ app.client_id - assert result =~ redirect_uri - - # Error message - assert result =~ "This action is outside the authorized scopes" - end - end - - describe "POST /oauth/token" do - test "issues a token for an all-body request" do - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) - - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => auth.token, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200) - - token = Repo.get_by(Token, token: token) - assert token - assert token.scopes == auth.scopes - assert user.ap_id == ap_id - end - - test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do - password = "testpassword" - user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - - app = insert(:oauth_app, scopes: ["read", "write"]) - - # Note: "scope" param is intentionally omitted - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token} = json_response(conn, 200) - - token = Repo.get_by(Token, token: token) - assert token - assert token.scopes == app.scopes - end - - test "issues a mfa token for `password` grant_type, when MFA enabled" do - password = "testpassword" - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - app = insert(:oauth_app, scopes: ["read", "write"]) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(403) - - assert match?( - %{ - "supported_challenge_types" => "totp", - "mfa_token" => _, - "error" => "mfa_required" - }, - response - ) - - token = Repo.get_by(MFA.Token, token: response["mfa_token"]) - assert token.user_id == user.id - assert token.authorization_id - end - - test "issues a token for request with HTTP basic auth client credentials" do - user = insert(:user) - app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"]) - assert auth.scopes == ["scope1", "scope2"] - - app_encoded = - (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret)) - |> Base.encode64() - - conn = - build_conn() - |> put_req_header("authorization", "Basic " <> app_encoded) - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => auth.token, - "redirect_uri" => OAuthController.default_redirect_uri(app) - }) - - assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200) - - assert scope == "scope1 scope2" - - token = Repo.get_by(Token, token: token) - assert token - assert token.scopes == ["scope1", "scope2"] - end - - test "issue a token for client_credentials grant type" do - app = insert(:oauth_app, scopes: ["read", "write"]) - - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "client_credentials", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} = - json_response(conn, 200) - - assert token - token_from_db = Repo.get_by(Token, token: token) - assert token_from_db - assert refresh - assert scope == "read write" - end - - test "rejects token exchange with invalid client credentials" do - user = insert(:user) - app = insert(:oauth_app) - - {:ok, auth} = Authorization.create_authorization(app, user) - - conn = - build_conn() - |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=") - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => auth.token, - "redirect_uri" => OAuthController.default_redirect_uri(app) - }) - - assert resp = json_response(conn, 400) - assert %{"error" => _} = resp - refute Map.has_key?(resp, "access_token") - end - - test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do - Pleroma.Config.put([:instance, :account_activation_required], true) - password = "testpassword" - - {:ok, user} = - insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password)) - |> User.confirmation_changeset(need_confirmation: true) - |> User.update_and_set_cache() - - refute Pleroma.User.account_status(user) == :active - - app = insert(:oauth_app) - - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert resp = json_response(conn, 403) - assert %{"error" => _} = resp - refute Map.has_key?(resp, "access_token") - end - - test "rejects token exchange for valid credentials belonging to deactivated user" do - password = "testpassword" - - user = - insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - deactivated: true - ) - - app = insert(:oauth_app) - - resp = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(403) - - assert resp == %{ - "error" => "Your account is currently disabled", - "identifier" => "account_is_disabled" - } - end - - test "rejects token exchange for user with password_reset_pending set to true" do - password = "testpassword" - - user = - insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - password_reset_pending: true - ) - - app = insert(:oauth_app, scopes: ["read", "write"]) - - resp = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(403) - - assert resp == %{ - "error" => "Password reset is required", - "identifier" => "password_reset_required" - } - end - - test "rejects token exchange for user with confirmation_pending set to true" do - Pleroma.Config.put([:instance, :account_activation_required], true) - password = "testpassword" - - user = - insert(:user, - password_hash: Pbkdf2.hash_pwd_salt(password), - confirmation_pending: true - ) - - app = insert(:oauth_app, scopes: ["read", "write"]) - - resp = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "password", - "username" => user.nickname, - "password" => password, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(403) - - assert resp == %{ - "error" => "Your login is missing a confirmed e-mail address", - "identifier" => "missing_confirmed_email" - } - end - - test "rejects an invalid authorization code" do - app = insert(:oauth_app) - - conn = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "authorization_code", - "code" => "Imobviouslyinvalid", - "redirect_uri" => OAuthController.default_redirect_uri(app), - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - - assert resp = json_response(conn, 400) - assert %{"error" => _} = json_response(conn, 400) - refute Map.has_key?(resp, "access_token") - end - end - - describe "POST /oauth/token - refresh token" do - setup do: clear_config([:oauth2, :issue_new_refresh_token]) - - test "issues a new access token with keep fresh token" do - Pleroma.Config.put([:oauth2, :issue_new_refresh_token], true) - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) - {:ok, token} = Token.exchange_token(app, auth) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "refresh_token", - "refresh_token" => token.refresh_token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(200) - - ap_id = user.ap_id - - assert match?( - %{ - "scope" => "write", - "token_type" => "Bearer", - "expires_in" => 600, - "access_token" => _, - "refresh_token" => _, - "me" => ^ap_id - }, - response - ) - - refute Repo.get_by(Token, token: token.token) - new_token = Repo.get_by(Token, token: response["access_token"]) - assert new_token.refresh_token == token.refresh_token - assert new_token.scopes == auth.scopes - assert new_token.user_id == user.id - assert new_token.app_id == app.id - end - - test "issues a new access token with new fresh token" do - Pleroma.Config.put([:oauth2, :issue_new_refresh_token], false) - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) - {:ok, token} = Token.exchange_token(app, auth) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "refresh_token", - "refresh_token" => token.refresh_token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(200) - - ap_id = user.ap_id - - assert match?( - %{ - "scope" => "write", - "token_type" => "Bearer", - "expires_in" => 600, - "access_token" => _, - "refresh_token" => _, - "me" => ^ap_id - }, - response - ) - - refute Repo.get_by(Token, token: token.token) - new_token = Repo.get_by(Token, token: response["access_token"]) - refute new_token.refresh_token == token.refresh_token - assert new_token.scopes == auth.scopes - assert new_token.user_id == user.id - assert new_token.app_id == app.id - end - - test "returns 400 if we try use access token" do - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) - {:ok, token} = Token.exchange_token(app, auth) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "refresh_token", - "refresh_token" => token.token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(400) - - assert %{"error" => "Invalid credentials"} == response - end - - test "returns 400 if refresh_token invalid" do - app = insert(:oauth_app, scopes: ["read", "write"]) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "refresh_token", - "refresh_token" => "token.refresh_token", - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(400) - - assert %{"error" => "Invalid credentials"} == response - end - - test "issues a new token if token expired" do - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write"]) - - {:ok, auth} = Authorization.create_authorization(app, user, ["write"]) - {:ok, token} = Token.exchange_token(app, auth) - - change = - Ecto.Changeset.change( - token, - %{valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -86_400 * 30)} - ) - - {:ok, access_token} = Repo.update(change) - - response = - build_conn() - |> post("/oauth/token", %{ - "grant_type" => "refresh_token", - "refresh_token" => access_token.refresh_token, - "client_id" => app.client_id, - "client_secret" => app.client_secret - }) - |> json_response(200) - - ap_id = user.ap_id - - assert match?( - %{ - "scope" => "write", - "token_type" => "Bearer", - "expires_in" => 600, - "access_token" => _, - "refresh_token" => _, - "me" => ^ap_id - }, - response - ) - - refute Repo.get_by(Token, token: token.token) - token = Repo.get_by(Token, token: response["access_token"]) - assert token - assert token.scopes == auth.scopes - assert token.user_id == user.id - assert token.app_id == app.id - end - end - - describe "POST /oauth/token - bad request" do - test "returns 500" do - response = - build_conn() - |> post("/oauth/token", %{}) - |> json_response(500) - - assert %{"error" => "Bad request"} == response - end - end - - describe "POST /oauth/revoke - bad request" do - test "returns 500" do - response = - build_conn() - |> post("/oauth/revoke", %{}) - |> json_response(500) - - assert %{"error" => "Bad request"} == response - end - end -end diff --git a/test/web/oauth/token/utils_test.exs b/test/web/oauth/token/utils_test.exs deleted file mode 100644 index a610d92f8..000000000 --- a/test/web/oauth/token/utils_test.exs +++ /dev/null @@ -1,53 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.Token.UtilsTest do - use Pleroma.DataCase - alias Pleroma.Web.OAuth.Token.Utils - import Pleroma.Factory - - describe "fetch_app/1" do - test "returns error when credentials is invalid" do - assert {:error, :not_found} = - Utils.fetch_app(%Plug.Conn{params: %{"client_id" => 1, "client_secret" => "x"}}) - end - - test "returns App by params credentails" do - app = insert(:oauth_app) - - assert {:ok, load_app} = - Utils.fetch_app(%Plug.Conn{ - params: %{"client_id" => app.client_id, "client_secret" => app.client_secret} - }) - - assert load_app == app - end - - test "returns App by header credentails" do - app = insert(:oauth_app) - header = "Basic " <> Base.encode64("#{app.client_id}:#{app.client_secret}") - - conn = - %Plug.Conn{} - |> Plug.Conn.put_req_header("authorization", header) - - assert {:ok, load_app} = Utils.fetch_app(conn) - assert load_app == app - end - end - - describe "format_created_at/1" do - test "returns formatted created at" do - token = insert(:oauth_token) - date = Utils.format_created_at(token) - - token_date = - token.inserted_at - |> DateTime.from_naive!("Etc/UTC") - |> DateTime.to_unix() - - assert token_date == date - end - end -end diff --git a/test/web/oauth/token_test.exs b/test/web/oauth/token_test.exs deleted file mode 100644 index 40d71eb59..000000000 --- a/test/web/oauth/token_test.exs +++ /dev/null @@ -1,85 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.TokenTest do - use Pleroma.DataCase - alias Pleroma.Repo - alias Pleroma.Web.OAuth.App - alias Pleroma.Web.OAuth.Authorization - alias Pleroma.Web.OAuth.Token - - import Pleroma.Factory - - test "exchanges a auth token for an access token, preserving `scopes`" do - {:ok, app} = - Repo.insert( - App.register_changeset(%App{}, %{ - client_name: "client", - scopes: ["read", "write"], - redirect_uris: "url" - }) - ) - - user = insert(:user) - - {:ok, auth} = Authorization.create_authorization(app, user, ["read"]) - assert auth.scopes == ["read"] - - {:ok, token} = Token.exchange_token(app, auth) - - assert token.app_id == app.id - assert token.user_id == user.id - assert token.scopes == auth.scopes - assert String.length(token.token) > 10 - assert String.length(token.refresh_token) > 10 - - auth = Repo.get(Authorization, auth.id) - {:error, "already used"} = Token.exchange_token(app, auth) - end - - test "deletes all tokens of a user" do - {:ok, app1} = - Repo.insert( - App.register_changeset(%App{}, %{ - client_name: "client1", - scopes: ["scope"], - redirect_uris: "url" - }) - ) - - {:ok, app2} = - Repo.insert( - App.register_changeset(%App{}, %{ - client_name: "client2", - scopes: ["scope"], - redirect_uris: "url" - }) - ) - - user = insert(:user) - - {:ok, auth1} = Authorization.create_authorization(app1, user) - {:ok, auth2} = Authorization.create_authorization(app2, user) - - {:ok, _token1} = Token.exchange_token(app1, auth1) - {:ok, _token2} = Token.exchange_token(app2, auth2) - - {tokens, _} = Token.delete_user_tokens(user) - - assert tokens == 2 - end - - test "deletes expired tokens" do - insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) - insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3)) - t3 = insert(:oauth_token) - t4 = insert(:oauth_token, valid_until: Timex.shift(Timex.now(), minutes: 10)) - {tokens, _} = Token.delete_expired_tokens() - assert tokens == 2 - available_tokens = Pleroma.Repo.all(Token) - - token_ids = available_tokens |> Enum.map(& &1.id) - assert token_ids == [t3.id, t4.id] - end -end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs deleted file mode 100644 index ee498f4b5..000000000 --- a/test/web/ostatus/ostatus_controller_test.exs +++ /dev/null @@ -1,338 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OStatus.OStatusControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Config - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Endpoint - - require Pleroma.Constants - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance, :federating], true) - - describe "Mastodon compatibility routes" do - setup %{conn: conn} do - conn = put_req_header(conn, "accept", "text/html") - - {:ok, object} = - %{ - "type" => "Note", - "content" => "hey", - "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", - "actor" => Endpoint.url() <> "/users/raymoo", - "to" => [Pleroma.Constants.as_public()] - } - |> Object.create() - - {:ok, activity, _} = - %{ - "id" => object.data["id"] <> "/activity", - "type" => "Create", - "object" => object.data["id"], - "actor" => object.data["actor"], - "to" => object.data["to"] - } - |> ActivityPub.persist(local: true) - - %{conn: conn, activity: activity} - end - - test "redirects to /notice/:id for html format", %{conn: conn, activity: activity} do - conn = get(conn, "/users/raymoo/statuses/999999999") - assert redirected_to(conn) == "/notice/#{activity.id}" - end - - test "redirects to /notice/:id for html format for activity", %{ - conn: conn, - activity: activity - } do - conn = get(conn, "/users/raymoo/statuses/999999999/activity") - assert redirected_to(conn) == "/notice/#{activity.id}" - end - end - - # Note: see ActivityPubControllerTest for JSON format tests - describe "GET /objects/:uuid (text/html)" do - setup %{conn: conn} do - conn = put_req_header(conn, "accept", "text/html") - %{conn: conn} - end - - test "redirects to /notice/id for html format", %{conn: conn} do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - url = "/objects/#{uuid}" - - conn = get(conn, url) - assert redirected_to(conn) == "/notice/#{note_activity.id}" - end - - test "404s on private objects", %{conn: conn} do - note_activity = insert(:direct_note_activity) - object = Object.normalize(note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - - conn - |> get("/objects/#{uuid}") - |> response(404) - end - - test "404s on non-existing objects", %{conn: conn} do - conn - |> get("/objects/123") - |> response(404) - end - end - - # Note: see ActivityPubControllerTest for JSON format tests - describe "GET /activities/:uuid (text/html)" do - setup %{conn: conn} do - conn = put_req_header(conn, "accept", "text/html") - %{conn: conn} - end - - test "redirects to /notice/id for html format", %{conn: conn} do - note_activity = insert(:note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - - conn = get(conn, "/activities/#{uuid}") - assert redirected_to(conn) == "/notice/#{note_activity.id}" - end - - test "404s on private activities", %{conn: conn} do - note_activity = insert(:direct_note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - - conn - |> get("/activities/#{uuid}") - |> response(404) - end - - test "404s on nonexistent activities", %{conn: conn} do - conn - |> get("/activities/123") - |> response(404) - end - end - - describe "GET notice/2" do - test "redirects to a proper object URL when json requested and the object is local", %{ - conn: conn - } do - note_activity = insert(:note_activity) - expected_redirect_url = Object.normalize(note_activity).data["id"] - - redirect_url = - conn - |> put_req_header("accept", "application/activity+json") - |> get("/notice/#{note_activity.id}") - |> redirected_to() - - assert redirect_url == expected_redirect_url - end - - test "returns a 404 on remote notice when json requested", %{conn: conn} do - note_activity = insert(:note_activity, local: false) - - conn - |> put_req_header("accept", "application/activity+json") - |> get("/notice/#{note_activity.id}") - |> response(404) - end - - test "500s when actor not found", %{conn: conn} do - note_activity = insert(:note_activity) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - User.invalidate_cache(user) - Pleroma.Repo.delete(user) - - conn = - conn - |> get("/notice/#{note_activity.id}") - - assert response(conn, 500) == ~S({"error":"Something went wrong"}) - end - - test "render html for redirect for html format", %{conn: conn} do - note_activity = insert(:note_activity) - - resp = - conn - |> put_req_header("accept", "text/html") - |> get("/notice/#{note_activity.id}") - |> response(200) - - assert resp =~ - "<meta content=\"#{Pleroma.Web.base_url()}/notice/#{note_activity.id}\" property=\"og:url\">" - - user = insert(:user) - - {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id) - - assert like_activity.data["type"] == "Like" - - resp = - conn - |> put_req_header("accept", "text/html") - |> get("/notice/#{like_activity.id}") - |> response(200) - - assert resp =~ "<!--server-generated-meta-->" - end - - test "404s a private notice", %{conn: conn} do - note_activity = insert(:direct_note_activity) - url = "/notice/#{note_activity.id}" - - conn = - conn - |> get(url) - - assert response(conn, 404) - end - - test "404s a non-existing notice", %{conn: conn} do - url = "/notice/123" - - conn = - conn - |> get(url) - - assert response(conn, 404) - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn - } do - user = insert(:user) - note_activity = insert(:note_activity) - - conn = put_req_header(conn, "accept", "text/html") - - ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}", user) - end - end - - describe "GET /notice/:id/embed_player" do - setup do - note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) - - object_data = - Map.put(object.data, "attachment", [ - %{ - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ]) - - object - |> Ecto.Changeset.change(data: object_data) - |> Pleroma.Repo.update() - - %{note_activity: note_activity} - end - - test "renders embed player", %{conn: conn, note_activity: note_activity} do - conn = get(conn, "/notice/#{note_activity.id}/embed_player") - - assert Plug.Conn.get_resp_header(conn, "x-frame-options") == ["ALLOW"] - - assert Plug.Conn.get_resp_header( - conn, - "content-security-policy" - ) == [ - "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;" - ] - - assert response(conn, 200) =~ - "<video controls loop><source src=\"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4\" type=\"video/mp4\">Your browser does not support video/mp4 playback.</video>" - end - - test "404s when activity isn't create", %{conn: conn} do - note_activity = insert(:note_activity, data_attrs: %{"type" => "Like"}) - - assert conn - |> get("/notice/#{note_activity.id}/embed_player") - |> response(404) - end - - test "404s when activity is direct message", %{conn: conn} do - note_activity = insert(:note_activity, data_attrs: %{"directMessage" => true}) - - assert conn - |> get("/notice/#{note_activity.id}/embed_player") - |> response(404) - end - - test "404s when attachment is empty", %{conn: conn} do - note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) - object_data = Map.put(object.data, "attachment", []) - - object - |> Ecto.Changeset.change(data: object_data) - |> Pleroma.Repo.update() - - assert conn - |> get("/notice/#{note_activity.id}/embed_player") - |> response(404) - end - - test "404s when attachment isn't audio or video", %{conn: conn} do - note_activity = insert(:note_activity) - object = Pleroma.Object.normalize(note_activity) - - object_data = - Map.put(object.data, "attachment", [ - %{ - "url" => [ - %{ - "href" => "https://peertube.moe/static/webseed/480.jpg", - "mediaType" => "image/jpg", - "type" => "Link" - } - ] - } - ]) - - object - |> Ecto.Changeset.change(data: object_data) - |> Pleroma.Repo.update() - - conn - |> get("/notice/#{note_activity.id}/embed_player") - |> response(404) - end - - test "it requires authentication if instance is NOT federating", %{ - conn: conn, - note_activity: note_activity - } do - user = insert(:user) - conn = put_req_header(conn, "accept", "text/html") - - ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}/embed_player", user) - end - end -end diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs deleted file mode 100644 index 07909d48b..000000000 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ /dev/null @@ -1,284 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - import Swoosh.TestAssertions - - describe "POST /api/v1/pleroma/accounts/confirmation_resend" do - setup do - {:ok, user} = - insert(:user) - |> User.confirmation_changeset(need_confirmation: true) - |> User.update_and_set_cache() - - assert user.confirmation_pending - - [user: user] - end - - setup do: clear_config([:instance, :account_activation_required], true) - - test "resend account confirmation email", %{conn: conn, user: user} do - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") - |> json_response_and_validate_schema(:no_content) - - ObanHelpers.perform_all() - - email = Pleroma.Emails.UserEmail.account_confirmation_email(user) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - - test "resend account confirmation email (with nickname)", %{conn: conn, user: user} do - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/accounts/confirmation_resend?nickname=#{user.nickname}") - |> json_response_and_validate_schema(:no_content) - - ObanHelpers.perform_all() - - email = Pleroma.Emails.UserEmail.account_confirmation_email(user) - notify_email = Config.get([:instance, :notify_email]) - instance_name = Config.get([:instance, :name]) - - assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - end - - describe "getting favorites timeline of specified user" do - setup do - [current_user, user] = insert_pair(:user, hide_favorites: false) - %{user: current_user, conn: conn} = oauth_access(["read:favourites"], user: current_user) - [current_user: current_user, user: user, conn: conn] - end - - test "returns list of statuses favorited by specified user", %{ - conn: conn, - user: user - } do - [activity | _] = insert_pair(:note_activity) - CommonAPI.favorite(user, activity.id) - - response = - conn - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(:ok) - - [like] = response - - assert length(response) == 1 - assert like["id"] == activity.id - end - - test "returns favorites for specified user_id when requester is not logged in", %{ - user: user - } do - activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) - - response = - build_conn() - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(200) - - assert length(response) == 1 - end - - test "returns favorited DM only when user is logged in and he is one of recipients", %{ - current_user: current_user, - user: user - } do - {:ok, direct} = - CommonAPI.post(current_user, %{ - status: "Hi @#{user.nickname}!", - visibility: "direct" - }) - - CommonAPI.favorite(user, direct.id) - - for u <- [user, current_user] do - response = - build_conn() - |> assign(:user, u) - |> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"])) - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(:ok) - - assert length(response) == 1 - end - - response = - build_conn() - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(200) - - assert length(response) == 0 - end - - test "does not return others' favorited DM when user is not one of recipients", %{ - conn: conn, - user: user - } do - user_two = insert(:user) - - {:ok, direct} = - CommonAPI.post(user_two, %{ - status: "Hi @#{user.nickname}!", - visibility: "direct" - }) - - CommonAPI.favorite(user, direct.id) - - response = - conn - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "paginates favorites using since_id and max_id", %{ - conn: conn, - user: user - } do - activities = insert_list(10, :note_activity) - - Enum.each(activities, fn activity -> - CommonAPI.favorite(user, activity.id) - end) - - third_activity = Enum.at(activities, 2) - seventh_activity = Enum.at(activities, 6) - - response = - conn - |> get( - "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{ - seventh_activity.id - }" - ) - |> json_response_and_validate_schema(:ok) - - assert length(response) == 3 - refute third_activity in response - refute seventh_activity in response - end - - test "limits favorites using limit parameter", %{ - conn: conn, - user: user - } do - 7 - |> insert_list(:note_activity) - |> Enum.each(fn activity -> - CommonAPI.favorite(user, activity.id) - end) - - response = - conn - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites?limit=3") - |> json_response_and_validate_schema(:ok) - - assert length(response) == 3 - end - - test "returns empty response when user does not have any favorited statuses", %{ - conn: conn, - user: user - } do - response = - conn - |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") - |> json_response_and_validate_schema(:ok) - - assert Enum.empty?(response) - end - - test "returns 404 error when specified user is not exist", %{conn: conn} do - conn = get(conn, "/api/v1/pleroma/accounts/test/favourites") - - assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} - end - - test "returns 403 error when user has hidden own favorites", %{conn: conn} do - user = insert(:user, hide_favorites: true) - activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) - - conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") - - assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"} - end - - test "hides favorites for new users by default", %{conn: conn} do - user = insert(:user) - activity = insert(:note_activity) - CommonAPI.favorite(user, activity.id) - - assert user.hide_favorites - conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") - - assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"} - end - end - - describe "subscribing / unsubscribing" do - test "subscribing / unsubscribing to a user" do - %{user: user, conn: conn} = oauth_access(["follow"]) - subscription_target = insert(:user) - - ret_conn = - conn - |> assign(:user, user) - |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") - - assert %{"id" => _id, "subscribing" => true} = - json_response_and_validate_schema(ret_conn, 200) - - conn = post(conn, "/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") - - assert %{"id" => _id, "subscribing" => false} = json_response_and_validate_schema(conn, 200) - end - end - - describe "subscribing" do - test "returns 404 when subscription_target not found" do - %{conn: conn} = oauth_access(["write:follows"]) - - conn = post(conn, "/api/v1/pleroma/accounts/target_id/subscribe") - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404) - end - end - - describe "unsubscribing" do - test "returns 404 when subscription_target not found" do - %{conn: conn} = oauth_access(["follow"]) - - conn = post(conn, "/api/v1/pleroma/accounts/target_id/unsubscribe") - - assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404) - end - end -end diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/web/pleroma_api/controllers/chat_controller_test.exs deleted file mode 100644 index d71e80d03..000000000 --- a/test/web/pleroma_api/controllers/chat_controller_test.exs +++ /dev/null @@ -1,358 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "POST /api/v1/pleroma/chats/:id/messages/:message_id/read" do - setup do: oauth_access(["write:chats"]) - - test "it marks one message as read", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") - {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - object = Object.normalize(create, false) - cm_ref = MessageReference.for_chat_and_object(chat, object) - - assert cm_ref.unread == true - - result = - conn - |> post("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}/read") - |> json_response_and_validate_schema(200) - - assert result["unread"] == false - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - assert cm_ref.unread == false - end - end - - describe "POST /api/v1/pleroma/chats/:id/read" do - setup do: oauth_access(["write:chats"]) - - test "given a `last_read_id`, it marks everything until then as read", %{ - conn: conn, - user: user - } do - other_user = insert(:user) - - {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") - {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - object = Object.normalize(create, false) - cm_ref = MessageReference.for_chat_and_object(chat, object) - - assert cm_ref.unread == true - - result = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/chats/#{chat.id}/read", %{"last_read_id" => cm_ref.id}) - |> json_response_and_validate_schema(200) - - assert result["unread"] == 1 - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - assert cm_ref.unread == false - end - end - - describe "POST /api/v1/pleroma/chats/:id/messages" do - setup do: oauth_access(["write:chats"]) - - test "it posts a message to the chat", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - - result = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "Hallo!!"}) - |> json_response_and_validate_schema(200) - - assert result["content"] == "Hallo!!" - assert result["chat_id"] == chat.id |> to_string() - end - - test "it fails if there is no content", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - - result = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/chats/#{chat.id}/messages") - |> json_response_and_validate_schema(400) - - assert result - end - - test "it works with an attachment", %{conn: conn, user: user} do - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - other_user = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - - result = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{ - "media_id" => to_string(upload.id) - }) - |> json_response_and_validate_schema(200) - - assert result["attachment"] - end - end - - describe "DELETE /api/v1/pleroma/chats/:id/messages/:message_id" do - setup do: oauth_access(["write:chats"]) - - test "it deletes a message from the chat", %{conn: conn, user: user} do - recipient = insert(:user) - - {:ok, message} = - CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend") - - {:ok, other_message} = CommonAPI.post_chat_message(recipient, user, "nico nico ni") - - object = Object.normalize(message, false) - - chat = Chat.get(user.id, recipient.ap_id) - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - # Deleting your own message removes the message and the reference - result = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] == cm_ref.id - refute MessageReference.get_by_id(cm_ref.id) - assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) - - # Deleting other people's messages just removes the reference - object = Object.normalize(other_message, false) - cm_ref = MessageReference.for_chat_and_object(chat, object) - - result = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] == cm_ref.id - refute MessageReference.get_by_id(cm_ref.id) - assert Object.get_by_id(object.id) - end - end - - describe "GET /api/v1/pleroma/chats/:id/messages" do - setup do: oauth_access(["read:chats"]) - - test "it paginates", %{conn: conn, user: user} do - recipient = insert(:user) - - Enum.each(1..30, fn _ -> - {:ok, _} = CommonAPI.post_chat_message(user, recipient, "hey") - end) - - chat = Chat.get(user.id, recipient.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}/messages") - |> json_response_and_validate_schema(200) - - assert length(result) == 20 - - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}") - |> json_response_and_validate_schema(200) - - assert length(result) == 10 - end - - test "it returns the messages for a given chat", %{conn: conn, user: user} do - other_user = insert(:user) - third_user = insert(:user) - - {:ok, _} = CommonAPI.post_chat_message(user, other_user, "hey") - {:ok, _} = CommonAPI.post_chat_message(user, third_user, "hey") - {:ok, _} = CommonAPI.post_chat_message(user, other_user, "how are you?") - {:ok, _} = CommonAPI.post_chat_message(other_user, user, "fine, how about you?") - - chat = Chat.get(user.id, other_user.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}/messages") - |> json_response_and_validate_schema(200) - - result - |> Enum.each(fn message -> - assert message["chat_id"] == chat.id |> to_string() - end) - - assert length(result) == 3 - - # Trying to get the chat of a different user - result = - conn - |> assign(:user, other_user) - |> get("/api/v1/pleroma/chats/#{chat.id}/messages") - - assert result |> json_response(404) - end - end - - describe "POST /api/v1/pleroma/chats/by-account-id/:id" do - setup do: oauth_access(["write:chats"]) - - test "it creates or returns a chat", %{conn: conn} do - other_user = insert(:user) - - result = - conn - |> post("/api/v1/pleroma/chats/by-account-id/#{other_user.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] - end - end - - describe "GET /api/v1/pleroma/chats/:id" do - setup do: oauth_access(["read:chats"]) - - test "it returns a chat", %{conn: conn, user: user} do - other_user = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats/#{chat.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] == to_string(chat.id) - end - end - - describe "GET /api/v1/pleroma/chats" do - setup do: oauth_access(["read:chats"]) - - test "it does not return chats with users you blocked", %{conn: conn, user: user} do - recipient = insert(:user) - - {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 1 - - User.block(user, recipient) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 0 - end - - test "it returns all chats", %{conn: conn, user: user} do - Enum.each(1..30, fn _ -> - recipient = insert(:user) - {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) - end) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - assert length(result) == 30 - end - - test "it return a list of chats the current user is participating in, in descending order of updates", - %{conn: conn, user: user} do - har = insert(:user) - jafnhar = insert(:user) - tridi = insert(:user) - - {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id) - :timer.sleep(1000) - {:ok, _chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id) - :timer.sleep(1000) - {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id) - :timer.sleep(1000) - - # bump the second one - {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - ids = Enum.map(result, & &1["id"]) - - assert ids == [ - chat_2.id |> to_string(), - chat_3.id |> to_string(), - chat_1.id |> to_string() - ] - end - - test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{ - conn: conn, - user: user - } do - clear_config([:restrict_unauthenticated, :profiles, :local], true) - clear_config([:restrict_unauthenticated, :profiles, :remote], true) - - user2 = insert(:user) - user3 = insert(:user, local: false) - - {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id) - {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id) - - result = - conn - |> get("/api/v1/pleroma/chats") - |> json_response_and_validate_schema(200) - - account_ids = Enum.map(result, &get_in(&1, ["account", "id"])) - assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id]) - end - end -end diff --git a/test/web/pleroma_api/controllers/conversation_controller_test.exs b/test/web/pleroma_api/controllers/conversation_controller_test.exs deleted file mode 100644 index e6d0b3e37..000000000 --- a/test/web/pleroma_api/controllers/conversation_controller_test.exs +++ /dev/null @@ -1,136 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Conversation.Participation - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "/api/v1/pleroma/conversations/:id" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) - - {:ok, _activity} = - CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"}) - - [participation] = Participation.for_user(other_user) - - result = - conn - |> get("/api/v1/pleroma/conversations/#{participation.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] == participation.id |> to_string() - end - - test "/api/v1/pleroma/conversations/:id/statuses" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) - third_user = insert(:user) - - {:ok, _activity} = - CommonAPI.post(user, %{status: "Hi @#{third_user.nickname}!", visibility: "direct"}) - - {:ok, activity} = - CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"}) - - [participation] = Participation.for_user(other_user) - - {:ok, activity_two} = - CommonAPI.post(other_user, %{ - status: "Hi!", - in_reply_to_status_id: activity.id, - in_reply_to_conversation_id: participation.id - }) - - result = - conn - |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses") - |> json_response_and_validate_schema(200) - - assert length(result) == 2 - - id_one = activity.id - id_two = activity_two.id - assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result - - {:ok, %{id: id_three}} = - CommonAPI.post(other_user, %{ - status: "Bye!", - in_reply_to_status_id: activity.id, - in_reply_to_conversation_id: participation.id - }) - - assert [%{"id" => ^id_two}, %{"id" => ^id_three}] = - conn - |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2") - |> json_response_and_validate_schema(:ok) - - assert [%{"id" => ^id_three}] = - conn - |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}") - |> json_response_and_validate_schema(:ok) - end - - test "PATCH /api/v1/pleroma/conversations/:id" do - %{user: user, conn: conn} = oauth_access(["write:conversations"]) - other_user = insert(:user) - - {:ok, _activity} = CommonAPI.post(user, %{status: "Hi", visibility: "direct"}) - - [participation] = Participation.for_user(user) - - participation = Repo.preload(participation, :recipients) - - user = User.get_cached_by_id(user.id) - assert [user] == participation.recipients - assert other_user not in participation.recipients - - query = "recipients[]=#{user.id}&recipients[]=#{other_user.id}" - - result = - conn - |> patch("/api/v1/pleroma/conversations/#{participation.id}?#{query}") - |> json_response_and_validate_schema(200) - - assert result["id"] == participation.id |> to_string - - [participation] = Participation.for_user(user) - participation = Repo.preload(participation, :recipients) - - assert user in participation.recipients - assert other_user in participation.recipients - end - - test "POST /api/v1/pleroma/conversations/read" do - user = insert(:user) - %{user: other_user, conn: conn} = oauth_access(["write:conversations"]) - - {:ok, _activity} = - CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"}) - - {:ok, _activity} = - CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"}) - - [participation2, participation1] = Participation.for_user(other_user) - assert Participation.get(participation2.id).read == false - assert Participation.get(participation1.id).read == false - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2 - - [%{"unread" => false}, %{"unread" => false}] = - conn - |> post("/api/v1/pleroma/conversations/read", %{}) - |> json_response_and_validate_schema(200) - - [participation2, participation1] = Participation.for_user(other_user) - assert Participation.get(participation2.id).read == true - assert Participation.get(participation1.id).read == true - assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 - end -end diff --git a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs deleted file mode 100644 index e113bb15f..000000000 --- a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ /dev/null @@ -1,861 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do - use Pleroma.Web.ConnCase - - import Tesla.Mock - import Pleroma.Factory - - @emoji_path Path.join( - Pleroma.Config.get!([:instance, :static_dir]), - "emoji" - ) - setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) - - setup do: clear_config([:instance, :public], true) - - setup do - admin = insert(:user, is_admin: true) - token = insert(:oauth_admin_token, user: admin) - - admin_conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, token) - - Pleroma.Emoji.reload() - {:ok, %{admin_conn: admin_conn}} - end - - test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do - Config.put([:instance, :public], false) - conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - end - - test "GET /api/pleroma/emoji/packs", %{conn: conn} do - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - - assert resp["count"] == 3 - - assert resp["packs"] - |> Map.keys() - |> length() == 3 - - shared = resp["packs"]["test_pack"] - assert shared["files"] == %{"blank" => "blank.png", "blank2" => "blank2.png"} - assert Map.has_key?(shared["pack"], "download-sha256") - assert shared["pack"]["can-download"] - assert shared["pack"]["share-files"] - - non_shared = resp["packs"]["test_pack_nonshared"] - assert non_shared["pack"]["share-files"] == false - assert non_shared["pack"]["can-download"] == false - - resp = - conn - |> get("/api/pleroma/emoji/packs?page_size=1") - |> json_response_and_validate_schema(200) - - assert resp["count"] == 3 - - packs = Map.keys(resp["packs"]) - - assert length(packs) == 1 - - [pack1] = packs - - resp = - conn - |> get("/api/pleroma/emoji/packs?page_size=1&page=2") - |> json_response_and_validate_schema(200) - - assert resp["count"] == 3 - packs = Map.keys(resp["packs"]) - assert length(packs) == 1 - [pack2] = packs - - resp = - conn - |> get("/api/pleroma/emoji/packs?page_size=1&page=3") - |> json_response_and_validate_schema(200) - - assert resp["count"] == 3 - packs = Map.keys(resp["packs"]) - assert length(packs) == 1 - [pack3] = packs - assert [pack1, pack2, pack3] |> Enum.uniq() |> length() == 3 - end - - describe "GET /api/pleroma/emoji/packs/remote" do - test "shareable instance", %{admin_conn: admin_conn, conn: conn} do - resp = - conn - |> get("/api/pleroma/emoji/packs") - |> json_response_and_validate_schema(200) - - mock(fn - %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - - %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> - json(resp) - end) - - assert admin_conn - |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") - |> json_response_and_validate_schema(200) == resp - end - - test "non shareable instance", %{admin_conn: admin_conn} do - mock(fn - %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: []}}) - end) - - assert admin_conn - |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") - |> json_response_and_validate_schema(500) == %{ - "error" => "The requested instance does not support sharing emoji packs" - } - end - end - - describe "GET /api/pleroma/emoji/packs/:name/archive" do - test "download shared pack", %{conn: conn} do - resp = - conn - |> get("/api/pleroma/emoji/packs/test_pack/archive") - |> response(200) - - {:ok, arch} = :zip.unzip(resp, [:memory]) - - assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) - assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) - end - - test "non existing pack", %{conn: conn} do - assert conn - |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") - |> json_response_and_validate_schema(:not_found) == %{ - "error" => "Pack test_pack_for_import does not exist" - } - end - - test "non downloadable pack", %{conn: conn} do - assert conn - |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") - |> json_response_and_validate_schema(:forbidden) == %{ - "error" => - "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" - } - end - end - - describe "POST /api/pleroma/emoji/packs/download" do - test "shared pack from remote and non shared from fallback-src", %{ - admin_conn: admin_conn, - conn: conn - } do - mock(fn - %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack" - } -> - conn - |> get("/api/pleroma/emoji/packs/test_pack") - |> json_response_and_validate_schema(200) - |> json() - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack/archive" - } -> - conn - |> get("/api/pleroma/emoji/packs/test_pack/archive") - |> response(200) - |> text() - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack_nonshared" - } -> - conn - |> get("/api/pleroma/emoji/packs/test_pack_nonshared") - |> json_response_and_validate_schema(200) - |> json() - - %{ - method: :get, - url: "https://nonshared-pack" - } -> - text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip")) - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ - url: "https://example.com", - name: "test_pack", - as: "test_pack2" - }) - |> json_response_and_validate_schema(200) == "ok" - - assert File.exists?("#{@emoji_path}/test_pack2/pack.json") - assert File.exists?("#{@emoji_path}/test_pack2/blank.png") - - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack2") - |> json_response_and_validate_schema(200) == "ok" - - refute File.exists?("#{@emoji_path}/test_pack2") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post( - "/api/pleroma/emoji/packs/download", - %{ - url: "https://example.com", - name: "test_pack_nonshared", - as: "test_pack_nonshared2" - } - ) - |> json_response_and_validate_schema(200) == "ok" - - assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") - assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") - - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") - |> json_response_and_validate_schema(200) == "ok" - - refute File.exists?("#{@emoji_path}/test_pack_nonshared2") - end - - test "nonshareable instance", %{admin_conn: admin_conn} do - mock(fn - %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: []}}) - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post( - "/api/pleroma/emoji/packs/download", - %{ - url: "https://old-instance", - name: "test_pack", - as: "test_pack2" - } - ) - |> json_response_and_validate_schema(500) == %{ - "error" => "The requested instance does not support sharing emoji packs" - } - end - - test "checksum fail", %{admin_conn: admin_conn} do - mock(fn - %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha" - } -> - {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha") - %Tesla.Env{status: 200, body: Jason.encode!(pack)} - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive" - } -> - %Tesla.Env{ - status: 200, - body: File.read!("test/instance_static/emoji/pack_bad_sha/pack_bad_sha.zip") - } - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ - url: "https://example.com", - name: "pack_bad_sha", - as: "pack_bad_sha2" - }) - |> json_response_and_validate_schema(:internal_server_error) == %{ - "error" => "SHA256 for the pack doesn't match the one sent by the server" - } - end - - test "other error", %{admin_conn: admin_conn} do - mock(fn - %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> - json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - - %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> - json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - - %{ - method: :get, - url: "https://example.com/api/pleroma/emoji/packs/test_pack" - } -> - {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack") - %Tesla.Env{status: 200, body: Jason.encode!(pack)} - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/download", %{ - url: "https://example.com", - name: "test_pack", - as: "test_pack2" - }) - |> json_response_and_validate_schema(:internal_server_error) == %{ - "error" => - "The pack was not set as shared and there is no fallback src to download from" - } - end - end - - describe "PATCH /api/pleroma/emoji/packs/:name" do - setup do - pack_file = "#{@emoji_path}/test_pack/pack.json" - original_content = File.read!(pack_file) - - on_exit(fn -> - File.write!(pack_file, original_content) - end) - - {:ok, - pack_file: pack_file, - new_data: %{ - "license" => "Test license changed", - "homepage" => "https://pleroma.social", - "description" => "Test description", - "share-files" => false - }} - end - - test "for a pack without a fallback source", ctx do - assert ctx[:admin_conn] - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) - |> json_response_and_validate_schema(200) == ctx[:new_data] - - assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] - end - - test "for a pack with a fallback source", ctx do - mock(fn - %{ - method: :get, - url: "https://nonshared-pack" - } -> - text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip")) - end) - - new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") - - new_data_with_sha = - Map.put( - new_data, - "fallback-src-sha256", - "1967BB4E42BCC34BCC12D57BE7811D3B7BE52F965BCE45C87BD377B9499CE11D" - ) - - assert ctx[:admin_conn] - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) - |> json_response_and_validate_schema(200) == new_data_with_sha - - assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha - end - - test "when the fallback source doesn't have all the files", ctx do - mock(fn - %{ - method: :get, - url: "https://nonshared-pack" - } -> - {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) - text(empty_arch) - end) - - new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") - - assert ctx[:admin_conn] - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "The fallback archive does not have all files specified in pack.json" - } - end - end - - describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do - setup do - pack_file = "#{@emoji_path}/test_pack/pack.json" - original_content = File.read!(pack_file) - - on_exit(fn -> - File.write!(pack_file, original_content) - end) - - :ok - end - - test "create shortcode exists", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:conflict) == %{ - "error" => "An emoji with the \"blank\" shortcode already exists" - } - end - - test "don't rewrite old emoji", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank3" => "dir/blank.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - new_shortcode: "blank2", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:conflict) == %{ - "error" => - "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" - } - end - - test "rewrite old emoji with force option", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank3" => "dir/blank.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - new_shortcode: "blank4", - new_filename: "dir_2/blank_3.png", - force: true - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png", - "blank4" => "dir_2/blank_3.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") - end - - test "with empty filename", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank2", - filename: "", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name, shortcode or filename cannot be empty" - } - end - - test "add file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/not_loaded/files", %{ - shortcode: "blank3", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "remove file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "remove file with empty shortcode", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name or shortcode cannot be empty" - } - end - - test "update file with not loaded pack", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ - shortcode: "blank4", - new_shortcode: "blank3", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack \"not_loaded\" is not found" - } - end - - test "new with shortcode as file with update", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank4", - filename: "dir/blank.png", - file: %Plug.Upload{ - filename: "blank.png", - path: "#{@emoji_path}/test_pack/blank.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank4" => "dir/blank.png", - "blank2" => "blank2.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank4", - new_shortcode: "blank3", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(200) == %{ - "blank3" => "dir_2/blank_3.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - refute File.exists?("#{@emoji_path}/test_pack/dir/") - assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") - - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") - |> json_response_and_validate_schema(200) == %{ - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - refute File.exists?("#{@emoji_path}/test_pack/dir_2/") - - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end) - end - - test "new with shortcode from url", %{admin_conn: admin_conn} do - mock(fn - %{ - method: :get, - url: "https://test-blank/blank_url.png" - } -> - text(File.read!("#{@emoji_path}/test_pack/blank.png")) - end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank_url", - file: "https://test-blank/blank_url.png" - }) - |> json_response_and_validate_schema(200) == %{ - "blank_url" => "blank_url.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } - - assert File.exists?("#{@emoji_path}/test_pack/blank_url.png") - - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end) - end - - test "new without shortcode", %{admin_conn: admin_conn} do - on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) - - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> post("/api/pleroma/emoji/packs/test_pack/files", %{ - file: %Plug.Upload{ - filename: "shortcode.png", - path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" - } - }) - |> json_response_and_validate_schema(200) == %{ - "shortcode" => "shortcode.png", - "blank" => "blank.png", - "blank2" => "blank2.png" - } - end - - test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "Emoji \"blank3\" does not exist" - } - end - - test "update non existing emoji", %{admin_conn: admin_conn} do - assert admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank3", - new_shortcode: "blank4", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "Emoji \"blank3\" does not exist" - } - end - - test "update with empty shortcode", %{admin_conn: admin_conn} do - assert %{ - "error" => "Missing field: new_shortcode." - } = - admin_conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ - shortcode: "blank", - new_filename: "dir_2/blank_3.png" - }) - |> json_response_and_validate_schema(:bad_request) - end - end - - describe "POST/DELETE /api/pleroma/emoji/packs/:name" do - test "creating and deleting a pack", %{admin_conn: admin_conn} do - assert admin_conn - |> post("/api/pleroma/emoji/packs/test_created") - |> json_response_and_validate_schema(200) == "ok" - - assert File.exists?("#{@emoji_path}/test_created/pack.json") - - assert Jason.decode!(File.read!("#{@emoji_path}/test_created/pack.json")) == %{ - "pack" => %{}, - "files" => %{}, - "files_count" => 0 - } - - assert admin_conn - |> delete("/api/pleroma/emoji/packs/test_created") - |> json_response_and_validate_schema(200) == "ok" - - refute File.exists?("#{@emoji_path}/test_created/pack.json") - end - - test "if pack exists", %{admin_conn: admin_conn} do - path = Path.join(@emoji_path, "test_created") - File.mkdir(path) - pack_file = Jason.encode!(%{files: %{}, pack: %{}}) - File.write!(Path.join(path, "pack.json"), pack_file) - - assert admin_conn - |> post("/api/pleroma/emoji/packs/test_created") - |> json_response_and_validate_schema(:conflict) == %{ - "error" => "A pack named \"test_created\" already exists" - } - - on_exit(fn -> File.rm_rf(path) end) - end - - test "with empty name", %{admin_conn: admin_conn} do - assert admin_conn - |> post("/api/pleroma/emoji/packs/ ") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name cannot be empty" - } - end - end - - test "deleting nonexisting pack", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/non_existing") - |> json_response_and_validate_schema(:not_found) == %{ - "error" => "Pack non_existing does not exist" - } - end - - test "deleting with empty name", %{admin_conn: admin_conn} do - assert admin_conn - |> delete("/api/pleroma/emoji/packs/ ") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name cannot be empty" - } - end - - test "filesystem import", %{admin_conn: admin_conn, conn: conn} do - on_exit(fn -> - File.rm!("#{@emoji_path}/test_pack_for_import/emoji.txt") - File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") - end) - - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - - refute Map.has_key?(resp["packs"], "test_pack_for_import") - - assert admin_conn - |> get("/api/pleroma/emoji/packs/import") - |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - assert resp["packs"]["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} - - File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") - refute File.exists?("#{@emoji_path}/test_pack_for_import/pack.json") - - emoji_txt_content = """ - blank, blank.png, Fun - blank2, blank.png - foo, /emoji/test_pack_for_import/blank.png - bar - """ - - File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content) - - assert admin_conn - |> get("/api/pleroma/emoji/packs/import") - |> json_response_and_validate_schema(200) == ["test_pack_for_import"] - - resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) - - assert resp["packs"]["test_pack_for_import"]["files"] == %{ - "blank" => "blank.png", - "blank2" => "blank.png", - "foo" => "blank.png" - } - end - - describe "GET /api/pleroma/emoji/packs/:name" do - test "shows pack.json", %{conn: conn} do - assert %{ - "files" => files, - "files_count" => 2, - "pack" => %{ - "can-download" => true, - "description" => "Test description", - "download-sha256" => _, - "homepage" => "https://pleroma.social", - "license" => "Test license", - "share-files" => true - } - } = - conn - |> get("/api/pleroma/emoji/packs/test_pack") - |> json_response_and_validate_schema(200) - - assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"} - - assert %{ - "files" => files, - "files_count" => 2 - } = - conn - |> get("/api/pleroma/emoji/packs/test_pack?page_size=1") - |> json_response_and_validate_schema(200) - - assert files |> Map.keys() |> length() == 1 - - assert %{ - "files" => files, - "files_count" => 2 - } = - conn - |> get("/api/pleroma/emoji/packs/test_pack?page_size=1&page=2") - |> json_response_and_validate_schema(200) - - assert files |> Map.keys() |> length() == 1 - end - - test "non existing pack", %{conn: conn} do - assert conn - |> get("/api/pleroma/emoji/packs/non_existing") - |> json_response_and_validate_schema(:not_found) == %{ - "error" => "Pack non_existing does not exist" - } - end - - test "error name", %{conn: conn} do - assert conn - |> get("/api/pleroma/emoji/packs/ ") - |> json_response_and_validate_schema(:bad_request) == %{ - "error" => "pack name cannot be empty" - } - end - end -end diff --git a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs deleted file mode 100644 index e1bb5ebfe..000000000 --- a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs +++ /dev/null @@ -1,132 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.Web.ConnCase - - alias Pleroma.Object - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - - result = - conn - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) - |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") - |> json_response_and_validate_schema(200) - - # We return the status, but this our implementation detail. - assert %{"id" => id} = result - assert to_string(activity.id) == id - - assert result["pleroma"]["emoji_reactions"] == [ - %{"name" => "☕", "count" => 1, "me" => true} - ] - - # Reacting with a non-emoji - assert conn - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) - |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/x") - |> json_response_and_validate_schema(400) - end - - test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - {:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - - ObanHelpers.perform_all() - - result = - conn - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) - |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") - - assert %{"id" => id} = json_response_and_validate_schema(result, 200) - assert to_string(activity.id) == id - - ObanHelpers.perform_all() - - object = Object.get_by_ap_id(activity.data["object"]) - - assert object.data["reaction_count"] == 0 - end - - test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - doomed_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - - result = - conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") - |> json_response_and_validate_schema(200) - - assert result == [] - - {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") - {:ok, _} = CommonAPI.react_with_emoji(activity.id, doomed_user, "🎅") - - User.perform(:delete, doomed_user) - - result = - conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") - |> json_response_and_validate_schema(200) - - [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result - - assert represented_user["id"] == other_user.id - - result = - conn - |> assign(:user, other_user) - |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:statuses"])) - |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") - |> json_response_and_validate_schema(200) - - assert [%{"name" => "🎅", "count" => 1, "accounts" => [_represented_user], "me" => true}] = - result - end - - test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) - - result = - conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") - |> json_response_and_validate_schema(200) - - assert result == [] - - {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") - {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - - assert [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = - conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") - |> json_response_and_validate_schema(200) - - assert represented_user["id"] == other_user.id - end -end diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/web/pleroma_api/controllers/mascot_controller_test.exs deleted file mode 100644 index e2ead6e15..000000000 --- a/test/web/pleroma_api/controllers/mascot_controller_test.exs +++ /dev/null @@ -1,73 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.User - - test "mascot upload" do - %{conn: conn} = oauth_access(["write:accounts"]) - - non_image_file = %Plug.Upload{ - content_type: "audio/mpeg", - path: Path.absname("test/fixtures/sound.mp3"), - filename: "sound.mp3" - } - - ret_conn = - conn - |> put_req_header("content-type", "multipart/form-data") - |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) - - assert json_response_and_validate_schema(ret_conn, 415) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - conn = - conn - |> put_req_header("content-type", "multipart/form-data") - |> put("/api/v1/pleroma/mascot", %{"file" => file}) - - assert %{"id" => _, "type" => image} = json_response_and_validate_schema(conn, 200) - end - - test "mascot retrieving" do - %{user: user, conn: conn} = oauth_access(["read:accounts", "write:accounts"]) - - # When user hasn't set a mascot, we should just get pleroma tan back - ret_conn = get(conn, "/api/v1/pleroma/mascot") - - assert %{"url" => url} = json_response_and_validate_schema(ret_conn, 200) - assert url =~ "pleroma-fox-tan-smol" - - # When a user sets their mascot, we should get that back - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - ret_conn = - conn - |> put_req_header("content-type", "multipart/form-data") - |> put("/api/v1/pleroma/mascot", %{"file" => file}) - - assert json_response_and_validate_schema(ret_conn, 200) - - user = User.get_cached_by_id(user.id) - - conn = - conn - |> assign(:user, user) - |> get("/api/v1/pleroma/mascot") - - assert %{"url" => url, "type" => "image"} = json_response_and_validate_schema(conn, 200) - assert url =~ "an_image" - end -end diff --git a/test/web/pleroma_api/controllers/notification_controller_test.exs b/test/web/pleroma_api/controllers/notification_controller_test.exs deleted file mode 100644 index bb4fe6c49..000000000 --- a/test/web/pleroma_api/controllers/notification_controller_test.exs +++ /dev/null @@ -1,68 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Notification - alias Pleroma.Repo - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - describe "POST /api/v1/pleroma/notifications/read" do - setup do: oauth_access(["write:notifications"]) - - test "it marks a single notification as read", %{user: user1, conn: conn} do - user2 = insert(:user) - {:ok, activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) - {:ok, activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) - {:ok, [notification1]} = Notification.create_notifications(activity1) - {:ok, [notification2]} = Notification.create_notifications(activity2) - - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/notifications/read", %{id: notification1.id}) - |> json_response_and_validate_schema(:ok) - - assert %{"pleroma" => %{"is_seen" => true}} = response - assert Repo.get(Notification, notification1.id).seen - refute Repo.get(Notification, notification2.id).seen - end - - test "it marks multiple notifications as read", %{user: user1, conn: conn} do - user2 = insert(:user) - {:ok, _activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) - {:ok, _activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) - {:ok, _activity3} = CommonAPI.post(user2, %{status: "HIE @#{user1.nickname}"}) - - [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3}) - - [response1, response2] = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/notifications/read", %{max_id: notification2.id}) - |> json_response_and_validate_schema(:ok) - - assert %{"pleroma" => %{"is_seen" => true}} = response1 - assert %{"pleroma" => %{"is_seen" => true}} = response2 - assert Repo.get(Notification, notification1.id).seen - assert Repo.get(Notification, notification2.id).seen - refute Repo.get(Notification, notification3.id).seen - end - - test "it returns error when notification not found", %{conn: conn} do - response = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/notifications/read", %{ - id: 22_222_222_222_222 - }) - |> json_response_and_validate_schema(:bad_request) - - assert response == %{"error" => "Cannot get notification"} - end - end -end diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs deleted file mode 100644 index f39c07ac6..000000000 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ /dev/null @@ -1,60 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Web.CommonAPI - - describe "POST /api/v1/pleroma/scrobble" do - test "works correctly" do - %{conn: conn} = oauth_access(["write"]) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> post("/api/v1/pleroma/scrobble", %{ - "title" => "lain radio episode 1", - "artist" => "lain", - "album" => "lain radio", - "length" => "180000" - }) - - assert %{"title" => "lain radio episode 1"} = json_response_and_validate_schema(conn, 200) - end - end - - describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do - test "works correctly" do - %{user: user, conn: conn} = oauth_access(["read"]) - - {:ok, _activity} = - CommonAPI.listen(user, %{ - title: "lain radio episode 1", - artist: "lain", - album: "lain radio" - }) - - {:ok, _activity} = - CommonAPI.listen(user, %{ - title: "lain radio episode 2", - artist: "lain", - album: "lain radio" - }) - - {:ok, _activity} = - CommonAPI.listen(user, %{ - title: "lain radio episode 3", - artist: "lain", - album: "lain radio" - }) - - conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/scrobbles") - - result = json_response_and_validate_schema(conn, 200) - - assert length(result) == 3 - end - end -end diff --git a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs deleted file mode 100644 index d23d08a00..000000000 --- a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs +++ /dev/null @@ -1,260 +0,0 @@ -defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - alias Pleroma.MFA.Settings - alias Pleroma.MFA.TOTP - - describe "GET /api/pleroma/accounts/mfa/settings" do - test "returns user mfa settings for new user", %{conn: conn} do - token = insert(:oauth_token, scopes: ["read", "follow"]) - token2 = insert(:oauth_token, scopes: ["write"]) - - assert conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/pleroma/accounts/mfa") - |> json_response(:ok) == %{ - "settings" => %{"enabled" => false, "totp" => false} - } - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> get("/api/pleroma/accounts/mfa") - |> json_response(403) == %{ - "error" => "Insufficient permissions: read:security." - } - end - - test "returns user mfa settings with enabled totp", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - enabled: true, - totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true} - } - ) - - token = insert(:oauth_token, scopes: ["read", "follow"], user: user) - - assert conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/pleroma/accounts/mfa") - |> json_response(:ok) == %{ - "settings" => %{"enabled" => true, "totp" => true} - } - end - end - - describe "GET /api/pleroma/accounts/mfa/backup_codes" do - test "returns backup codes", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - backup_codes: ["1", "2", "3"], - totp: %Settings.TOTP{secret: "secret"} - } - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - token2 = insert(:oauth_token, scopes: ["read"]) - - response = - conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/pleroma/accounts/mfa/backup_codes") - |> json_response(:ok) - - assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"] - user = refresh_record(user) - mfa_settings = user.multi_factor_authentication_settings - assert mfa_settings.totp.secret == "secret" - refute mfa_settings.backup_codes == ["1", "2", "3"] - refute mfa_settings.backup_codes == [] - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> get("/api/pleroma/accounts/mfa/backup_codes") - |> json_response(403) == %{ - "error" => "Insufficient permissions: write:security." - } - end - end - - describe "GET /api/pleroma/accounts/mfa/setup/totp" do - test "return errors when method is invalid", %{conn: conn} do - user = insert(:user) - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - - response = - conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/pleroma/accounts/mfa/setup/torf") - |> json_response(400) - - assert response == %{"error" => "undefined method"} - end - - test "returns key and provisioning_uri", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]} - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - token2 = insert(:oauth_token, scopes: ["read"]) - - response = - conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> get("/api/pleroma/accounts/mfa/setup/totp") - |> json_response(:ok) - - user = refresh_record(user) - mfa_settings = user.multi_factor_authentication_settings - secret = mfa_settings.totp.secret - refute mfa_settings.enabled - assert mfa_settings.backup_codes == ["1", "2", "3"] - - assert response == %{ - "key" => secret, - "provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}") - } - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> get("/api/pleroma/accounts/mfa/setup/totp") - |> json_response(403) == %{ - "error" => "Insufficient permissions: write:security." - } - end - end - - describe "GET /api/pleroma/accounts/mfa/confirm/totp" do - test "returns success result", %{conn: conn} do - secret = TOTP.generate_secret() - code = TOTP.generate_token(secret) - - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - backup_codes: ["1", "2", "3"], - totp: %Settings.TOTP{secret: secret} - } - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - token2 = insert(:oauth_token, scopes: ["read"]) - - assert conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) - |> json_response(:ok) - - settings = refresh_record(user).multi_factor_authentication_settings - assert settings.enabled - assert settings.totp.secret == secret - assert settings.totp.confirmed - assert settings.backup_codes == ["1", "2", "3"] - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) - |> json_response(403) == %{ - "error" => "Insufficient permissions: write:security." - } - end - - test "returns error if password incorrect", %{conn: conn} do - secret = TOTP.generate_secret() - code = TOTP.generate_token(secret) - - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - backup_codes: ["1", "2", "3"], - totp: %Settings.TOTP{secret: secret} - } - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - - response = - conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code}) - |> json_response(422) - - settings = refresh_record(user).multi_factor_authentication_settings - refute settings.enabled - refute settings.totp.confirmed - assert settings.backup_codes == ["1", "2", "3"] - assert response == %{"error" => "Invalid password."} - end - - test "returns error if code incorrect", %{conn: conn} do - secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - backup_codes: ["1", "2", "3"], - totp: %Settings.TOTP{secret: secret} - } - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - token2 = insert(:oauth_token, scopes: ["read"]) - - response = - conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) - |> json_response(422) - - settings = refresh_record(user).multi_factor_authentication_settings - refute settings.enabled - refute settings.totp.confirmed - assert settings.backup_codes == ["1", "2", "3"] - assert response == %{"error" => "invalid_token"} - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) - |> json_response(403) == %{ - "error" => "Insufficient permissions: write:security." - } - end - end - - describe "DELETE /api/pleroma/accounts/mfa/totp" do - test "returns success result", %{conn: conn} do - user = - insert(:user, - multi_factor_authentication_settings: %Settings{ - backup_codes: ["1", "2", "3"], - totp: %Settings.TOTP{secret: "secret"} - } - ) - - token = insert(:oauth_token, scopes: ["write", "follow"], user: user) - token2 = insert(:oauth_token, scopes: ["read"]) - - assert conn - |> put_req_header("authorization", "Bearer #{token.token}") - |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) - |> json_response(:ok) - - settings = refresh_record(user).multi_factor_authentication_settings - refute settings.enabled - assert settings.totp.secret == nil - refute settings.totp.confirmed - - assert conn - |> put_req_header("authorization", "Bearer #{token2.token}") - |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) - |> json_response(403) == %{ - "error" => "Insufficient permissions: write:security." - } - end - end -end diff --git a/test/web/pleroma_api/views/chat/message_reference_view_test.exs b/test/web/pleroma_api/views/chat/message_reference_view_test.exs deleted file mode 100644 index e5b165255..000000000 --- a/test/web/pleroma_api/views/chat/message_reference_view_test.exs +++ /dev/null @@ -1,61 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do - use Pleroma.DataCase - - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Object - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView - - import Pleroma.Factory - - test "it displays a chat message" do - user = insert(:user) - recipient = insert(:user) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "kippis :firefox:") - - chat = Chat.get(user.id, recipient.ap_id) - - object = Object.normalize(activity) - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - chat_message = MessageReferenceView.render("show.json", chat_message_reference: cm_ref) - - assert chat_message[:id] == cm_ref.id - assert chat_message[:content] == "kippis :firefox:" - assert chat_message[:account_id] == user.id - assert chat_message[:chat_id] - assert chat_message[:created_at] - assert chat_message[:unread] == false - assert match?([%{shortcode: "firefox"}], chat_message[:emojis]) - - {:ok, activity} = CommonAPI.post_chat_message(recipient, user, "gkgkgk", media_id: upload.id) - - object = Object.normalize(activity) - - cm_ref = MessageReference.for_chat_and_object(chat, object) - - chat_message_two = MessageReferenceView.render("show.json", chat_message_reference: cm_ref) - - assert chat_message_two[:id] == cm_ref.id - assert chat_message_two[:content] == "gkgkgk" - assert chat_message_two[:account_id] == recipient.id - assert chat_message_two[:chat_id] == chat_message[:chat_id] - assert chat_message_two[:attachment] - assert chat_message_two[:unread] == true - end -end diff --git a/test/web/pleroma_api/views/chat_view_test.exs b/test/web/pleroma_api/views/chat_view_test.exs deleted file mode 100644 index 02484b705..000000000 --- a/test/web/pleroma_api/views/chat_view_test.exs +++ /dev/null @@ -1,49 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.ChatViewTest do - use Pleroma.DataCase - - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Object - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.MastodonAPI.AccountView - alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView - alias Pleroma.Web.PleromaAPI.ChatView - - import Pleroma.Factory - - test "it represents a chat" do - user = insert(:user) - recipient = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) - - represented_chat = ChatView.render("show.json", chat: chat) - - assert represented_chat == %{ - id: "#{chat.id}", - account: - AccountView.render("show.json", user: recipient, skip_visibility_check: true), - unread: 0, - last_message: nil, - updated_at: Utils.to_masto_date(chat.updated_at) - } - - {:ok, chat_message_creation} = CommonAPI.post_chat_message(user, recipient, "hello") - - chat_message = Object.normalize(chat_message_creation, false) - - {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) - - represented_chat = ChatView.render("show.json", chat: chat) - - cm_ref = MessageReference.for_chat_and_object(chat, chat_message) - - assert represented_chat[:last_message] == - MessageReferenceView.render("show.json", chat_message_reference: cm_ref) - end -end diff --git a/test/web/pleroma_api/views/scrobble_view_test.exs b/test/web/pleroma_api/views/scrobble_view_test.exs deleted file mode 100644 index 6bdb56509..000000000 --- a/test/web/pleroma_api/views/scrobble_view_test.exs +++ /dev/null @@ -1,20 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.StatusViewTest do - use Pleroma.DataCase - - alias Pleroma.Web.PleromaAPI.ScrobbleView - - import Pleroma.Factory - - test "successfully renders a Listen activity (pleroma extension)" do - listen_activity = insert(:listen) - - status = ScrobbleView.render("show.json", activity: listen_activity) - - assert status.length == listen_activity.data["object"]["length"] - assert status.title == listen_activity.data["object"]["title"] - end -end diff --git a/test/web/plugs/federating_plug_test.exs b/test/web/plugs/federating_plug_test.exs deleted file mode 100644 index 2f8aadadc..000000000 --- a/test/web/plugs/federating_plug_test.exs +++ /dev/null @@ -1,31 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FederatingPlugTest do - use Pleroma.Web.ConnCase - - setup do: clear_config([:instance, :federating]) - - test "returns and halt the conn when federating is disabled" do - Pleroma.Config.put([:instance, :federating], false) - - conn = - build_conn() - |> Pleroma.Web.FederatingPlug.call(%{}) - - assert conn.status == 404 - assert conn.halted - end - - test "does nothing when federating is enabled" do - Pleroma.Config.put([:instance, :federating], true) - - conn = - build_conn() - |> Pleroma.Web.FederatingPlug.call(%{}) - - refute conn.status - refute conn.halted - end -end diff --git a/test/web/plugs/plug_test.exs b/test/web/plugs/plug_test.exs deleted file mode 100644 index 943e484e7..000000000 --- a/test/web/plugs/plug_test.exs +++ /dev/null @@ -1,91 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PlugTest do - @moduledoc "Tests for the functionality added via `use Pleroma.Web, :plug`" - - alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug - alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug - alias Pleroma.Plugs.PlugHelper - - import Mock - - use Pleroma.Web.ConnCase - - describe "when plug is skipped, " do - setup_with_mocks( - [ - {ExpectPublicOrAuthenticatedCheckPlug, [:passthrough], []} - ], - %{conn: conn} - ) do - conn = ExpectPublicOrAuthenticatedCheckPlug.skip_plug(conn) - %{conn: conn} - end - - test "it neither adds plug to called plugs list nor calls `perform/2`, " <> - "regardless of :if_func / :unless_func options", - %{conn: conn} do - for opts <- [%{}, %{if_func: fn _ -> true end}, %{unless_func: fn _ -> false end}] do - ret_conn = ExpectPublicOrAuthenticatedCheckPlug.call(conn, opts) - - refute called(ExpectPublicOrAuthenticatedCheckPlug.perform(:_, :_)) - refute PlugHelper.plug_called?(ret_conn, ExpectPublicOrAuthenticatedCheckPlug) - end - end - end - - describe "when plug is NOT skipped, " do - setup_with_mocks([{ExpectAuthenticatedCheckPlug, [:passthrough], []}]) do - :ok - end - - test "with no pre-run checks, adds plug to called plugs list and calls `perform/2`", %{ - conn: conn - } do - ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{}) - - assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_)) - assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug) - end - - test "when :if_func option is given, calls the plug only if provided function evals tru-ish", - %{conn: conn} do - ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> false end}) - - refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_)) - refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug) - - ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> true end}) - - assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_)) - assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug) - end - - test "if :unless_func option is given, calls the plug only if provided function evals falsy", - %{conn: conn} do - ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> true end}) - - refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_)) - refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug) - - ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> false end}) - - assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_)) - assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug) - end - - test "allows a plug to be called multiple times (even if it's in called plugs list)", %{ - conn: conn - } do - conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value1}) - assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value1})) - - assert PlugHelper.plug_called?(conn, ExpectAuthenticatedCheckPlug) - - conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value2}) - assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value2})) - end - end -end diff --git a/test/web/preload/instance_test.exs b/test/web/preload/instance_test.exs deleted file mode 100644 index a46f28312..000000000 --- a/test/web/preload/instance_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Preload.Providers.InstanceTest do - use Pleroma.DataCase - alias Pleroma.Web.Preload.Providers.Instance - - setup do: {:ok, Instance.generate_terms(nil)} - - test "it renders the info", %{"/api/v1/instance" => info} do - assert %{ - description: description, - email: "admin@example.com", - registrations: true - } = info - - assert String.equivalent?(description, "Pleroma: An efficient and flexible fediverse server") - end - - test "it renders the panel", %{"/instance/panel.html" => panel} do - assert String.contains?( - panel, - "<p>Welcome to <a href=\"https://pleroma.social\" target=\"_blank\">Pleroma!</a></p>" - ) - end - - test "it works with overrides" do - clear_config([:instance, :static_dir], "test/fixtures/preload_static") - - %{"/instance/panel.html" => panel} = Instance.generate_terms(nil) - - assert String.contains?( - panel, - "HEY!" - ) - end - - test "it renders the node_info", %{"/nodeinfo/2.0.json" => nodeinfo} do - %{ - metadata: metadata, - version: "2.0" - } = nodeinfo - - assert metadata.private == false - assert metadata.suggestions == %{enabled: false} - end -end diff --git a/test/web/preload/timeline_test.exs b/test/web/preload/timeline_test.exs deleted file mode 100644 index fea95a6a4..000000000 --- a/test/web/preload/timeline_test.exs +++ /dev/null @@ -1,74 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Preload.Providers.TimelineTest do - use Pleroma.DataCase - import Pleroma.Factory - - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Preload.Providers.Timelines - - @public_url "/api/v1/timelines/public" - - describe "unauthenticated timeliness when restricted" do - setup do - svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines]) - Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{local: true, federated: true}) - - on_exit(fn -> - Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config) - end) - - :ok - end - - test "return nothing" do - tl_data = Timelines.generate_terms(%{}) - - refute Map.has_key?(tl_data, "/api/v1/timelines/public") - end - end - - describe "unauthenticated timeliness when unrestricted" do - setup do - svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines]) - - Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{ - local: false, - federated: false - }) - - on_exit(fn -> - Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config) - end) - - {:ok, user: insert(:user)} - end - - test "returns the timeline when not restricted" do - assert Timelines.generate_terms(%{}) - |> Map.has_key?(@public_url) - end - - test "returns public items", %{user: user} do - {:ok, _} = CommonAPI.post(user, %{status: "it's post 1!"}) - {:ok, _} = CommonAPI.post(user, %{status: "it's post 2!"}) - {:ok, _} = CommonAPI.post(user, %{status: "it's post 3!"}) - - assert Timelines.generate_terms(%{}) - |> Map.fetch!(@public_url) - |> Enum.count() == 3 - end - - test "does not return non-public items", %{user: user} do - {:ok, _} = CommonAPI.post(user, %{status: "it's post 1!", visibility: "unlisted"}) - {:ok, _} = CommonAPI.post(user, %{status: "it's post 2!", visibility: "direct"}) - {:ok, _} = CommonAPI.post(user, %{status: "it's post 3!"}) - - assert Timelines.generate_terms(%{}) - |> Map.fetch!(@public_url) - |> Enum.count() == 1 - end - end -end diff --git a/test/web/preload/user_test.exs b/test/web/preload/user_test.exs deleted file mode 100644 index 83f065e27..000000000 --- a/test/web/preload/user_test.exs +++ /dev/null @@ -1,33 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Preload.Providers.UserTest do - use Pleroma.DataCase - import Pleroma.Factory - alias Pleroma.Web.Preload.Providers.User - - describe "returns empty when user doesn't exist" do - test "nil user specified" do - assert User.generate_terms(%{user: nil}) == %{} - end - - test "missing user specified" do - assert User.generate_terms(%{user: :not_a_user}) == %{} - end - end - - describe "specified user exists" do - setup do - user = insert(:user) - - terms = User.generate_terms(%{user: user}) - %{terms: terms, user: user} - end - - test "account is rendered", %{terms: terms, user: user} do - account = terms["/api/v1/accounts/#{user.id}"] - assert %{acct: user, username: user} = account - end - end -end diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs deleted file mode 100644 index aeb5c1fbd..000000000 --- a/test/web/push/impl_test.exs +++ /dev/null @@ -1,344 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Push.ImplTest do - use Pleroma.DataCase - - alias Pleroma.Notification - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Push.Impl - alias Pleroma.Web.Push.Subscription - - import Pleroma.Factory - - setup do - Tesla.Mock.mock(fn - %{method: :post, url: "https://example.com/example/1234"} -> - %Tesla.Env{status: 200} - - %{method: :post, url: "https://example.com/example/not_found"} -> - %Tesla.Env{status: 400} - - %{method: :post, url: "https://example.com/example/bad"} -> - %Tesla.Env{status: 100} - end) - - :ok - end - - @sub %{ - endpoint: "https://example.com/example/1234", - keys: %{ - auth: "8eDyX_uCN0XRhSbY5hs7Hg==", - p256dh: - "BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA=" - } - } - @api_key "BASgACIHpN1GYgzSRp" - @message "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." - - test "performs sending notifications" do - user = insert(:user) - user2 = insert(:user) - insert(:push_subscription, user: user, data: %{alerts: %{"mention" => true}}) - insert(:push_subscription, user: user2, data: %{alerts: %{"mention" => true}}) - - insert(:push_subscription, - user: user, - data: %{alerts: %{"follow" => true, "mention" => true}} - ) - - insert(:push_subscription, - user: user, - data: %{alerts: %{"follow" => true, "mention" => false}} - ) - - {:ok, activity} = CommonAPI.post(user, %{status: "<Lorem ipsum dolor sit amet."}) - - notif = - insert(:notification, - user: user, - activity: activity, - type: "mention" - ) - - assert Impl.perform(notif) == {:ok, [:ok, :ok]} - end - - @tag capture_log: true - test "returns error if notif does not match " do - assert Impl.perform(%{}) == {:error, :unknown_type} - end - - test "successful message sending" do - assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok - end - - @tag capture_log: true - test "fail message sending" do - assert Impl.push_message( - @message, - Map.merge(@sub, %{endpoint: "https://example.com/example/bad"}), - @api_key, - %Subscription{} - ) == :error - end - - test "delete subscription if result send message between 400..500" do - subscription = insert(:push_subscription) - - assert Impl.push_message( - @message, - Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}), - @api_key, - subscription - ) == :ok - - refute Pleroma.Repo.get(Subscription, subscription.id) - end - - test "deletes subscription when token has been deleted" do - subscription = insert(:push_subscription) - - Pleroma.Repo.delete(subscription.token) - - refute Pleroma.Repo.get(Subscription, subscription.id) - end - - test "renders title and body for create activity" do - user = insert(:user, nickname: "Bob") - - {:ok, activity} = - CommonAPI.post(user, %{ - status: - "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." - }) - - object = Object.normalize(activity) - - assert Impl.format_body( - %{ - activity: activity - }, - user, - object - ) == - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." - - assert Impl.format_title(%{activity: activity, type: "mention"}) == - "New Mention" - end - - test "renders title and body for follow activity" do - user = insert(:user, nickname: "Bob") - other_user = insert(:user) - {:ok, _, _, activity} = CommonAPI.follow(user, other_user) - object = Object.normalize(activity, false) - - assert Impl.format_body(%{activity: activity, type: "follow"}, user, object) == - "@Bob has followed you" - - assert Impl.format_title(%{activity: activity, type: "follow"}) == - "New Follower" - end - - test "renders title and body for announce activity" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: - "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." - }) - - {:ok, announce_activity} = CommonAPI.repeat(activity.id, user) - object = Object.normalize(activity) - - assert Impl.format_body(%{activity: announce_activity}, user, object) == - "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..." - - assert Impl.format_title(%{activity: announce_activity, type: "reblog"}) == - "New Repeat" - end - - test "renders title and body for like activity" do - user = insert(:user, nickname: "Bob") - - {:ok, activity} = - CommonAPI.post(user, %{ - status: - "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." - }) - - {:ok, activity} = CommonAPI.favorite(user, activity.id) - object = Object.normalize(activity) - - assert Impl.format_body(%{activity: activity, type: "favourite"}, user, object) == - "@Bob has favorited your post" - - assert Impl.format_title(%{activity: activity, type: "favourite"}) == - "New Favorite" - end - - test "renders title for create activity with direct visibility" do - user = insert(:user, nickname: "Bob") - - {:ok, activity} = - CommonAPI.post(user, %{ - visibility: "direct", - status: "This is just between you and me, pal" - }) - - assert Impl.format_title(%{activity: activity}) == - "New Direct Message" - end - - describe "build_content/3" do - test "builds content for chat messages" do - user = insert(:user) - recipient = insert(:user) - - {:ok, chat} = CommonAPI.post_chat_message(user, recipient, "hey") - object = Object.normalize(chat, false) - [notification] = Notification.for_user(recipient) - - res = Impl.build_content(notification, user, object) - - assert res == %{ - body: "@#{user.nickname}: hey", - title: "New Chat Message" - } - end - - test "builds content for chat messages with no content" do - user = insert(:user) - recipient = insert(:user) - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image.jpg"), - filename: "an_image.jpg" - } - - {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - - {:ok, chat} = CommonAPI.post_chat_message(user, recipient, nil, media_id: upload.id) - object = Object.normalize(chat, false) - [notification] = Notification.for_user(recipient) - - res = Impl.build_content(notification, user, object) - - assert res == %{ - body: "@#{user.nickname}: (Attachment)", - title: "New Chat Message" - } - end - - test "hides contents of notifications when option enabled" do - user = insert(:user, nickname: "Bob") - - user2 = - insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: true}) - - {:ok, activity} = - CommonAPI.post(user, %{ - visibility: "direct", - status: "<Lorem ipsum dolor sit amet." - }) - - notif = insert(:notification, user: user2, activity: activity) - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: "New Direct Message" - } - - {:ok, activity} = - CommonAPI.post(user, %{ - visibility: "public", - status: "<Lorem ipsum dolor sit amet." - }) - - notif = insert(:notification, user: user2, activity: activity, type: "mention") - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: "New Mention" - } - - {:ok, activity} = CommonAPI.favorite(user, activity.id) - - notif = insert(:notification, user: user2, activity: activity, type: "favourite") - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: "New Favorite" - } - end - - test "returns regular content when hiding contents option disabled" do - user = insert(:user, nickname: "Bob") - - user2 = - insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: false}) - - {:ok, activity} = - CommonAPI.post(user, %{ - visibility: "direct", - status: - "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." - }) - - notif = insert(:notification, user: user2, activity: activity) - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...", - title: "New Direct Message" - } - - {:ok, activity} = - CommonAPI.post(user, %{ - visibility: "public", - status: - "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." - }) - - notif = insert(:notification, user: user2, activity: activity, type: "mention") - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: - "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...", - title: "New Mention" - } - - {:ok, activity} = CommonAPI.favorite(user, activity.id) - - notif = insert(:notification, user: user2, activity: activity, type: "favourite") - - actor = User.get_cached_by_ap_id(notif.activity.data["actor"]) - object = Object.normalize(activity) - - assert Impl.build_content(notif, actor, object) == %{ - body: "@Bob has favorited your post", - title: "New Favorite" - } - end - end -end diff --git a/test/web/rel_me_test.exs b/test/web/rel_me_test.exs deleted file mode 100644 index 65255916d..000000000 --- a/test/web/rel_me_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.RelMeTest do - use ExUnit.Case - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - test "parse/1" do - hrefs = ["https://social.example.org/users/lain"] - - assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/null") == {:ok, []} - - assert {:ok, %Tesla.Env{status: 404}} = - Pleroma.Web.RelMe.parse("http://example.com/rel_me/error") - - assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/link") == {:ok, hrefs} - assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/anchor") == {:ok, hrefs} - assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/anchor_nofollow") == {:ok, hrefs} - end - - test "maybe_put_rel_me/2" do - profile_urls = ["https://social.example.org/users/lain"] - attr = "me" - fallback = nil - - assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/null", profile_urls) == - fallback - - assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/error", profile_urls) == - fallback - - assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/anchor", profile_urls) == - attr - - assert Pleroma.Web.RelMe.maybe_put_rel_me( - "http://example.com/rel_me/anchor_nofollow", - profile_urls - ) == attr - - assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/link", profile_urls) == - attr - end -end diff --git a/test/web/rich_media/aws_signed_url_test.exs b/test/web/rich_media/aws_signed_url_test.exs deleted file mode 100644 index b30f4400e..000000000 --- a/test/web/rich_media/aws_signed_url_test.exs +++ /dev/null @@ -1,82 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do - use ExUnit.Case, async: true - - test "s3 signed url is parsed correct for expiration time" do - url = "https://pleroma.social/amz" - - {:ok, timestamp} = - Timex.now() - |> DateTime.truncate(:second) - |> Timex.format("{ISO:Basic:Z}") - - # in seconds - valid_till = 30 - - metadata = construct_metadata(timestamp, valid_till, url) - - expire_time = - Timex.parse!(timestamp, "{ISO:Basic:Z}") |> Timex.to_unix() |> Kernel.+(valid_till) - - assert expire_time == Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl.ttl(metadata, url) - end - - test "s3 signed url is parsed and correct ttl is set for rich media" do - url = "https://pleroma.social/amz" - - {:ok, timestamp} = - Timex.now() - |> DateTime.truncate(:second) - |> Timex.format("{ISO:Basic:Z}") - - # in seconds - valid_till = 30 - - metadata = construct_metadata(timestamp, valid_till, url) - - body = """ - <meta name="twitter:card" content="Pleroma" /> - <meta name="twitter:site" content="Pleroma" /> - <meta name="twitter:title" content="Pleroma" /> - <meta name="twitter:description" content="Pleroma" /> - <meta name="twitter:image" content="#{Map.get(metadata, :image)}" /> - """ - - Tesla.Mock.mock(fn - %{ - method: :get, - url: "https://pleroma.social/amz" - } -> - %Tesla.Env{status: 200, body: body} - end) - - Cachex.put(:rich_media_cache, url, metadata) - - Pleroma.Web.RichMedia.Parser.set_ttl_based_on_image({:ok, metadata}, url) - - {:ok, cache_ttl} = Cachex.ttl(:rich_media_cache, url) - - # as there is delay in setting and pulling the data from cache we ignore 1 second - # make it 2 seconds for flakyness - assert_in_delta(valid_till * 1000, cache_ttl, 2000) - end - - defp construct_s3_url(timestamp, valid_till) do - "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{ - timestamp - }&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host" - end - - defp construct_metadata(timestamp, valid_till, url) do - %{ - image: construct_s3_url(timestamp, valid_till), - site: "Pleroma", - title: "Pleroma", - description: "Pleroma", - url: url - } - end -end diff --git a/test/web/rich_media/helpers_test.exs b/test/web/rich_media/helpers_test.exs deleted file mode 100644 index 8264a9c41..000000000 --- a/test/web/rich_media/helpers_test.exs +++ /dev/null @@ -1,121 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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) - - :ok - end - - setup do: clear_config([:rich_media, :enabled]) - - test "refuses to crawl incomplete URLs" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "[test](example.com/ogp)", - content_type: "text/markdown" - }) - - Config.put([:rich_media, :enabled], true) - - assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - - test "refuses to crawl malformed URLs" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "[test](example.com[]/ogp)", - content_type: "text/markdown" - }) - - Config.put([:rich_media, :enabled], true) - - assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - - test "crawls valid, complete URLs" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "[test](https://example.com/ogp)", - content_type: "text/markdown" - }) - - Config.put([:rich_media, :enabled], true) - - assert %{page_url: "https://example.com/ogp", rich_media: _} = - Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - - test "refuses to crawl URLs from posts marked sensitive" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "http://example.com/ogp", - sensitive: true - }) - - %Object{} = object = Object.normalize(activity) - - assert object.data["sensitive"] - - Config.put([:rich_media, :enabled], true) - - assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end - - test "refuses to crawl URLs from posts tagged NSFW" do - user = insert(:user) - - {:ok, activity} = - CommonAPI.post(user, %{ - status: "http://example.com/ogp #nsfw" - }) - - %Object{} = object = Object.normalize(activity) - - assert object.data["sensitive"] - - 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) - - 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 deleted file mode 100644 index 420a612c6..000000000 --- a/test/web/rich_media/parser_test.exs +++ /dev/null @@ -1,137 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.RichMedia.ParserTest do - use ExUnit.Case, async: true - - setup do - Tesla.Mock.mock(fn - %{ - method: :get, - url: "http://example.com/ogp" - } -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")} - - %{ - 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")} - - %{ - method: :get, - url: "http://example.com/oembed" - } -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.html")} - - %{ - method: :get, - url: "http://example.com/oembed.json" - } -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/oembed.json")} - - %{method: :get, url: "http://example.com/empty"} -> - %Tesla.Env{status: 200, body: "hello"} - end) - - :ok - end - - test "returns error when no metadata present" 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: %{\"url\" => \"http://example.com/non-ogp\"}"} - 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://example.com/ogp" - }} - 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://example.com/ogp-missing-title" - }} - end - - test "parses twitter card" do - assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/twitter-card") == - {:ok, - %{ - "card" => "summary", - "site" => "@flickr", - "image" => "https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg", - "title" => "Small Island Developing States Photo Submission", - "description" => "View the album on Flickr.", - "url" => "http://example.com/twitter-card" - }} - end - - test "parses OEmbed" do - assert Pleroma.Web.RichMedia.Parser.parse("http://example.com/oembed") == - {:ok, - %{ - "author_name" => "bees", - "author_url" => "https://www.flickr.com/photos/bees/", - "cache_age" => 3600, - "flickr_type" => "photo", - "height" => "768", - "html" => - "<a data-flickr-embed=\"true\" href=\"https://www.flickr.com/photos/bees/2362225867/\" title=\"Bacon Lollys by bees, on Flickr\"><img src=\"https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_b.jpg\" width=\"1024\" height=\"768\" alt=\"Bacon Lollys\"></a><script async src=\"https://embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"></script>", - "license" => "All Rights Reserved", - "license_id" => 0, - "provider_name" => "Flickr", - "provider_url" => "https://www.flickr.com/", - "thumbnail_height" => 150, - "thumbnail_url" => - "https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_q.jpg", - "thumbnail_width" => 150, - "title" => "Bacon Lollys", - "type" => "photo", - "url" => "http://example.com/oembed", - "version" => "1.0", - "web_page" => "https://www.flickr.com/photos/bees/2362225867/", - "web_page_short_url" => "https://flic.kr/p/4AK2sc", - "width" => "1024" - }} - end - - test "rejects invalid OGP data" do - assert {:error, _} = Pleroma.Web.RichMedia.Parser.parse("http://example.com/malformed") - end -end diff --git a/test/web/rich_media/parsers/twitter_card_test.exs b/test/web/rich_media/parsers/twitter_card_test.exs deleted file mode 100644 index 219f005a2..000000000 --- a/test/web/rich_media/parsers/twitter_card_test.exs +++ /dev/null @@ -1,127 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do - use ExUnit.Case, async: true - alias Pleroma.Web.RichMedia.Parsers.TwitterCard - - test "returns error when html not contains twitter card" do - assert TwitterCard.parse([{"html", [], [{"head", [], []}, {"body", [], []}]}], %{}) == %{} - end - - test "parses twitter card with only name attributes" do - html = - File.read!("test/fixtures/nypd-facial-recognition-children-teenagers3.html") - |> Floki.parse_document!() - - assert TwitterCard.parse(html, %{}) == - %{ - "app:id:googleplay" => "com.nytimes.android", - "app:name:googleplay" => "NYTimes", - "app:url:googleplay" => "nytimes://reader/id/100000006583622", - "site" => nil, - "description" => - "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", - "image" => - "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-facebookJumbo.jpg", - "type" => "article", - "url" => - "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html", - "title" => - "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database." - } - end - - test "parses twitter card with only property attributes" do - html = - File.read!("test/fixtures/nypd-facial-recognition-children-teenagers2.html") - |> Floki.parse_document!() - - assert TwitterCard.parse(html, %{}) == - %{ - "card" => "summary_large_image", - "description" => - "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", - "image" => - "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg", - "image:alt" => "", - "title" => - "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.", - "url" => - "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html", - "type" => "article" - } - end - - test "parses twitter card with name & property attributes" do - html = - File.read!("test/fixtures/nypd-facial-recognition-children-teenagers.html") - |> Floki.parse_document!() - - assert TwitterCard.parse(html, %{}) == - %{ - "app:id:googleplay" => "com.nytimes.android", - "app:name:googleplay" => "NYTimes", - "app:url:googleplay" => "nytimes://reader/id/100000006583622", - "card" => "summary_large_image", - "description" => - "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", - "image" => - "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg", - "image:alt" => "", - "site" => nil, - "title" => - "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.", - "url" => - "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html", - "type" => "article" - } - end - - test "respect only first title tag on the page" do - image_path = - "https://assets.atlasobscura.com/media/W1siZiIsInVwbG9hZHMvYXNzZXRzLzkwYzgyMzI4LThlMDUtNGRiNS05MDg3LTUzMGUxZTM5N2RmMmVkOTM5ZDM4MGM4OTIx" <> - "YTQ5MF9EQVIgZXhodW1hdGlvbiBvZiBNYXJnYXJldCBDb3JiaW4gZ3JhdmUgMTkyNi5qcGciXSxbInAiLCJjb252ZXJ0IiwiIl0sWyJwIiwiY29udmVydCIsIi1xdWFsaXR5IDgxIC1hdXRvLW9" <> - "yaWVudCJdLFsicCIsInRodW1iIiwiNjAweD4iXV0/DAR%20exhumation%20of%20Margaret%20Corbin%20grave%201926.jpg" - - html = - File.read!("test/fixtures/margaret-corbin-grave-west-point.html") |> Floki.parse_document!() - - assert TwitterCard.parse(html, %{}) == - %{ - "site" => "@atlasobscura", - "title" => "The Missing Grave of Margaret Corbin, Revolutionary War Veteran", - "card" => "summary_large_image", - "image" => image_path, - "description" => - "She's the only woman veteran honored with a monument at West Point. But where was she buried?", - "site_name" => "Atlas Obscura", - "type" => "article", - "url" => "http://www.atlasobscura.com/articles/margaret-corbin-grave-west-point" - } - end - - test "takes first founded title in html head if there is html markup error" do - html = - File.read!("test/fixtures/nypd-facial-recognition-children-teenagers4.html") - |> Floki.parse_document!() - - assert TwitterCard.parse(html, %{}) == - %{ - "site" => nil, - "title" => - "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.", - "app:id:googleplay" => "com.nytimes.android", - "app:name:googleplay" => "NYTimes", - "app:url:googleplay" => "nytimes://reader/id/100000006583622", - "description" => - "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", - "image" => - "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-facebookJumbo.jpg", - "type" => "article", - "url" => - "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html" - } - end -end diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/web/static_fe/static_fe_controller_test.exs deleted file mode 100644 index 1598bf675..000000000 --- a/test/web/static_fe/static_fe_controller_test.exs +++ /dev/null @@ -1,192 +0,0 @@ -defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Activity - alias Pleroma.Config - alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.CommonAPI - - import Pleroma.Factory - - setup_all do: clear_config([:static_fe, :enabled], true) - setup do: clear_config([:instance, :federating], true) - - setup %{conn: conn} do - conn = put_req_header(conn, "accept", "text/html") - user = insert(:user) - - %{conn: conn, user: user} - end - - describe "user profile html" do - test "just the profile as HTML", %{conn: conn, user: user} do - conn = get(conn, "/users/#{user.nickname}") - - assert html_response(conn, 200) =~ user.nickname - end - - test "404 when user not found", %{conn: conn} do - conn = get(conn, "/users/limpopo") - - assert html_response(conn, 404) =~ "not found" - end - - test "profile does not include private messages", %{conn: conn, user: user} do - CommonAPI.post(user, %{status: "public"}) - CommonAPI.post(user, %{status: "private", visibility: "private"}) - - conn = get(conn, "/users/#{user.nickname}") - - html = html_response(conn, 200) - - assert html =~ ">public<" - refute html =~ ">private<" - end - - test "pagination", %{conn: conn, user: user} do - Enum.map(1..30, fn i -> CommonAPI.post(user, %{status: "test#{i}"}) end) - - conn = get(conn, "/users/#{user.nickname}") - - html = html_response(conn, 200) - - assert html =~ ">test30<" - assert html =~ ">test11<" - refute html =~ ">test10<" - refute html =~ ">test1<" - end - - test "pagination, page 2", %{conn: conn, user: user} do - activities = Enum.map(1..30, fn i -> CommonAPI.post(user, %{status: "test#{i}"}) end) - {:ok, a11} = Enum.at(activities, 11) - - conn = get(conn, "/users/#{user.nickname}?max_id=#{a11.id}") - - html = html_response(conn, 200) - - assert html =~ ">test1<" - assert html =~ ">test10<" - refute html =~ ">test20<" - refute html =~ ">test29<" - end - - test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do - ensure_federating_or_authenticated(conn, "/users/#{user.nickname}", user) - end - end - - describe "notice html" do - test "single notice page", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) - - conn = get(conn, "/notice/#{activity.id}") - - html = html_response(conn, 200) - assert html =~ "<header>" - assert html =~ user.nickname - assert html =~ "testing a thing!" - end - - test "redirects to json if requested", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) - - conn = - conn - |> put_req_header( - "accept", - "Accept: application/activity+json, application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\", text/html" - ) - |> get("/notice/#{activity.id}") - - assert redirected_to(conn, 302) =~ activity.data["object"] - end - - test "filters HTML tags", %{conn: conn} do - user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "<script>alert('xss')</script>"}) - - conn = - conn - |> put_req_header("accept", "text/html") - |> get("/notice/#{activity.id}") - - html = html_response(conn, 200) - assert html =~ ~s[<script>alert('xss')</script>] - end - - test "shows the whole thread", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "space: the final frontier"}) - - CommonAPI.post(user, %{ - status: "these are the voyages or something", - in_reply_to_status_id: activity.id - }) - - conn = get(conn, "/notice/#{activity.id}") - - html = html_response(conn, 200) - assert html =~ "the final frontier" - assert html =~ "voyages" - end - - test "redirect by AP object ID", %{conn: conn, user: user} do - {:ok, %Activity{data: %{"object" => object_url}}} = - CommonAPI.post(user, %{status: "beam me up"}) - - conn = get(conn, URI.parse(object_url).path) - - assert html_response(conn, 302) =~ "redirected" - end - - test "redirect by activity ID", %{conn: conn, user: user} do - {:ok, %Activity{data: %{"id" => id}}} = - CommonAPI.post(user, %{status: "I'm a doctor, not a devops!"}) - - conn = get(conn, URI.parse(id).path) - - assert html_response(conn, 302) =~ "redirected" - end - - test "404 when notice not found", %{conn: conn} do - conn = get(conn, "/notice/88c9c317") - - assert html_response(conn, 404) =~ "not found" - end - - test "404 for private status", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "don't show me!", visibility: "private"}) - - conn = get(conn, "/notice/#{activity.id}") - - assert html_response(conn, 404) =~ "not found" - end - - test "302 for remote cached status", %{conn: conn, user: user} do - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "to" => user.follower_address, - "cc" => "https://www.w3.org/ns/activitystreams#Public", - "type" => "Create", - "object" => %{ - "content" => "blah blah blah", - "type" => "Note", - "attributedTo" => user.ap_id, - "inReplyTo" => nil - }, - "actor" => user.ap_id - } - - assert {:ok, activity} = Transmogrifier.handle_incoming(message) - - conn = get(conn, "/notice/#{activity.id}") - - assert html_response(conn, 302) =~ "redirected" - end - - test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do - {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) - - ensure_federating_or_authenticated(conn, "/notice/#{activity.id}", user) - end - end -end diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs deleted file mode 100644 index d56d74464..000000000 --- a/test/web/streamer/streamer_test.exs +++ /dev/null @@ -1,671 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.StreamerTest do - use Pleroma.DataCase - - import Pleroma.Factory - - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Conversation.Participation - alias Pleroma.List - alias Pleroma.Object - alias Pleroma.User - alias Pleroma.Web.CommonAPI - alias Pleroma.Web.Streamer - alias Pleroma.Web.StreamerView - - @moduletag needs_streamer: true, capture_log: true - - setup do: clear_config([:instance, :skip_thread_containment]) - - describe "get_topic without an user" do - test "allows public" do - assert {:ok, "public"} = Streamer.get_topic("public", nil) - assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil) - assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil) - assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil) - end - - test "allows hashtag streams" do - assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, %{"tag" => "cofe"}) - end - - test "disallows user streams" do - assert {:error, _} = Streamer.get_topic("user", nil) - assert {:error, _} = Streamer.get_topic("user:notification", nil) - assert {:error, _} = Streamer.get_topic("direct", nil) - end - - test "disallows list streams" do - assert {:error, _} = Streamer.get_topic("list", nil, %{"list" => 42}) - end - end - - describe "get_topic with an user" do - setup do - user = insert(:user) - {:ok, %{user: user}} - end - - test "allows public streams", %{user: user} do - assert {:ok, "public"} = Streamer.get_topic("public", user) - assert {:ok, "public:local"} = Streamer.get_topic("public:local", user) - assert {:ok, "public:media"} = Streamer.get_topic("public:media", user) - assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", user) - end - - test "allows user streams", %{user: user} do - expected_user_topic = "user:#{user.id}" - expected_notif_topic = "user:notification:#{user.id}" - expected_direct_topic = "direct:#{user.id}" - assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user) - assert {:ok, ^expected_notif_topic} = Streamer.get_topic("user:notification", user) - assert {:ok, ^expected_direct_topic} = Streamer.get_topic("direct", user) - end - - test "allows hashtag streams", %{user: user} do - assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", user, %{"tag" => "cofe"}) - end - - test "disallows registering to an user stream", %{user: user} do - another_user = insert(:user) - assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user) - assert {:error, _} = Streamer.get_topic("user:notification:#{another_user.id}", user) - assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user) - end - - test "allows list stream that are owned by the user", %{user: user} do - {:ok, list} = List.create("Test", user) - assert {:error, _} = Streamer.get_topic("list:#{list.id}", user) - assert {:ok, _} = Streamer.get_topic("list", user, %{"list" => list.id}) - end - - test "disallows list stream that are not owned by the user", %{user: user} do - another_user = insert(:user) - {:ok, list} = List.create("Test", another_user) - assert {:error, _} = Streamer.get_topic("list:#{list.id}", user) - assert {:error, _} = Streamer.get_topic("list", user, %{"list" => list.id}) - end - end - - describe "user streams" do - setup do - user = insert(:user) - notify = insert(:notification, user: user, activity: build(:note_activity)) - {:ok, %{user: user, notify: notify}} - end - - test "it streams the user's post in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user, activity) - end - - test "it streams boosts of the user in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) - - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) - {:ok, announce} = CommonAPI.repeat(activity.id, user) - - assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} - refute Streamer.filtered_by_user?(user, announce) - end - - test "it does not stream announces of the user's own posts in the 'user' stream", %{ - user: user - } do - Streamer.get_topic_and_add_socket("user", user) - - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, announce} = CommonAPI.repeat(activity.id, other_user) - - assert Streamer.filtered_by_user?(user, announce) - end - - test "it does stream notifications announces of the user's own posts in the 'user' stream", %{ - user: user - } do - Streamer.get_topic_and_add_socket("user", user) - - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - {:ok, announce} = CommonAPI.repeat(activity.id, other_user) - - notification = - Pleroma.Notification - |> Repo.get_by(%{user_id: user.id, activity_id: announce.id}) - |> Repo.preload(:activity) - - refute Streamer.filtered_by_user?(user, notification) - end - - test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do - Streamer.get_topic_and_add_socket("user", user) - - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) - - data = - File.read!("test/fixtures/mastodon-announce.json") - |> Poison.decode!() - |> Map.put("object", activity.data["object"]) - |> Map.put("actor", user.ap_id) - - {:ok, %Pleroma.Activity{data: _data, local: false} = announce} = - Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(data) - - assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} - refute Streamer.filtered_by_user?(user, announce) - end - - test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do - Streamer.get_topic_and_add_socket("user", user) - Streamer.stream("user", notify) - assert_receive {:render_with_user, _, _, ^notify} - refute Streamer.filtered_by_user?(user, notify) - end - - test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do - Streamer.get_topic_and_add_socket("user:notification", user) - Streamer.stream("user:notification", notify) - assert_receive {:render_with_user, _, _, ^notify} - refute Streamer.filtered_by_user?(user, notify) - end - - test "it sends chat messages to the 'user:pleroma_chat' stream", %{user: user} do - other_user = insert(:user) - - {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") - object = Object.normalize(create_activity, false) - chat = Chat.get(user.id, other_user.ap_id) - cm_ref = MessageReference.for_chat_and_object(chat, object) - cm_ref = %{cm_ref | chat: chat, object: object} - - Streamer.get_topic_and_add_socket("user:pleroma_chat", user) - Streamer.stream("user:pleroma_chat", {user, cm_ref}) - - text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) - - assert text =~ "hey cirno" - assert_receive {:text, ^text} - end - - test "it sends chat messages to the 'user' stream", %{user: user} do - other_user = insert(:user) - - {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") - object = Object.normalize(create_activity, false) - chat = Chat.get(user.id, other_user.ap_id) - cm_ref = MessageReference.for_chat_and_object(chat, object) - cm_ref = %{cm_ref | chat: chat, object: object} - - Streamer.get_topic_and_add_socket("user", user) - Streamer.stream("user", {user, cm_ref}) - - text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) - - assert text =~ "hey cirno" - assert_receive {:text, ^text} - end - - test "it sends chat message notifications to the 'user:notification' stream", %{user: user} do - other_user = insert(:user) - - {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey") - - notify = - Repo.get_by(Pleroma.Notification, user_id: user.id, activity_id: create_activity.id) - |> Repo.preload(:activity) - - Streamer.get_topic_and_add_socket("user:notification", user) - Streamer.stream("user:notification", notify) - assert_receive {:render_with_user, _, _, ^notify} - refute Streamer.filtered_by_user?(user, notify) - end - - test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{ - user: user - } do - blocked = insert(:user) - {:ok, _user_relationship} = User.block(user, blocked) - - Streamer.get_topic_and_add_socket("user:notification", user) - - {:ok, activity} = CommonAPI.post(user, %{status: ":("}) - {:ok, _} = CommonAPI.favorite(blocked, activity.id) - - refute_receive _ - end - - test "it doesn't send notify to the 'user:notification' stream when a thread is muted", %{ - user: user - } do - user2 = insert(:user) - - {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - {:ok, _} = CommonAPI.add_mute(user, activity) - - Streamer.get_topic_and_add_socket("user:notification", user) - - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) - - refute_receive _ - assert Streamer.filtered_by_user?(user, favorite_activity) - end - - test "it sends favorite to 'user:notification' stream'", %{ - user: user - } do - user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) - - {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - Streamer.get_topic_and_add_socket("user:notification", user) - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) - - assert_receive {:render_with_user, _, "notification.json", notif} - assert notif.activity.id == favorite_activity.id - refute Streamer.filtered_by_user?(user, notif) - end - - test "it doesn't send the 'user:notification' stream' when a domain is blocked", %{ - user: user - } do - user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) - - {:ok, user} = User.block_domain(user, "hecking-lewd-place.com") - {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - Streamer.get_topic_and_add_socket("user:notification", user) - {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) - - refute_receive _ - assert Streamer.filtered_by_user?(user, favorite_activity) - end - - test "it sends follow activities to the 'user:notification' stream", %{ - user: user - } do - user_url = user.ap_id - user2 = insert(:user) - - body = - File.read!("test/fixtures/users_mock/localhost.json") - |> String.replace("{{nickname}}", user.nickname) - |> Jason.encode!() - - Tesla.Mock.mock_global(fn - %{method: :get, url: ^user_url} -> - %Tesla.Env{status: 200, body: body} - end) - - Streamer.get_topic_and_add_socket("user:notification", user) - {:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user) - - assert_receive {:render_with_user, _, "notification.json", notif} - assert notif.activity.id == follow_activity.id - refute Streamer.filtered_by_user?(user, notif) - end - end - - test "it sends to public authenticated" do - user = insert(:user) - other_user = insert(:user) - - Streamer.get_topic_and_add_socket("public", other_user) - - {:ok, activity} = CommonAPI.post(user, %{status: "Test"}) - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user, activity) - end - - test "works for deletions" do - user = insert(:user) - other_user = insert(:user) - {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"}) - - Streamer.get_topic_and_add_socket("public", user) - - {:ok, _} = CommonAPI.delete(activity.id, other_user) - activity_id = activity.id - assert_receive {:text, event} - assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) - end - - test "it sends to public unauthenticated" do - user = insert(:user) - - Streamer.get_topic_and_add_socket("public", nil) - - {:ok, activity} = CommonAPI.post(user, %{status: "Test"}) - activity_id = activity.id - assert_receive {:text, event} - assert %{"event" => "update", "payload" => payload} = Jason.decode!(event) - assert %{"id" => ^activity_id} = Jason.decode!(payload) - - {:ok, _} = CommonAPI.delete(activity.id, user) - assert_receive {:text, event} - assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event) - end - - describe "thread_containment" do - test "it filters 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) - User.follow(user, author, :follow_accept) - - activity = - insert(:note_activity, - note: - insert(:note, - user: author, - data: %{"to" => ["TEST-FFF"]} - ) - ) - - Streamer.get_topic_and_add_socket("public", user) - Streamer.stream("public", activity) - assert_receive {:render_with_user, _, _, ^activity} - assert Streamer.filtered_by_user?(user, activity) - 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) - User.follow(user, author, :follow_accept) - - activity = - insert(:note_activity, - note: - insert(:note, - user: author, - data: %{"to" => ["TEST-FFF"]} - ) - ) - - Streamer.get_topic_and_add_socket("public", user) - Streamer.stream("public", activity) - - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user, activity) - 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, skip_thread_containment: true) - User.follow(user, author, :follow_accept) - - activity = - insert(:note_activity, - note: - insert(:note, - user: author, - data: %{"to" => ["TEST-FFF"]} - ) - ) - - Streamer.get_topic_and_add_socket("public", user) - Streamer.stream("public", activity) - - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user, activity) - end - end - - describe "blocks" do - test "it filters messages involving blocked users" do - user = insert(:user) - blocked_user = insert(:user) - {:ok, _user_relationship} = User.block(user, blocked_user) - - Streamer.get_topic_and_add_socket("public", user) - {:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"}) - assert_receive {:render_with_user, _, _, ^activity} - assert Streamer.filtered_by_user?(user, activity) - end - - test "it filters messages transitively involving blocked users" do - blocker = insert(:user) - blockee = insert(:user) - friend = insert(:user) - - Streamer.get_topic_and_add_socket("public", blocker) - - {:ok, _user_relationship} = User.block(blocker, blockee) - - {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"}) - - assert_receive {:render_with_user, _, _, ^activity_one} - assert Streamer.filtered_by_user?(blocker, activity_one) - - {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - - assert_receive {:render_with_user, _, _, ^activity_two} - assert Streamer.filtered_by_user?(blocker, activity_two) - - {:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"}) - - assert_receive {:render_with_user, _, _, ^activity_three} - assert Streamer.filtered_by_user?(blocker, activity_three) - end - end - - describe "lists" do - test "it doesn't send unwanted DMs to list" do - user_a = insert(:user) - user_b = insert(:user) - user_c = insert(:user) - - {:ok, user_a} = User.follow(user_a, user_b) - - {:ok, list} = List.create("Test", user_a) - {:ok, list} = List.follow(list, user_b) - - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) - - {:ok, _activity} = - CommonAPI.post(user_b, %{ - status: "@#{user_c.nickname} Test", - visibility: "direct" - }) - - refute_receive _ - end - - test "it doesn't send unwanted private posts to list" do - user_a = insert(:user) - user_b = insert(:user) - - {:ok, list} = List.create("Test", user_a) - {:ok, list} = List.follow(list, user_b) - - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) - - {:ok, _activity} = - CommonAPI.post(user_b, %{ - status: "Test", - visibility: "private" - }) - - refute_receive _ - end - - test "it sends wanted private posts to list" do - user_a = insert(:user) - user_b = insert(:user) - - {:ok, user_a} = User.follow(user_a, user_b) - - {:ok, list} = List.create("Test", user_a) - {:ok, list} = List.follow(list, user_b) - - Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id}) - - {:ok, activity} = - CommonAPI.post(user_b, %{ - status: "Test", - visibility: "private" - }) - - assert_receive {:render_with_user, _, _, ^activity} - refute Streamer.filtered_by_user?(user_a, activity) - end - end - - describe "muted reblogs" do - test "it filters muted reblogs" do - user1 = insert(:user) - user2 = insert(:user) - user3 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) - - {:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"}) - - Streamer.get_topic_and_add_socket("user", user1) - {:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2) - assert_receive {:render_with_user, _, _, ^announce_activity} - assert Streamer.filtered_by_user?(user1, announce_activity) - end - - test "it filters reblog notification for reblog-muted actors" do - user1 = insert(:user) - user2 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) - - {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) - Streamer.get_topic_and_add_socket("user", user1) - {:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2) - - assert_receive {:render_with_user, _, "notification.json", notif} - assert Streamer.filtered_by_user?(user1, notif) - end - - test "it send non-reblog notification for reblog-muted actors" do - user1 = insert(:user) - user2 = insert(:user) - CommonAPI.follow(user1, user2) - CommonAPI.hide_reblogs(user1, user2) - - {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) - Streamer.get_topic_and_add_socket("user", user1) - {:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id) - - assert_receive {:render_with_user, _, "notification.json", notif} - refute Streamer.filtered_by_user?(user1, notif) - end - end - - test "it filters posts from muted threads" do - user = insert(:user) - user2 = insert(:user) - Streamer.get_topic_and_add_socket("user", user2) - {:ok, user2, user, _activity} = CommonAPI.follow(user2, user) - {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) - {:ok, _} = CommonAPI.add_mute(user2, activity) - assert_receive {:render_with_user, _, _, ^activity} - assert Streamer.filtered_by_user?(user2, activity) - end - - describe "direct streams" do - setup do - :ok - end - - test "it sends conversation update to the 'direct' stream", %{} do - user = insert(:user) - another_user = insert(:user) - - Streamer.get_topic_and_add_socket("direct", user) - - {:ok, _create_activity} = - CommonAPI.post(another_user, %{ - status: "hey @#{user.nickname}", - visibility: "direct" - }) - - assert_receive {:text, received_event} - - assert %{"event" => "conversation", "payload" => received_payload} = - Jason.decode!(received_event) - - assert %{"last_status" => last_status} = Jason.decode!(received_payload) - [participation] = Participation.for_user(user) - assert last_status["pleroma"]["direct_conversation_id"] == participation.id - end - - test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted" do - user = insert(:user) - another_user = insert(:user) - - Streamer.get_topic_and_add_socket("direct", user) - - {:ok, create_activity} = - CommonAPI.post(another_user, %{ - status: "hi @#{user.nickname}", - visibility: "direct" - }) - - create_activity_id = create_activity.id - assert_receive {:render_with_user, _, _, ^create_activity} - assert_receive {:text, received_conversation1} - assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1) - - {:ok, _} = CommonAPI.delete(create_activity_id, another_user) - - assert_receive {:text, received_event} - - assert %{"event" => "delete", "payload" => ^create_activity_id} = - Jason.decode!(received_event) - - refute_receive _ - end - - test "it sends conversation update to the 'direct' stream when a message is deleted" do - user = insert(:user) - another_user = insert(:user) - Streamer.get_topic_and_add_socket("direct", 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} 2", - in_reply_to_status_id: create_activity.id, - visibility: "direct" - }) - - assert_receive {:render_with_user, _, _, ^create_activity} - assert_receive {:render_with_user, _, _, ^create_activity2} - assert_receive {:text, received_conversation1} - assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1) - assert_receive {:text, received_conversation1} - assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1) - - {:ok, _} = CommonAPI.delete(create_activity2.id, another_user) - - assert_receive {:text, received_event} - assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event) - - assert_receive {:text, received_event} - - 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 - end -end diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs deleted file mode 100644 index 231a46c67..000000000 --- a/test/web/twitter_api/password_controller_test.exs +++ /dev/null @@ -1,81 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 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.User - 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 Pbkdf2.verify_pass("test", user.password_hash) - assert Enum.empty?(Token.get_user_tokens(user)) - end - - test "it sets password_reset_pending to false", %{conn: conn} do - user = insert(:user, password_reset_pending: true) - - {: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 - } - - conn - |> assign(:user, user) - |> post("/api/pleroma/password_reset", %{data: params}) - |> html_response(:ok) - - assert User.get_by_id(user.id).password_reset_pending == false - end - end -end diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/web/twitter_api/remote_follow_controller_test.exs deleted file mode 100644 index f7e54c26a..000000000 --- a/test/web/twitter_api/remote_follow_controller_test.exs +++ /dev/null @@ -1,350 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Config - alias Pleroma.MFA - alias Pleroma.MFA.TOTP - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - import ExUnit.CaptureLog - import Pleroma.Factory - import Ecto.Query - - setup do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup_all do: clear_config([:instance, :federating], true) - setup do: clear_config([:instance]) - setup do: clear_config([:frontend_configurations, :pleroma_fe]) - setup do: clear_config([:user, :deny_follow_blocked]) - - describe "GET /ostatus_subscribe - remote_follow/2" do - test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do - assert conn - |> get( - remote_follow_path(conn, :follow, %{ - acct: "https://mastodon.social/users/emelie/statuses/101849165031453009" - }) - ) - |> redirected_to() =~ "/notice/" - end - - test "show follow account page if the `acct` is a account link", %{conn: conn} do - response = - conn - |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) - |> html_response(200) - - assert response =~ "Log in to follow" - end - - test "show follow page if the `acct` is a account link", %{conn: conn} do - user = insert(:user) - - response = - conn - |> assign(:user, user) - |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) - |> html_response(200) - - assert response =~ "Remote follow" - end - - test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do - user = insert(:user) - - assert capture_log(fn -> - response = - conn - |> assign(:user, user) - |> get( - remote_follow_path(conn, :follow, %{ - acct: "https://mastodon.social/users/not_found" - }) - ) - |> html_response(200) - - assert response =~ "Error fetching user" - end) =~ "Object has been deleted" - end - end - - describe "POST /ostatus_subscribe - do_follow/2 with assigned user " do - test "required `follow | write:follows` scope", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - read_token = insert(:oauth_token, user: user, scopes: ["read"]) - - assert capture_log(fn -> - response = - conn - |> assign(:user, user) - |> assign(:token, read_token) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - - assert response =~ "Error following account" - end) =~ "Insufficient permissions: follow | write:follows." - end - - test "follows user", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - - conn = - conn - |> assign(:user, user) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - - assert redirected_to(conn) == "/users/#{user2.id}" - end - - test "returns error when user is deactivated", %{conn: conn} do - user = insert(:user, deactivated: true) - user2 = insert(:user) - - response = - conn - |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - - assert response =~ "Error following account" - end - - test "returns error when user is blocked", %{conn: conn} do - Pleroma.Config.put([:user, :deny_follow_blocked], true) - user = insert(:user) - user2 = insert(:user) - - {:ok, _user_block} = Pleroma.User.block(user2, user) - - response = - conn - |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - - assert response =~ "Error following account" - end - - test "returns error when followee not found", %{conn: conn} do - user = insert(:user) - - response = - conn - |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}}) - |> response(200) - - assert response =~ "Error following account" - end - - test "returns success result when user already in followers", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - {:ok, _, _, _} = CommonAPI.follow(user, user2) - - conn = - conn - |> assign(:user, refresh_record(user)) - |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - - assert redirected_to(conn) == "/users/#{user2.id}" - end - end - - describe "POST /ostatus_subscribe - follow/2 with enabled Two-Factor Auth " do - test "render the MFA login form", %{conn: conn} do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - user2 = insert(:user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} - }) - |> response(200) - - mfa_token = Pleroma.Repo.one(from(q in Pleroma.MFA.Token, where: q.user_id == ^user.id)) - - assert response =~ "Two-factor authentication" - assert response =~ "Authentication code" - assert response =~ mfa_token.token - refute user2.follower_address in User.following(user) - end - - test "returns error when password is incorrect", %{conn: conn} do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - user2 = insert(:user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "test1", "id" => user2.id} - }) - |> response(200) - - assert response =~ "Wrong username or password" - refute user2.follower_address in User.following(user) - end - - test "follows", %{conn: conn} do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - {:ok, %{token: token}} = MFA.Token.create_token(user) - - user2 = insert(:user) - otp_token = TOTP.generate_token(otp_secret) - - conn = - conn - |> post( - remote_follow_path(conn, :do_follow), - %{ - "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} - } - ) - - assert redirected_to(conn) == "/users/#{user2.id}" - assert user2.follower_address in User.following(user) - end - - test "returns error when auth code is incorrect", %{conn: conn} do - otp_secret = TOTP.generate_secret() - - user = - insert(:user, - multi_factor_authentication_settings: %MFA.Settings{ - enabled: true, - totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true} - } - ) - - {:ok, %{token: token}} = MFA.Token.create_token(user) - - user2 = insert(:user) - otp_token = TOTP.generate_token(TOTP.generate_secret()) - - response = - conn - |> post( - remote_follow_path(conn, :do_follow), - %{ - "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} - } - ) - |> response(200) - - assert response =~ "Wrong authentication code" - refute user2.follower_address in User.following(user) - end - end - - describe "POST /ostatus_subscribe - follow/2 without assigned user " do - test "follows", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - - conn = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} - }) - - assert redirected_to(conn) == "/users/#{user2.id}" - assert user2.follower_address in User.following(user) - end - - test "returns error when followee not found", %{conn: conn} do - user = insert(:user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"} - }) - |> response(200) - - assert response =~ "Error following account" - end - - test "returns error when login invalid", %{conn: conn} do - user = insert(:user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id} - }) - |> response(200) - - assert response =~ "Wrong username or password" - end - - test "returns error when password invalid", %{conn: conn} do - user = insert(:user) - user2 = insert(:user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id} - }) - |> response(200) - - assert response =~ "Wrong username or password" - end - - test "returns error when user is blocked", %{conn: conn} do - Pleroma.Config.put([:user, :deny_follow_blocked], true) - user = insert(:user) - user2 = insert(:user) - {:ok, _user_block} = Pleroma.User.block(user2, user) - - response = - conn - |> post(remote_follow_path(conn, :do_follow), %{ - "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} - }) - |> response(200) - - assert response =~ "Error following account" - 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 deleted file mode 100644 index 464d0ea2e..000000000 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ /dev/null @@ -1,138 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.ControllerTest do - use Pleroma.Web.ConnCase - - alias Pleroma.Builders.ActivityBuilder - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.OAuth.Token - - import Pleroma.Factory - - describe "POST /api/qvitter/statuses/notifications/read" do - test "without valid credentials", %{conn: conn} do - conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567}) - assert json_response(conn, 403) == %{"error" => "Invalid credentials."} - end - - test "with credentials, without any params" do - %{conn: conn} = oauth_access(["write:notifications"]) - - conn = post(conn, "/api/qvitter/statuses/notifications/read") - - assert json_response(conn, 400) == %{ - "error" => "You need to specify latest_id", - "request" => "/api/qvitter/statuses/notifications/read" - } - end - - test "with credentials, with params" do - %{user: current_user, conn: conn} = - oauth_access(["read:notifications", "write:notifications"]) - - other_user = insert(:user) - - {:ok, _activity} = - ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user}) - - response_conn = - conn - |> assign(:user, current_user) - |> get("/api/v1/notifications") - - [notification] = response = json_response(response_conn, 200) - - assert length(response) == 1 - - assert notification["pleroma"]["is_seen"] == false - - response_conn = - conn - |> assign(:user, current_user) - |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]}) - - [notification] = response = json_response(response_conn, 200) - - assert length(response) == 1 - - assert notification["pleroma"]["is_seen"] == true - end - end - - describe "GET /api/account/confirm_email/:id/:token" do - setup do - {:ok, user} = - insert(:user) - |> User.confirmation_changeset(need_confirmation: true) - |> Repo.update() - - assert user.confirmation_pending - - [user: user] - end - - test "it redirects to root url", %{conn: conn, user: user} do - conn = get(conn, "/api/account/confirm_email/#{user.id}/#{user.confirmation_token}") - - assert 302 == conn.status - end - - test "it confirms the user account", %{conn: conn, user: user} do - get(conn, "/api/account/confirm_email/#{user.id}/#{user.confirmation_token}") - - user = User.get_cached_by_id(user.id) - - refute user.confirmation_pending - refute user.confirmation_token - end - - test "it returns 500 if user cannot be found by id", %{conn: conn, user: user} do - conn = get(conn, "/api/account/confirm_email/0/#{user.confirmation_token}") - - assert 500 == conn.status - end - - test "it returns 500 if token is invalid", %{conn: conn, user: user} do - conn = get(conn, "/api/account/confirm_email/#{user.id}/wrong_token") - - assert 500 == conn.status - end - end - - describe "GET /api/oauth_tokens" do - setup do - token = insert(:oauth_token) |> Repo.preload(:user) - - %{token: token} - end - - test "renders list", %{token: token} do - response = - build_conn() - |> assign(:user, token.user) - |> get("/api/oauth_tokens") - - keys = - json_response(response, 200) - |> hd() - |> Map.keys() - - assert keys -- ["id", "app_name", "valid_until"] == [] - end - - test "revoke token", %{token: token} do - response = - build_conn() - |> assign(:user, token.user) - |> delete("/api/oauth_tokens/#{token.id}") - - tokens = Token.get_user_tokens(token.user) - - assert tokens == [] - assert response.status == 201 - end - end -end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs deleted file mode 100644 index 5bb2d8d89..000000000 --- a/test/web/twitter_api/twitter_api_test.exs +++ /dev/null @@ -1,396 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do - use Pleroma.DataCase - - alias Pleroma.Repo - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - alias Pleroma.UserInviteToken - alias Pleroma.Web.TwitterAPI.TwitterAPI - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - test "it registers a new user and returns the user." do - data = %{ - :username => "lain", - :email => "lain@wired.jp", - :fullname => "lain iwakura", - :password => "bear", - :confirm => "bear" - } - - {:ok, user} = TwitterAPI.register_user(data) - - assert user == User.get_cached_by_nickname("lain") - end - - test "it registers a new user with empty string in bio and returns the user" do - data = %{ - :username => "lain", - :email => "lain@wired.jp", - :fullname => "lain iwakura", - :bio => "", - :password => "bear", - :confirm => "bear" - } - - {:ok, user} = TwitterAPI.register_user(data) - - assert user == User.get_cached_by_nickname("lain") - end - - test "it sends confirmation email if :account_activation_required is specified in instance config" do - setting = Pleroma.Config.get([:instance, :account_activation_required]) - - unless setting do - Pleroma.Config.put([:instance, :account_activation_required], true) - on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) - end - - data = %{ - :username => "lain", - :email => "lain@wired.jp", - :fullname => "lain iwakura", - :bio => "", - :password => "bear", - :confirm => "bear" - } - - {:ok, user} = TwitterAPI.register_user(data) - ObanHelpers.perform_all() - - assert user.confirmation_pending - - email = Pleroma.Emails.UserEmail.account_confirmation_email(user) - - notify_email = Pleroma.Config.get([:instance, :notify_email]) - instance_name = Pleroma.Config.get([:instance, :name]) - - Swoosh.TestAssertions.assert_email_sent( - from: {instance_name, notify_email}, - to: {user.name, user.email}, - html_body: email.html_body - ) - end - - test "it registers a new user and parses mentions in the bio" do - data1 = %{ - :username => "john", - :email => "john@gmail.com", - :fullname => "John Doe", - :bio => "test", - :password => "bear", - :confirm => "bear" - } - - {:ok, user1} = TwitterAPI.register_user(data1) - - data2 = %{ - :username => "lain", - :email => "lain@wired.jp", - :fullname => "lain iwakura", - :bio => "@john test", - :password => "bear", - :confirm => "bear" - } - - {:ok, user2} = TwitterAPI.register_user(data2) - - expected_text = - ~s(<span class="h-card"><a class="u-url mention" data-user="#{user1.id}" href="#{ - user1.ap_id - }" rel="ugc">@<span>john</span></a></span> test) - - assert user2.bio == expected_text - end - - describe "register with one time token" do - setup do: clear_config([:instance, :registrations_open], false) - - test "returns user on success" do - {:ok, invite} = UserInviteToken.create_invite() - - data = %{ - :username => "vinny", - :email => "pasta@pizza.vs", - :fullname => "Vinny Vinesauce", - :bio => "streamer", - :password => "hiptofbees", - :confirm => "hiptofbees", - :token => invite.token - } - - {:ok, user} = TwitterAPI.register_user(data) - - assert user == User.get_cached_by_nickname("vinny") - - invite = Repo.get_by(UserInviteToken, token: invite.token) - assert invite.used == true - end - - test "returns error on invalid token" do - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => "DudeLetMeInImAFairy" - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Invalid token" - refute User.get_cached_by_nickname("GrimReaper") - end - - test "returns error on expired token" do - {:ok, invite} = UserInviteToken.create_invite() - UserInviteToken.update_invite!(invite, used: true) - - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => invite.token - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("GrimReaper") - end - end - - describe "registers with date limited token" do - setup do: clear_config([:instance, :registrations_open], false) - - setup do - data = %{ - :username => "vinny", - :email => "pasta@pizza.vs", - :fullname => "Vinny Vinesauce", - :bio => "streamer", - :password => "hiptofbees", - :confirm => "hiptofbees" - } - - check_fn = fn invite -> - data = Map.put(data, :token, invite.token) - {:ok, user} = TwitterAPI.register_user(data) - - assert user == User.get_cached_by_nickname("vinny") - end - - {:ok, data: data, check_fn: check_fn} - end - - test "returns user on success", %{check_fn: check_fn} do - {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today()}) - - check_fn.(invite) - - invite = Repo.get_by(UserInviteToken, token: invite.token) - - refute invite.used - end - - test "returns user on token which expired tomorrow", %{check_fn: check_fn} do - {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), 1)}) - - check_fn.(invite) - - invite = Repo.get_by(UserInviteToken, token: invite.token) - - refute invite.used - end - - test "returns an error on overdue date", %{data: data} do - {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1)}) - - data = Map.put(data, "token", invite.token) - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("vinny") - invite = Repo.get_by(UserInviteToken, token: invite.token) - - refute invite.used - end - end - - describe "registers with reusable token" do - setup do: clear_config([:instance, :registrations_open], false) - - test "returns user on success, after him registration fails" do - {:ok, invite} = UserInviteToken.create_invite(%{max_use: 100}) - - UserInviteToken.update_invite!(invite, uses: 99) - - data = %{ - :username => "vinny", - :email => "pasta@pizza.vs", - :fullname => "Vinny Vinesauce", - :bio => "streamer", - :password => "hiptofbees", - :confirm => "hiptofbees", - :token => invite.token - } - - {:ok, user} = TwitterAPI.register_user(data) - assert user == User.get_cached_by_nickname("vinny") - - invite = Repo.get_by(UserInviteToken, token: invite.token) - assert invite.used == true - - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => invite.token - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("GrimReaper") - end - end - - describe "registers with reusable date limited token" do - setup do: clear_config([:instance, :registrations_open], false) - - test "returns user on success" do - {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) - - data = %{ - :username => "vinny", - :email => "pasta@pizza.vs", - :fullname => "Vinny Vinesauce", - :bio => "streamer", - :password => "hiptofbees", - :confirm => "hiptofbees", - :token => invite.token - } - - {:ok, user} = TwitterAPI.register_user(data) - assert user == User.get_cached_by_nickname("vinny") - - invite = Repo.get_by(UserInviteToken, token: invite.token) - refute invite.used - end - - test "error after max uses" do - {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) - - UserInviteToken.update_invite!(invite, uses: 99) - - data = %{ - :username => "vinny", - :email => "pasta@pizza.vs", - :fullname => "Vinny Vinesauce", - :bio => "streamer", - :password => "hiptofbees", - :confirm => "hiptofbees", - :token => invite.token - } - - {:ok, user} = TwitterAPI.register_user(data) - assert user == User.get_cached_by_nickname("vinny") - - invite = Repo.get_by(UserInviteToken, token: invite.token) - assert invite.used == true - - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => invite.token - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("GrimReaper") - end - - test "returns error on overdue date" do - {:ok, invite} = - UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) - - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => invite.token - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("GrimReaper") - end - - test "returns error on with overdue date and after max" do - {:ok, invite} = - UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) - - UserInviteToken.update_invite!(invite, uses: 100) - - data = %{ - :username => "GrimReaper", - :email => "death@reapers.afterlife", - :fullname => "Reaper Grim", - :bio => "Your time has come", - :password => "scythe", - :confirm => "scythe", - :token => invite.token - } - - {:error, msg} = TwitterAPI.register_user(data) - - assert msg == "Expired token" - refute User.get_cached_by_nickname("GrimReaper") - end - end - - test "it returns the error on registration problems" do - data = %{ - :username => "lain", - :email => "lain@wired.jp", - :fullname => "lain iwakura", - :bio => "close the world." - } - - {:error, error} = TwitterAPI.register_user(data) - - assert is_binary(error) - refute User.get_cached_by_nickname("lain") - end - - setup do - Supervisor.terminate_child(Pleroma.Supervisor, Cachex) - Supervisor.restart_child(Pleroma.Supervisor, Cachex) - :ok - end -end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs deleted file mode 100644 index 109c1e637..000000000 --- a/test/web/twitter_api/util_controller_test.exs +++ /dev/null @@ -1,595 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do - use Pleroma.Web.ConnCase - use Oban.Testing, repo: Pleroma.Repo - - alias Pleroma.Config - alias Pleroma.Tests.ObanHelpers - alias Pleroma.User - - import Pleroma.Factory - import Mock - - setup do - Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup do: clear_config([:instance]) - setup do: clear_config([:frontend_configurations, :pleroma_fe]) - - describe "POST /api/pleroma/follow_import" do - setup do: oauth_access(["follow"]) - - test "it returns HTTP 200", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"}) - |> json_response(:ok) - - assert response == "job started" - end - - test "it imports follow lists from file", %{user: user1, conn: conn} do - user2 = insert(:user) - - with_mocks([ - {File, [], - read!: fn "follow_list.txt" -> - "Account address,Show boosts\n#{user2.ap_id},true" - end} - ]) do - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}}) - |> json_response(:ok) - - assert response == "job started" - - assert ObanHelpers.member?( - %{ - "op" => "follow_import", - "follower_id" => user1.id, - "followed_identifiers" => [user2.ap_id] - }, - all_enqueued(worker: Pleroma.Workers.BackgroundWorker) - ) - end - end - - test "it imports new-style mastodon follow lists", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/follow_import", %{ - "list" => "Account address,Show boosts\n#{user2.ap_id},true" - }) - |> json_response(:ok) - - assert response == "job started" - end - - test "requires 'follow' or 'write:follows' permissions" do - token1 = insert(:oauth_token, scopes: ["read", "write"]) - token2 = insert(:oauth_token, scopes: ["follow"]) - token3 = insert(:oauth_token, scopes: ["something"]) - another_user = insert(:user) - - for token <- [token1, token2, token3] do - conn = - build_conn() - |> put_req_header("authorization", "Bearer #{token.token}") - |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) - - if token == token3 do - assert %{"error" => "Insufficient permissions: follow | write:follows."} == - json_response(conn, 403) - else - assert json_response(conn, 200) - end - end - end - - test "it imports follows with different nickname variations", %{conn: conn} do - [user2, user3, user4, user5, user6] = insert_list(5, :user) - - identifiers = - [ - user2.ap_id, - user3.nickname, - " ", - "@" <> user4.nickname, - user5.nickname <> "@localhost", - "@" <> user6.nickname <> "@localhost" - ] - |> Enum.join("\n") - - response = - conn - |> post("/api/pleroma/follow_import", %{"list" => identifiers}) - |> json_response(:ok) - - assert response == "job started" - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [user2, user3, user4, user5, user6] - end - end - - describe "POST /api/pleroma/blocks_import" do - # Note: "follow" or "write:blocks" permission is required - setup do: oauth_access(["write:blocks"]) - - test "it returns HTTP 200", %{conn: conn} do - user2 = insert(:user) - - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"}) - |> json_response(:ok) - - assert response == "job started" - end - - test "it imports blocks users from file", %{user: user1, conn: conn} do - user2 = insert(:user) - user3 = insert(:user) - - with_mocks([ - {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end} - ]) do - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}}) - |> json_response(:ok) - - assert response == "job started" - - assert ObanHelpers.member?( - %{ - "op" => "blocks_import", - "blocker_id" => user1.id, - "blocked_identifiers" => [user2.ap_id, user3.ap_id] - }, - all_enqueued(worker: Pleroma.Workers.BackgroundWorker) - ) - end - end - - test "it imports blocks with different nickname variations", %{conn: conn} do - [user2, user3, user4, user5, user6] = insert_list(5, :user) - - identifiers = - [ - user2.ap_id, - user3.nickname, - "@" <> user4.nickname, - user5.nickname <> "@localhost", - "@" <> user6.nickname <> "@localhost" - ] - |> Enum.join(" ") - - response = - conn - |> post("/api/pleroma/blocks_import", %{"list" => identifiers}) - |> json_response(:ok) - - assert response == "job started" - assert [{:ok, job_result}] = ObanHelpers.perform_all() - assert job_result == [user2, user3, user4, user5, user6] - end - end - - describe "PUT /api/pleroma/notification_settings" do - setup do: oauth_access(["write:accounts"]) - - test "it updates notification settings", %{user: user, conn: conn} do - conn - |> put("/api/pleroma/notification_settings", %{ - "block_from_strangers" => true, - "bar" => 1 - }) - |> json_response(:ok) - - user = refresh_record(user) - - assert %Pleroma.User.NotificationSetting{ - block_from_strangers: true, - hide_notification_contents: false - } == user.notification_settings - end - - test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do - conn - |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"}) - |> json_response(:ok) - - user = refresh_record(user) - - assert %Pleroma.User.NotificationSetting{ - block_from_strangers: false, - hide_notification_contents: true - } == user.notification_settings - end - end - - describe "GET /api/pleroma/frontend_configurations" do - test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} do - config = [ - frontend_a: %{ - x: 1, - y: 2 - }, - frontend_b: %{ - z: 3 - } - ] - - Config.put(:frontend_configurations, config) - - response = - conn - |> get("/api/pleroma/frontend_configurations") - |> json_response(:ok) - - assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!() - end - end - - describe "/api/pleroma/emoji" do - test "returns json with custom emoji with tags", %{conn: conn} do - emoji = - conn - |> get("/api/pleroma/emoji") - |> json_response(200) - - assert Enum.all?(emoji, fn - {_key, - %{ - "image_url" => url, - "tags" => tags - }} -> - is_binary(url) and is_list(tags) - end) - end - end - - describe "GET /api/pleroma/healthcheck" do - setup do: clear_config([:instance, :healthcheck]) - - test "returns 503 when healthcheck disabled", %{conn: conn} do - Config.put([:instance, :healthcheck], false) - - response = - conn - |> get("/api/pleroma/healthcheck") - |> json_response(503) - - assert response == %{} - end - - test "returns 200 when healthcheck enabled and all ok", %{conn: conn} do - Config.put([:instance, :healthcheck], true) - - with_mock Pleroma.Healthcheck, - system_info: fn -> %Pleroma.Healthcheck{healthy: true} end do - response = - conn - |> get("/api/pleroma/healthcheck") - |> json_response(200) - - assert %{ - "active" => _, - "healthy" => true, - "idle" => _, - "memory_used" => _, - "pool_size" => _ - } = response - end - end - - test "returns 503 when healthcheck enabled and health is false", %{conn: conn} do - Config.put([:instance, :healthcheck], true) - - with_mock Pleroma.Healthcheck, - system_info: fn -> %Pleroma.Healthcheck{healthy: false} end do - response = - conn - |> get("/api/pleroma/healthcheck") - |> json_response(503) - - assert %{ - "active" => _, - "healthy" => false, - "idle" => _, - "memory_used" => _, - "pool_size" => _ - } = response - end - end - end - - describe "POST /api/pleroma/disable_account" do - setup do: oauth_access(["write:accounts"]) - - test "with valid permissions and password, it disables the account", %{conn: conn, user: user} do - response = - conn - |> post("/api/pleroma/disable_account", %{"password" => "test"}) - |> json_response(:ok) - - assert response == %{"status" => "success"} - ObanHelpers.perform_all() - - user = User.get_cached_by_id(user.id) - - assert user.deactivated == true - end - - test "with valid permissions and invalid password, it returns an error", %{conn: conn} do - user = insert(:user) - - response = - conn - |> post("/api/pleroma/disable_account", %{"password" => "test1"}) - |> json_response(:ok) - - assert response == %{"error" => "Invalid password."} - user = User.get_cached_by_id(user.id) - - refute user.deactivated - end - end - - describe "POST /main/ostatus - remote_subscribe/2" do - setup do: clear_config([:instance, :federating], true) - - test "renders subscribe form", %{conn: conn} do - user = insert(:user) - - response = - conn - |> post("/main/ostatus", %{"nickname" => user.nickname, "profile" => ""}) - |> response(:ok) - - refute response =~ "Could not find user" - assert response =~ "Remotely follow #{user.nickname}" - end - - test "renders subscribe form with error when user not found", %{conn: conn} do - response = - conn - |> post("/main/ostatus", %{"nickname" => "nickname", "profile" => ""}) - |> response(:ok) - - assert response =~ "Could not find user" - refute response =~ "Remotely follow" - end - - test "it redirect to webfinger url", %{conn: conn} do - user = insert(:user) - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - conn = - conn - |> post("/main/ostatus", %{ - "user" => %{"nickname" => user.nickname, "profile" => user2.ap_id} - }) - - assert redirected_to(conn) == - "https://social.heldscal.la/main/ostatussub?profile=#{user.ap_id}" - end - - test "it renders form with error when user not found", %{conn: conn} do - user2 = insert(:user, ap_id: "shp@social.heldscal.la") - - response = - conn - |> post("/main/ostatus", %{"user" => %{"nickname" => "jimm", "profile" => user2.ap_id}}) - |> response(:ok) - - assert response =~ "Something went wrong." - end - end - - test "it returns new captcha", %{conn: conn} do - with_mock Pleroma.Captcha, - new: fn -> "test_captcha" end do - resp = - conn - |> get("/api/pleroma/captcha") - |> response(200) - - assert resp == "\"test_captcha\"" - assert called(Pleroma.Captcha.new()) - end - end - - describe "POST /api/pleroma/change_email" do - setup do: oauth_access(["write:accounts"]) - - test "without permissions", %{conn: conn} do - conn = - conn - |> assign(:token, nil) - |> post("/api/pleroma/change_email") - - assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."} - end - - test "with proper permissions and invalid password", %{conn: conn} do - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "hi", - "email" => "test@test.com" - }) - - assert json_response(conn, 200) == %{"error" => "Invalid password."} - end - - test "with proper permissions, valid password and invalid email", %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "foobar" - }) - - assert json_response(conn, 200) == %{"error" => "Email has invalid format."} - end - - test "with proper permissions, valid password and no email", %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test" - }) - - assert json_response(conn, 200) == %{"error" => "Email can't be blank."} - end - - test "with proper permissions, valid password and blank email", %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "" - }) - - assert json_response(conn, 200) == %{"error" => "Email can't be blank."} - end - - test "with proper permissions, valid password and non unique email", %{ - conn: conn - } do - user = insert(:user) - - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => user.email - }) - - assert json_response(conn, 200) == %{"error" => "Email has already been taken."} - end - - test "with proper permissions, valid password and valid email", %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_email", %{ - "password" => "test", - "email" => "cofe@foobar.com" - }) - - assert json_response(conn, 200) == %{"status" => "success"} - end - end - - describe "POST /api/pleroma/change_password" do - setup do: oauth_access(["write:accounts"]) - - test "without permissions", %{conn: conn} do - conn = - conn - |> assign(:token, nil) - |> post("/api/pleroma/change_password") - - assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."} - end - - test "with proper permissions and invalid password", %{conn: conn} do - conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "hi", - "new_password" => "newpass", - "new_password_confirmation" => "newpass" - }) - - assert json_response(conn, 200) == %{"error" => "Invalid password."} - end - - test "with proper permissions, valid password and new password and confirmation not matching", - %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "test", - "new_password" => "newpass", - "new_password_confirmation" => "notnewpass" - }) - - assert json_response(conn, 200) == %{ - "error" => "New password does not match confirmation." - } - end - - test "with proper permissions, valid password and invalid new password", %{ - conn: conn - } do - conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "test", - "new_password" => "", - "new_password_confirmation" => "" - }) - - assert json_response(conn, 200) == %{ - "error" => "New password can't be blank." - } - end - - test "with proper permissions, valid password and matching new password and confirmation", %{ - conn: conn, - user: user - } do - conn = - post(conn, "/api/pleroma/change_password", %{ - "password" => "test", - "new_password" => "newpass", - "new_password_confirmation" => "newpass" - }) - - assert json_response(conn, 200) == %{"status" => "success"} - fetched_user = User.get_cached_by_id(user.id) - assert Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true - end - end - - describe "POST /api/pleroma/delete_account" do - setup do: oauth_access(["write:accounts"]) - - test "without permissions", %{conn: conn} do - conn = - conn - |> assign(:token, nil) - |> post("/api/pleroma/delete_account") - - assert json_response(conn, 403) == - %{"error" => "Insufficient permissions: write:accounts."} - end - - test "with proper permissions and wrong or missing password", %{conn: conn} do - for params <- [%{"password" => "hi"}, %{}] do - ret_conn = post(conn, "/api/pleroma/delete_account", params) - - assert json_response(ret_conn, 200) == %{"error" => "Invalid password."} - end - end - - test "with proper permissions and valid password", %{conn: conn} do - conn = post(conn, "/api/pleroma/delete_account", %{"password" => "test"}) - - assert json_response(conn, 200) == %{"status" => "success"} - end - end -end diff --git a/test/web/uploader_controller_test.exs b/test/web/uploader_controller_test.exs deleted file mode 100644 index 21e518236..000000000 --- a/test/web/uploader_controller_test.exs +++ /dev/null @@ -1,43 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.UploaderControllerTest do - use Pleroma.Web.ConnCase - alias Pleroma.Uploaders.Uploader - - describe "callback/2" do - test "it returns 400 response when process callback isn't alive", %{conn: conn} do - res = - conn - |> post(uploader_path(conn, :callback, "test-path")) - - assert res.status == 400 - assert res.resp_body == "{\"error\":\"bad request\"}" - end - - test "it returns success result", %{conn: conn} do - task = - Task.async(fn -> - receive do - {Uploader, pid, conn, _params} -> - conn = - conn - |> put_status(:ok) - |> Phoenix.Controller.json(%{upload_path: "test-path"}) - - send(pid, {Uploader, conn}) - end - end) - - :global.register_name({Uploader, "test-path"}, task.pid) - - res = - conn - |> post(uploader_path(conn, :callback, "test-path")) - |> json_response(200) - - assert res == %{"upload_path" => "test-path"} - end - end -end diff --git a/test/web/views/error_view_test.exs b/test/web/views/error_view_test.exs deleted file mode 100644 index 8dbbd18b4..000000000 --- a/test/web/views/error_view_test.exs +++ /dev/null @@ -1,36 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ErrorViewTest do - use Pleroma.Web.ConnCase, async: true - import ExUnit.CaptureLog - - # Bring render/3 and render_to_string/3 for testing custom views - import Phoenix.View - - test "renders 404.json" do - assert render(Pleroma.Web.ErrorView, "404.json", []) == %{errors: %{detail: "Page not found"}} - end - - test "render 500.json" do - assert capture_log(fn -> - assert render(Pleroma.Web.ErrorView, "500.json", []) == - %{errors: %{detail: "Internal server error", reason: "nil"}} - end) =~ "[error] Internal server error: nil" - end - - test "render any other" do - assert capture_log(fn -> - assert render(Pleroma.Web.ErrorView, "505.json", []) == - %{errors: %{detail: "Internal server error", reason: "nil"}} - end) =~ "[error] Internal server error: nil" - end - - test "render 500.json with reason" do - assert capture_log(fn -> - assert render(Pleroma.Web.ErrorView, "500.json", reason: "test reason") == - %{errors: %{detail: "Internal server error", reason: "\"test reason\""}} - end) =~ "[error] Internal server error: \"test reason\"" - end -end diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs deleted file mode 100644 index 0023f1e81..000000000 --- a/test/web/web_finger/web_finger_controller_test.exs +++ /dev/null @@ -1,94 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do - use Pleroma.Web.ConnCase - - import ExUnit.CaptureLog - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - setup_all do: clear_config([:instance, :federating], true) - - test "GET host-meta" do - response = - build_conn() - |> get("/.well-known/host-meta") - - assert response.status == 200 - - assert response.resp_body == - ~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{ - Pleroma.Web.base_url() - }/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>) - end - - test "Webfinger JRD" do - user = insert(:user) - - response = - build_conn() - |> put_req_header("accept", "application/jrd+json") - |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") - - assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost" - end - - test "it returns 404 when user isn't found (JSON)" do - result = - build_conn() - |> put_req_header("accept", "application/jrd+json") - |> get("/.well-known/webfinger?resource=acct:jimm@localhost") - |> json_response(404) - - assert result == "Couldn't find user" - end - - test "Webfinger XML" do - user = insert(:user) - - response = - build_conn() - |> put_req_header("accept", "application/xrd+xml") - |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") - - assert response(response, 200) - end - - test "it returns 404 when user isn't found (XML)" do - result = - build_conn() - |> put_req_header("accept", "application/xrd+xml") - |> get("/.well-known/webfinger?resource=acct:jimm@localhost") - |> response(404) - - assert result == "Couldn't find user" - end - - test "Sends a 404 when invalid format" do - user = insert(:user) - - assert capture_log(fn -> - assert_raise Phoenix.NotAcceptableError, fn -> - build_conn() - |> put_req_header("accept", "text/html") - |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") - end - end) =~ "no supported media type in accept header" - end - - test "Sends a 400 when resource param is missing" do - response = - build_conn() - |> put_req_header("accept", "application/xrd+xml,application/jrd+json") - |> get("/.well-known/webfinger") - - assert response(response, 400) - end -end diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs deleted file mode 100644 index f4884e0a2..000000000 --- a/test/web/web_finger/web_finger_test.exs +++ /dev/null @@ -1,111 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.WebFingerTest do - use Pleroma.DataCase - alias Pleroma.Web.WebFinger - import Pleroma.Factory - import Tesla.Mock - - setup do - mock(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - describe "host meta" do - test "returns a link to the xml lrdd" do - host_info = WebFinger.host_meta() - - assert String.contains?(host_info, Pleroma.Web.base_url()) - end - end - - describe "incoming webfinger request" do - test "works for fqns" do - user = insert(:user) - - {:ok, result} = - WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "XML") - - assert is_binary(result) - end - - test "works for ap_ids" do - user = insert(:user) - - {:ok, result} = WebFinger.webfinger(user.ap_id, "XML") - assert is_binary(result) - end - end - - describe "fingering" do - test "returns error when fails parse xml or json" do - user = "invalid_content@social.heldscal.la" - assert {:error, %Jason.DecodeError{}} = WebFinger.finger(user) - end - - test "returns the ActivityPub actor URI for an ActivityPub user" do - user = "framasoft@framatube.org" - - {:ok, _data} = WebFinger.finger(user) - end - - test "returns the ActivityPub actor URI for an ActivityPub user with the ld+json mimetype" do - user = "kaniini@gerzilla.de" - - {:ok, data} = WebFinger.finger(user) - - assert data["ap_id"] == "https://gerzilla.de/channel/kaniini" - end - - test "it work for AP-only user" do - user = "kpherox@mstdn.jp" - - {:ok, data} = WebFinger.finger(user) - - assert data["magic_key"] == nil - assert data["salmon"] == nil - - assert data["topic"] == nil - assert data["subject"] == "acct:kPherox@mstdn.jp" - assert data["ap_id"] == "https://mstdn.jp/users/kPherox" - assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}" - end - - test "it works for friendica" do - user = "lain@squeet.me" - - {:ok, _data} = WebFinger.finger(user) - end - - test "it gets the xrd endpoint" do - {:ok, template} = WebFinger.find_lrdd_template("social.heldscal.la") - - assert template == "https://social.heldscal.la/.well-known/webfinger?resource={uri}" - end - - test "it gets the xrd endpoint for hubzilla" do - {:ok, template} = WebFinger.find_lrdd_template("macgirvin.com") - - assert template == "https://macgirvin.com/xrd/?uri={uri}" - end - - test "it gets the xrd endpoint for statusnet" do - {:ok, template} = WebFinger.find_lrdd_template("status.alpicola.com") - - 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 |