From 5f2071c458b19311b035bf18c136e069023b7f5b Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 19 Sep 2020 21:25:01 +0300 Subject: changes after rebase --- .../web/admin_api/controllers/chat_controller.ex | 2 +- .../controllers/instance_document_controller.ex | 4 +- lib/pleroma/web/fed_sockets.ex | 185 +++++++++++++++++ lib/pleroma/web/fed_sockets/fed_sockets.ex | 185 ----------------- .../article_note_validator_test.exs | 35 ++++ .../transmogrifier/article_handling_test.exs | 75 +++++++ .../transmogrifier/video_handling_test.exs | 93 +++++++++ .../admin_api/controllers/chat_controller_test.exs | 219 +++++++++++++++++++++ .../instance_document_controller_test.exs | 106 ++++++++++ test/pleroma/web/fed_sockets/fed_registry_test.exs | 124 ++++++++++++ .../web/fed_sockets/fetch_registry_test.exs | 67 +++++++ test/pleroma/web/fed_sockets/socket_info_test.exs | 118 +++++++++++ .../article_note_validator_test.exs | 35 ---- .../transmogrifier/article_handling_test.exs | 75 ------- .../transmogrifier/video_handling_test.exs | 93 --------- .../admin_api/controllers/chat_controller_test.exs | 219 --------------------- .../instance_document_controller_test.exs | 106 ---------- test/web/fed_sockets/fed_registry_test.exs | 124 ------------ test/web/fed_sockets/fetch_registry_test.exs | 67 ------- test/web/fed_sockets/socket_info_test.exs | 118 ----------- 20 files changed, 1025 insertions(+), 1025 deletions(-) create mode 100644 lib/pleroma/web/fed_sockets.ex delete mode 100644 lib/pleroma/web/fed_sockets/fed_sockets.ex create mode 100644 test/pleroma/web/activity_pub/object_validators/article_note_validator_test.exs create mode 100644 test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs create mode 100644 test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs create mode 100644 test/pleroma/web/admin_api/controllers/chat_controller_test.exs create mode 100644 test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs create mode 100644 test/pleroma/web/fed_sockets/fed_registry_test.exs create mode 100644 test/pleroma/web/fed_sockets/fetch_registry_test.exs create mode 100644 test/pleroma/web/fed_sockets/socket_info_test.exs delete mode 100644 test/web/activity_pub/object_validators/article_note_validator_test.exs delete mode 100644 test/web/activity_pub/transmogrifier/article_handling_test.exs delete mode 100644 test/web/activity_pub/transmogrifier/video_handling_test.exs delete mode 100644 test/web/admin_api/controllers/chat_controller_test.exs delete mode 100644 test/web/admin_api/controllers/instance_document_controller_test.exs delete mode 100644 test/web/fed_sockets/fed_registry_test.exs delete mode 100644 test/web/fed_sockets/fetch_registry_test.exs delete mode 100644 test/web/fed_sockets/socket_info_test.exs diff --git a/lib/pleroma/web/admin_api/controllers/chat_controller.ex b/lib/pleroma/web/admin_api/controllers/chat_controller.ex index 967600d69..af8ff8292 100644 --- a/lib/pleroma/web/admin_api/controllers/chat_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/chat_controller.ex @@ -10,10 +10,10 @@ defmodule Pleroma.Web.AdminAPI.ChatController do alias Pleroma.Chat.MessageReference alias Pleroma.ModerationLog alias Pleroma.Pagination - alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Web.AdminAPI alias Pleroma.Web.CommonAPI alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView + alias Pleroma.Web.Plugs.OAuthScopesPlug require Logger diff --git a/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex b/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex index 504d9b517..37dbfeb72 100644 --- a/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex @@ -5,9 +5,9 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do use Pleroma.Web, :controller - alias Pleroma.Plugs.InstanceStatic - alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Web.InstanceDocument + alias Pleroma.Web.Plugs.InstanceStatic + alias Pleroma.Web.Plugs.OAuthScopesPlug plug(Pleroma.Web.ApiSpec.CastAndValidate) diff --git a/lib/pleroma/web/fed_sockets.ex b/lib/pleroma/web/fed_sockets.ex new file mode 100644 index 000000000..1fd5899c8 --- /dev/null +++ b/lib/pleroma/web/fed_sockets.ex @@ -0,0 +1,185 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.FedSockets do + @moduledoc """ + This documents the FedSockets framework. A framework for federating + ActivityPub objects between servers via persistant WebSocket connections. + + FedSockets allow servers to authenticate on first contact and maintain that + connection, eliminating the need to authenticate every time data needs to be shared. + + ## Protocol + FedSockets currently support 2 types of data transfer: + * `publish` method which doesn't require a response + * `fetch` method requires a response be sent + + ### Publish + The publish operation sends a json encoded map of the shape: + %{action: :publish, data: json} + and accepts (but does not require) a reply of form: + %{"action" => "publish_reply"} + + The outgoing params represent + * data: ActivityPub object encoded into json + + + ### Fetch + The fetch operation sends a json encoded map of the shape: + %{action: :fetch, data: id, uuid: fetch_uuid} + and requires a reply of form: + %{"action" => "fetch_reply", "uuid" => uuid, "data" => data} + + The outgoing params represent + * id: an ActivityPub object URI + * uuid: a unique uuid generated by the sender + + The reply params represent + * data: an ActivityPub object encoded into json + * uuid: the uuid sent along with the fetch request + + ## Examples + Clients of FedSocket transfers shouldn't need to use any of the functions outside of this module. + + A typical publish operation can be performed through the following code, and a fetch operation in a similar manner. + + case FedSockets.get_or_create_fed_socket(inbox) do + {:ok, fedsocket} -> + FedSockets.publish(fedsocket, json) + + _ -> + alternative_publish(inbox, actor, json, params) + end + + ## Configuration + FedSockets have the following config settings + + config :pleroma, :fed_sockets, + enabled: true, + ping_interval: :timer.seconds(15), + connection_duration: :timer.hours(1), + rejection_duration: :timer.hours(1), + fed_socket_fetches: [ + default: 12_000, + interval: 3_000, + lazy: false + ] + * enabled - turn FedSockets on or off with this flag. Can be toggled at runtime. + * connection_duration - How long a FedSocket can sit idle before it's culled. + * rejection_duration - After failing to make a FedSocket connection a host will be excluded + from further connections for this amount of time + * fed_socket_fetches - Use these parameters to pass options to the Cachex queue backing the FetchRegistry + * fed_socket_rejections - Use these parameters to pass options to the Cachex queue backing the FedRegistry + + Cachex options are + * default: the minimum amount of time a fetch can wait before it times out. + * interval: the interval between checks for timed out entries. This plus the default represent the maximum time allowed + * lazy: leave at false for consistant and fast lookups, set to true for stricter timeout enforcement + + """ + require Logger + + alias Pleroma.Web.FedSockets.FedRegistry + alias Pleroma.Web.FedSockets.FedSocket + alias Pleroma.Web.FedSockets.SocketInfo + + @doc """ + returns a FedSocket for the given origin. Will reuse an existing one or create a new one. + + address is expected to be a fully formed URL such as: + "http://www.example.com" or "http://www.example.com:8080" + + It can and usually does include additional path parameters, + but these are ignored as the FedSockets are organized by host and port info alone. + """ + def get_or_create_fed_socket(address) do + with {:cache, {:error, :missing}} <- {:cache, get_fed_socket(address)}, + {:connect, {:ok, _pid}} <- {:connect, FedSocket.connect_to_host(address)}, + {:cache, {:ok, fed_socket}} <- {:cache, get_fed_socket(address)} do + Logger.debug("fedsocket created for - #{inspect(address)}") + {:ok, fed_socket} + else + {:cache, {:ok, socket}} -> + Logger.debug("fedsocket found in cache - #{inspect(address)}") + {:ok, socket} + + {:cache, {:error, :rejected} = e} -> + e + + {:connect, {:error, _host}} -> + Logger.debug("set host rejected for - #{inspect(address)}") + FedRegistry.set_host_rejected(address) + {:error, :rejected} + + {_, {:error, :disabled}} -> + {:error, :disabled} + + {_, {:error, reason}} -> + Logger.warn("get_or_create_fed_socket error - #{inspect(reason)}") + {:error, reason} + end + end + + @doc """ + returns a FedSocket for the given origin. Will not create a new FedSocket if one does not exist. + + address is expected to be a fully formed URL such as: + "http://www.example.com" or "http://www.example.com:8080" + """ + def get_fed_socket(address) do + origin = SocketInfo.origin(address) + + with {:config, true} <- {:config, Pleroma.Config.get([:fed_sockets, :enabled], false)}, + {:ok, socket} <- FedRegistry.get_fed_socket(origin) do + {:ok, socket} + else + {:config, _} -> + {:error, :disabled} + + {:error, :rejected} -> + Logger.debug("FedSocket previously rejected - #{inspect(origin)}") + {:error, :rejected} + + {:error, reason} -> + {:error, reason} + end + end + + @doc """ + Sends the supplied data via the publish protocol. + It will not block waiting for a reply. + Returns :ok but this is not an indication of a successful transfer. + + the data is expected to be JSON encoded binary data. + """ + def publish(%SocketInfo{} = fed_socket, json) do + FedSocket.publish(fed_socket, json) + end + + @doc """ + Sends the supplied data via the fetch protocol. + It will block waiting for a reply or timeout. + + Returns {:ok, object} where object is the requested object (or nil) + {:error, :timeout} in the event the message was not responded to + + the id is expected to be the URI of an ActivityPub object. + """ + def fetch(%SocketInfo{} = fed_socket, id) do + FedSocket.fetch(fed_socket, id) + end + + @doc """ + Disconnect all and restart FedSockets. + This is mainly used in development and testing but could be useful in production. + """ + def reset do + FedRegistry + |> Process.whereis() + |> Process.exit(:testing) + end + + def uri_for_origin(origin), + do: "ws://#{origin}/api/fedsocket/v1" +end diff --git a/lib/pleroma/web/fed_sockets/fed_sockets.ex b/lib/pleroma/web/fed_sockets/fed_sockets.ex deleted file mode 100644 index 1fd5899c8..000000000 --- a/lib/pleroma/web/fed_sockets/fed_sockets.ex +++ /dev/null @@ -1,185 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FedSockets do - @moduledoc """ - This documents the FedSockets framework. A framework for federating - ActivityPub objects between servers via persistant WebSocket connections. - - FedSockets allow servers to authenticate on first contact and maintain that - connection, eliminating the need to authenticate every time data needs to be shared. - - ## Protocol - FedSockets currently support 2 types of data transfer: - * `publish` method which doesn't require a response - * `fetch` method requires a response be sent - - ### Publish - The publish operation sends a json encoded map of the shape: - %{action: :publish, data: json} - and accepts (but does not require) a reply of form: - %{"action" => "publish_reply"} - - The outgoing params represent - * data: ActivityPub object encoded into json - - - ### Fetch - The fetch operation sends a json encoded map of the shape: - %{action: :fetch, data: id, uuid: fetch_uuid} - and requires a reply of form: - %{"action" => "fetch_reply", "uuid" => uuid, "data" => data} - - The outgoing params represent - * id: an ActivityPub object URI - * uuid: a unique uuid generated by the sender - - The reply params represent - * data: an ActivityPub object encoded into json - * uuid: the uuid sent along with the fetch request - - ## Examples - Clients of FedSocket transfers shouldn't need to use any of the functions outside of this module. - - A typical publish operation can be performed through the following code, and a fetch operation in a similar manner. - - case FedSockets.get_or_create_fed_socket(inbox) do - {:ok, fedsocket} -> - FedSockets.publish(fedsocket, json) - - _ -> - alternative_publish(inbox, actor, json, params) - end - - ## Configuration - FedSockets have the following config settings - - config :pleroma, :fed_sockets, - enabled: true, - ping_interval: :timer.seconds(15), - connection_duration: :timer.hours(1), - rejection_duration: :timer.hours(1), - fed_socket_fetches: [ - default: 12_000, - interval: 3_000, - lazy: false - ] - * enabled - turn FedSockets on or off with this flag. Can be toggled at runtime. - * connection_duration - How long a FedSocket can sit idle before it's culled. - * rejection_duration - After failing to make a FedSocket connection a host will be excluded - from further connections for this amount of time - * fed_socket_fetches - Use these parameters to pass options to the Cachex queue backing the FetchRegistry - * fed_socket_rejections - Use these parameters to pass options to the Cachex queue backing the FedRegistry - - Cachex options are - * default: the minimum amount of time a fetch can wait before it times out. - * interval: the interval between checks for timed out entries. This plus the default represent the maximum time allowed - * lazy: leave at false for consistant and fast lookups, set to true for stricter timeout enforcement - - """ - require Logger - - alias Pleroma.Web.FedSockets.FedRegistry - alias Pleroma.Web.FedSockets.FedSocket - alias Pleroma.Web.FedSockets.SocketInfo - - @doc """ - returns a FedSocket for the given origin. Will reuse an existing one or create a new one. - - address is expected to be a fully formed URL such as: - "http://www.example.com" or "http://www.example.com:8080" - - It can and usually does include additional path parameters, - but these are ignored as the FedSockets are organized by host and port info alone. - """ - def get_or_create_fed_socket(address) do - with {:cache, {:error, :missing}} <- {:cache, get_fed_socket(address)}, - {:connect, {:ok, _pid}} <- {:connect, FedSocket.connect_to_host(address)}, - {:cache, {:ok, fed_socket}} <- {:cache, get_fed_socket(address)} do - Logger.debug("fedsocket created for - #{inspect(address)}") - {:ok, fed_socket} - else - {:cache, {:ok, socket}} -> - Logger.debug("fedsocket found in cache - #{inspect(address)}") - {:ok, socket} - - {:cache, {:error, :rejected} = e} -> - e - - {:connect, {:error, _host}} -> - Logger.debug("set host rejected for - #{inspect(address)}") - FedRegistry.set_host_rejected(address) - {:error, :rejected} - - {_, {:error, :disabled}} -> - {:error, :disabled} - - {_, {:error, reason}} -> - Logger.warn("get_or_create_fed_socket error - #{inspect(reason)}") - {:error, reason} - end - end - - @doc """ - returns a FedSocket for the given origin. Will not create a new FedSocket if one does not exist. - - address is expected to be a fully formed URL such as: - "http://www.example.com" or "http://www.example.com:8080" - """ - def get_fed_socket(address) do - origin = SocketInfo.origin(address) - - with {:config, true} <- {:config, Pleroma.Config.get([:fed_sockets, :enabled], false)}, - {:ok, socket} <- FedRegistry.get_fed_socket(origin) do - {:ok, socket} - else - {:config, _} -> - {:error, :disabled} - - {:error, :rejected} -> - Logger.debug("FedSocket previously rejected - #{inspect(origin)}") - {:error, :rejected} - - {:error, reason} -> - {:error, reason} - end - end - - @doc """ - Sends the supplied data via the publish protocol. - It will not block waiting for a reply. - Returns :ok but this is not an indication of a successful transfer. - - the data is expected to be JSON encoded binary data. - """ - def publish(%SocketInfo{} = fed_socket, json) do - FedSocket.publish(fed_socket, json) - end - - @doc """ - Sends the supplied data via the fetch protocol. - It will block waiting for a reply or timeout. - - Returns {:ok, object} where object is the requested object (or nil) - {:error, :timeout} in the event the message was not responded to - - the id is expected to be the URI of an ActivityPub object. - """ - def fetch(%SocketInfo{} = fed_socket, id) do - FedSocket.fetch(fed_socket, id) - end - - @doc """ - Disconnect all and restart FedSockets. - This is mainly used in development and testing but could be useful in production. - """ - def reset do - FedRegistry - |> Process.whereis() - |> Process.exit(:testing) - end - - def uri_for_origin(origin), - do: "ws://#{origin}/api/fedsocket/v1" -end diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_validator_test.exs new file mode 100644 index 000000000..cc6dab872 --- /dev/null +++ b/test/pleroma/web/activity_pub/object_validators/article_note_validator_test.exs @@ -0,0 +1,35 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidatorTest do + use Pleroma.DataCase + + alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator + 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} = ArticleNoteValidator.cast_and_validate(note) + end + end +end diff --git a/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs new file mode 100644 index 000000000..9b12a470a --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs @@ -0,0 +1,75 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Object.Fetcher + alias Pleroma.Web.ActivityPub.Transmogrifier + + test "Pterotype (Wordpress Plugin) Article" do + Tesla.Mock.mock(fn %{url: "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json")} + end) + + data = + File.read!("test/fixtures/tesla_mock/wedistribute-create-article.json") |> Jason.decode!() + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + object = Object.normalize(data["object"]) + + assert object.data["name"] == "The end is near: Mastodon plans to drop OStatus support" + + assert object.data["summary"] == + "One of the largest platforms in the federated social web is dropping the protocol that it started with." + + assert object.data["url"] == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" + end + + test "Plume Article" do + Tesla.Mock.mock(fn + %{url: "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json") + } + + %{url: "https://baptiste.gelez.xyz/@/BaptisteGelez"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json") + } + end) + + {:ok, object} = + Fetcher.fetch_object_from_id( + "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" + ) + + assert object.data["name"] == "This Month in Plume: June 2018" + + assert object.data["url"] == + "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" + end + + test "Prismo Article" do + Tesla.Mock.mock(fn %{url: "https://prismo.news/@mxb"} -> + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json") + } + end) + + data = File.read!("test/fixtures/prismo-url-map.json") |> Jason.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 +end diff --git a/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs new file mode 100644 index 000000000..69c953a2e --- /dev/null +++ b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs @@ -0,0 +1,93 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do + use Oban.Testing, repo: Pleroma.Repo + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Object.Fetcher + alias Pleroma.Web.ActivityPub.Transmogrifier + + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + test "skip converting the content when it is nil" do + data = + File.read!("test/fixtures/tesla_mock/framatube.org-video.json") + |> Jason.decode!() + |> Kernel.put_in(["object", "content"], nil) + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, false) + + assert object.data["content"] == nil + end + + test "it converts content of object to html" do + data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, false) + + assert object.data["content"] == + "

Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?

Transcription par @aprilorg ici : https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft

" + 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", + "name" => nil, + "url" => [ + %{ + "href" => + "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + + data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() + + {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + + assert object = Object.normalize(activity, false) + + assert object.data["attachment"] == [ + %{ + "type" => "Link", + "mediaType" => "video/mp4", + "name" => nil, + "url" => [ + %{ + "href" => + "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ] + + assert object.data["url"] == + "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" + end +end diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs new file mode 100644 index 000000000..bd4c9c9d1 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -0,0 +1,219 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.ChatControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + + alias Pleroma.Chat + alias Pleroma.Chat.MessageReference + alias Pleroma.Config + alias Pleroma.ModerationLog + alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.Web.CommonAPI + + defp admin_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 "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do + setup do: admin_setup() + + test "it deletes a message from the chat", %{conn: conn, admin: admin} do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = + CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend") + + object = Object.normalize(message, false) + + chat = Chat.get(user.id, recipient.ap_id) + recipient_chat = Chat.get(recipient.id, user.ap_id) + + cm_ref = MessageReference.for_chat_and_object(chat, object) + recipient_cm_ref = MessageReference.for_chat_and_object(recipient_chat, object) + + result = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response_and_validate_schema(200) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deleted chat message ##{cm_ref.id}" + + assert result["id"] == cm_ref.id + refute MessageReference.get_by_id(cm_ref.id) + refute MessageReference.get_by_id(recipient_cm_ref.id) + assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) + end + end + + describe "GET /api/pleroma/admin/chats/:id/messages" do + setup do: admin_setup() + + test "it paginates", %{conn: conn} do + user = insert(:user) + 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/pleroma/admin/chats/#{chat.id}/messages") + |> json_response_and_validate_schema(200) + + assert length(result) == 20 + + result = + conn + |> get("/api/pleroma/admin/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} do + user = insert(:user) + 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/pleroma/admin/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 + end + end + + describe "GET /api/pleroma/admin/chats/:id" do + setup do: admin_setup() + + test "it returns a chat", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + + result = + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response_and_validate_schema(200) + + assert result["id"] == to_string(chat.id) + assert %{} = result["sender"] + assert %{} = result["receiver"] + refute result["account"] + end + end + + describe "unauthorized chat moderation" do + setup do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") + object = Object.normalize(message, false) + chat = Chat.get(user.id, recipient.ap_id) + cm_ref = MessageReference.for_chat_and_object(chat, object) + + %{conn: conn} = oauth_access(["read:chats", "write:chats"]) + %{conn: conn, chat: chat, cm_ref: cm_ref} + end + + test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ + conn: conn, + chat: chat, + cm_ref: cm_ref + } do + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response(403) + + assert MessageReference.get_by_id(cm_ref.id) == cm_ref + end + + test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response(403) + end + + test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response(403) + end + end + + describe "unauthenticated chat moderation" do + setup do + user = insert(:user) + recipient = insert(:user) + + {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") + object = Object.normalize(message, false) + chat = Chat.get(user.id, recipient.ap_id) + cm_ref = MessageReference.for_chat_and_object(chat, object) + + %{conn: build_conn(), chat: chat, cm_ref: cm_ref} + end + + test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ + conn: conn, + chat: chat, + cm_ref: cm_ref + } do + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") + |> json_response(403) + + assert MessageReference.get_by_id(cm_ref.id) == cm_ref + end + + test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}/messages") + |> json_response(403) + end + + test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do + conn + |> get("/api/pleroma/admin/chats/#{chat.id}") + |> json_response(403) + end + end +end diff --git a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs new file mode 100644 index 000000000..5f7b042f6 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs @@ -0,0 +1,106 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do + use Pleroma.Web.ConnCase, async: true + import Pleroma.Factory + alias Pleroma.Config + + @dir "test/tmp/instance_static" + @default_instance_panel ~s(

Welcome to Pleroma!

) + + setup do + File.mkdir_p!(@dir) + on_exit(fn -> File.rm_rf(@dir) end) + end + + setup do: clear_config([:instance, :static_dir], @dir) + + 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/instance_document/:name" do + test "return the instance document url", %{conn: conn} do + conn = get(conn, "/api/pleroma/admin/instance_document/instance-panel") + + assert content = html_response(conn, 200) + assert String.contains?(content, @default_instance_panel) + 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) + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert json_response(conn, :forbidden) + end + + test "it returns 404 if the instance document with the given name doesn't exist", %{ + conn: conn + } do + conn = get(conn, "/api/pleroma/admin/instance_document/1234") + + assert json_response_and_validate_schema(conn, 404) + end + end + + describe "PATCH /api/pleroma/admin/instance_document/:name" do + test "uploads the instance document", %{conn: conn} do + image = %Plug.Upload{ + content_type: "text/html", + path: Path.absname("test/fixtures/custom_instance_panel.html"), + filename: "custom_instance_panel.html" + } + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/admin/instance_document/instance-panel", %{ + "file" => image + }) + + assert %{"url" => url} = json_response_and_validate_schema(conn, 200) + index = get(build_conn(), url) + assert html_response(index, 200) == "

Custom instance panel

" + end + end + + describe "DELETE /api/pleroma/admin/instance_document/:name" do + test "deletes the instance document", %{conn: conn} do + File.mkdir!(@dir <> "/instance/") + File.write!(@dir <> "/instance/panel.html", "Custom instance panel") + + conn_resp = + conn + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert html_response(conn_resp, 200) == "Custom instance panel" + + conn + |> delete("/api/pleroma/admin/instance_document/instance-panel") + |> json_response_and_validate_schema(200) + + conn_resp = + conn + |> get("/api/pleroma/admin/instance_document/instance-panel") + + assert content = html_response(conn_resp, 200) + assert String.contains?(content, @default_instance_panel) + end + end +end diff --git a/test/pleroma/web/fed_sockets/fed_registry_test.exs b/test/pleroma/web/fed_sockets/fed_registry_test.exs new file mode 100644 index 000000000..19ac874d6 --- /dev/null +++ b/test/pleroma/web/fed_sockets/fed_registry_test.exs @@ -0,0 +1,124 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.FedSockets.FedRegistryTest do + use ExUnit.Case + + alias Pleroma.Web.FedSockets + alias Pleroma.Web.FedSockets.FedRegistry + alias Pleroma.Web.FedSockets.SocketInfo + + @good_domain "http://good.domain" + @good_domain_origin "good.domain:80" + + setup do + start_supervised({Pleroma.Web.FedSockets.Supervisor, []}) + build_test_socket(@good_domain) + Process.sleep(10) + + :ok + end + + describe "add_fed_socket/1 without conflicting sockets" do + test "can be added" do + Process.sleep(10) + assert {:ok, %SocketInfo{origin: origin}} = FedRegistry.get_fed_socket(@good_domain_origin) + assert origin == "good.domain:80" + end + + test "multiple origins can be added" do + build_test_socket("http://anothergood.domain") + Process.sleep(10) + + assert {:ok, %SocketInfo{origin: origin_1}} = + FedRegistry.get_fed_socket(@good_domain_origin) + + assert {:ok, %SocketInfo{origin: origin_2}} = + FedRegistry.get_fed_socket("anothergood.domain:80") + + assert origin_1 == "good.domain:80" + assert origin_2 == "anothergood.domain:80" + assert FedRegistry.list_all() |> Enum.count() == 2 + end + end + + describe "add_fed_socket/1 when duplicate sockets conflict" do + setup do + build_test_socket(@good_domain) + build_test_socket(@good_domain) + Process.sleep(10) + :ok + end + + test "will be ignored" do + assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = + FedRegistry.get_fed_socket(@good_domain_origin) + + assert origin == "good.domain:80" + + assert FedRegistry.list_all() |> Enum.count() == 1 + end + + test "the newer process will be closed" do + pid_two = build_test_socket(@good_domain) + + assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = + FedRegistry.get_fed_socket(@good_domain_origin) + + assert origin == "good.domain:80" + Process.sleep(10) + + refute Process.alive?(pid_two) + + assert FedRegistry.list_all() |> Enum.count() == 1 + end + end + + describe "get_fed_socket/1" do + test "returns missing for unknown hosts" do + assert {:error, :missing} = FedRegistry.get_fed_socket("not_a_dmoain") + end + + test "returns rejected for hosts previously rejected" do + "rejected.domain:80" + |> FedSockets.uri_for_origin() + |> FedRegistry.set_host_rejected() + + assert {:error, :rejected} = FedRegistry.get_fed_socket("rejected.domain:80") + end + + test "can retrieve a previously added SocketInfo" do + build_test_socket(@good_domain) + Process.sleep(10) + assert {:ok, %SocketInfo{origin: origin}} = FedRegistry.get_fed_socket(@good_domain_origin) + assert origin == "good.domain:80" + end + + test "removes references to SocketInfos when the process crashes" do + assert {:ok, %SocketInfo{origin: origin, pid: pid}} = + FedRegistry.get_fed_socket(@good_domain_origin) + + assert origin == "good.domain:80" + + Process.exit(pid, :testing) + Process.sleep(100) + assert {:error, :missing} = FedRegistry.get_fed_socket(@good_domain_origin) + end + end + + def build_test_socket(uri) do + Kernel.spawn(fn -> fed_socket_almost(uri) end) + end + + def fed_socket_almost(origin) do + FedRegistry.add_fed_socket(origin) + + receive do + :close -> + :ok + after + 5_000 -> :timeout + end + end +end diff --git a/test/pleroma/web/fed_sockets/fetch_registry_test.exs b/test/pleroma/web/fed_sockets/fetch_registry_test.exs new file mode 100644 index 000000000..7bd2d995a --- /dev/null +++ b/test/pleroma/web/fed_sockets/fetch_registry_test.exs @@ -0,0 +1,67 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.FedSockets.FetchRegistryTest do + use ExUnit.Case + + alias Pleroma.Web.FedSockets.FetchRegistry + alias Pleroma.Web.FedSockets.FetchRegistry.FetchRegistryData + + @json_message "hello" + @json_reply "hello back" + + setup do + start_supervised( + {Pleroma.Web.FedSockets.Supervisor, + [ + ping_interval: 8, + connection_duration: 15, + rejection_duration: 5, + fed_socket_fetches: [default: 10, interval: 10] + ]} + ) + + :ok + end + + test "fetches can be stored" do + uuid = FetchRegistry.register_fetch(@json_message) + + assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) + end + + test "fetches can return" do + uuid = FetchRegistry.register_fetch(@json_message) + task = Task.async(fn -> FetchRegistry.register_fetch_received(uuid, @json_reply) end) + + assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) + Task.await(task) + + assert {:ok, %FetchRegistryData{received_json: received_json}} = + FetchRegistry.check_fetch(uuid) + + assert received_json == @json_reply + end + + test "fetches are deleted once popped from stack" do + uuid = FetchRegistry.register_fetch(@json_message) + task = Task.async(fn -> FetchRegistry.register_fetch_received(uuid, @json_reply) end) + Task.await(task) + + assert {:ok, %FetchRegistryData{received_json: received_json}} = + FetchRegistry.check_fetch(uuid) + + assert received_json == @json_reply + assert {:ok, @json_reply} = FetchRegistry.pop_fetch(uuid) + + assert {:error, :missing} = FetchRegistry.check_fetch(uuid) + end + + test "fetches can time out" do + uuid = FetchRegistry.register_fetch(@json_message) + assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) + Process.sleep(500) + assert {:error, :missing} = FetchRegistry.check_fetch(uuid) + end +end diff --git a/test/pleroma/web/fed_sockets/socket_info_test.exs b/test/pleroma/web/fed_sockets/socket_info_test.exs new file mode 100644 index 000000000..db3d6edcd --- /dev/null +++ b/test/pleroma/web/fed_sockets/socket_info_test.exs @@ -0,0 +1,118 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.FedSockets.SocketInfoTest do + use ExUnit.Case + + alias Pleroma.Web.FedSockets + alias Pleroma.Web.FedSockets.SocketInfo + + describe "uri_for_origin" do + test "provides the fed_socket URL given the origin information" do + endpoint = "example.com:4000" + assert FedSockets.uri_for_origin(endpoint) =~ "ws://" + assert FedSockets.uri_for_origin(endpoint) =~ endpoint + end + end + + describe "origin" do + test "will provide the origin field given a url" do + endpoint = "example.com:4000" + assert SocketInfo.origin("ws://#{endpoint}") == endpoint + assert SocketInfo.origin("http://#{endpoint}") == endpoint + assert SocketInfo.origin("https://#{endpoint}") == endpoint + end + + test "will proide the origin field given a uri" do + endpoint = "example.com:4000" + uri = URI.parse("http://#{endpoint}") + + assert SocketInfo.origin(uri) == endpoint + end + end + + describe "touch" do + test "will update the TTL" do + endpoint = "example.com:4000" + socket = SocketInfo.build("ws://#{endpoint}") + Process.sleep(2) + touched_socket = SocketInfo.touch(socket) + + assert socket.connected_until < touched_socket.connected_until + end + end + + describe "expired?" do + setup do + start_supervised( + {Pleroma.Web.FedSockets.Supervisor, + [ + ping_interval: 8, + connection_duration: 5, + rejection_duration: 5, + fed_socket_rejections: [lazy: true] + ]} + ) + + :ok + end + + test "tests if the TTL is exceeded" do + endpoint = "example.com:4000" + socket = SocketInfo.build("ws://#{endpoint}") + refute SocketInfo.expired?(socket) + Process.sleep(10) + + assert SocketInfo.expired?(socket) + end + end + + describe "creating outgoing connection records" do + test "can be passed a string" do + assert %{conn_pid: :pid, origin: _origin} = SocketInfo.build("example.com:4000", :pid) + end + + test "can be passed a URI" do + uri = URI.parse("http://example.com:4000") + assert %{conn_pid: :pid, origin: origin} = SocketInfo.build(uri, :pid) + assert origin =~ "example.com:4000" + end + + test "will include the port number" do + assert %{conn_pid: :pid, origin: origin} = SocketInfo.build("http://example.com:4000", :pid) + + assert origin =~ ":4000" + end + + test "will provide the port if missing" do + assert %{conn_pid: :pid, origin: "example.com:80"} = + SocketInfo.build("http://example.com", :pid) + + assert %{conn_pid: :pid, origin: "example.com:443"} = + SocketInfo.build("https://example.com", :pid) + end + end + + describe "creating incoming connection records" do + test "can be passed a string" do + assert %{pid: _, origin: _origin} = SocketInfo.build("example.com:4000") + end + + test "can be passed a URI" do + uri = URI.parse("example.com:4000") + assert %{pid: _, origin: _origin} = SocketInfo.build(uri) + end + + test "will include the port number" do + assert %{pid: _, origin: origin} = SocketInfo.build("http://example.com:4000") + + assert origin =~ ":4000" + end + + test "will provide the port if missing" do + assert %{pid: _, origin: "example.com:80"} = SocketInfo.build("http://example.com") + assert %{pid: _, origin: "example.com:443"} = SocketInfo.build("https://example.com") + end + end +end diff --git a/test/web/activity_pub/object_validators/article_note_validator_test.exs b/test/web/activity_pub/object_validators/article_note_validator_test.exs deleted file mode 100644 index cc6dab872..000000000 --- a/test/web/activity_pub/object_validators/article_note_validator_test.exs +++ /dev/null @@ -1,35 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidatorTest do - use Pleroma.DataCase - - alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNoteValidator - 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} = ArticleNoteValidator.cast_and_validate(note) - end - end -end diff --git a/test/web/activity_pub/transmogrifier/article_handling_test.exs b/test/web/activity_pub/transmogrifier/article_handling_test.exs deleted file mode 100644 index 9b12a470a..000000000 --- a/test/web/activity_pub/transmogrifier/article_handling_test.exs +++ /dev/null @@ -1,75 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Object.Fetcher - alias Pleroma.Web.ActivityPub.Transmogrifier - - test "Pterotype (Wordpress Plugin) Article" do - Tesla.Mock.mock(fn %{url: "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog"} -> - %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json")} - end) - - data = - File.read!("test/fixtures/tesla_mock/wedistribute-create-article.json") |> Jason.decode!() - - {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - - object = Object.normalize(data["object"]) - - assert object.data["name"] == "The end is near: Mastodon plans to drop OStatus support" - - assert object.data["summary"] == - "One of the largest platforms in the federated social web is dropping the protocol that it started with." - - assert object.data["url"] == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" - end - - test "Plume Article" do - Tesla.Mock.mock(fn - %{url: "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} -> - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json") - } - - %{url: "https://baptiste.gelez.xyz/@/BaptisteGelez"} -> - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json") - } - end) - - {:ok, object} = - Fetcher.fetch_object_from_id( - "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" - ) - - assert object.data["name"] == "This Month in Plume: June 2018" - - assert object.data["url"] == - "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/" - end - - test "Prismo Article" do - Tesla.Mock.mock(fn %{url: "https://prismo.news/@mxb"} -> - %Tesla.Env{ - status: 200, - body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json") - } - end) - - data = File.read!("test/fixtures/prismo-url-map.json") |> Jason.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 -end diff --git a/test/web/activity_pub/transmogrifier/video_handling_test.exs b/test/web/activity_pub/transmogrifier/video_handling_test.exs deleted file mode 100644 index 69c953a2e..000000000 --- a/test/web/activity_pub/transmogrifier/video_handling_test.exs +++ /dev/null @@ -1,93 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do - use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase - - alias Pleroma.Activity - alias Pleroma.Object - alias Pleroma.Object.Fetcher - alias Pleroma.Web.ActivityPub.Transmogrifier - - setup_all do - Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) - :ok - end - - test "skip converting the content when it is nil" do - data = - File.read!("test/fixtures/tesla_mock/framatube.org-video.json") - |> Jason.decode!() - |> Kernel.put_in(["object", "content"], nil) - - {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert object = Object.normalize(activity, false) - - assert object.data["content"] == nil - end - - test "it converts content of object to html" do - data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() - - {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert object = Object.normalize(activity, false) - - assert object.data["content"] == - "

Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?

Transcription par @aprilorg ici : https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft

" - 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", - "name" => nil, - "url" => [ - %{ - "href" => - "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - - data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!() - - {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) - - assert object = Object.normalize(activity, false) - - assert object.data["attachment"] == [ - %{ - "type" => "Link", - "mediaType" => "video/mp4", - "name" => nil, - "url" => [ - %{ - "href" => - "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", - "mediaType" => "video/mp4", - "type" => "Link" - } - ] - } - ] - - assert object.data["url"] == - "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" - end -end diff --git a/test/web/admin_api/controllers/chat_controller_test.exs b/test/web/admin_api/controllers/chat_controller_test.exs deleted file mode 100644 index bd4c9c9d1..000000000 --- a/test/web/admin_api/controllers/chat_controller_test.exs +++ /dev/null @@ -1,219 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.ChatControllerTest do - use Pleroma.Web.ConnCase - - import Pleroma.Factory - - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference - alias Pleroma.Config - alias Pleroma.ModerationLog - alias Pleroma.Object - alias Pleroma.Repo - alias Pleroma.Web.CommonAPI - - defp admin_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 "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do - setup do: admin_setup() - - test "it deletes a message from the chat", %{conn: conn, admin: admin} do - user = insert(:user) - recipient = insert(:user) - - {:ok, message} = - CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend") - - object = Object.normalize(message, false) - - chat = Chat.get(user.id, recipient.ap_id) - recipient_chat = Chat.get(recipient.id, user.ap_id) - - cm_ref = MessageReference.for_chat_and_object(chat, object) - recipient_cm_ref = MessageReference.for_chat_and_object(recipient_chat, object) - - result = - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") - |> json_response_and_validate_schema(200) - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deleted chat message ##{cm_ref.id}" - - assert result["id"] == cm_ref.id - refute MessageReference.get_by_id(cm_ref.id) - refute MessageReference.get_by_id(recipient_cm_ref.id) - assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) - end - end - - describe "GET /api/pleroma/admin/chats/:id/messages" do - setup do: admin_setup() - - test "it paginates", %{conn: conn} do - user = insert(:user) - 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/pleroma/admin/chats/#{chat.id}/messages") - |> json_response_and_validate_schema(200) - - assert length(result) == 20 - - result = - conn - |> get("/api/pleroma/admin/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} do - user = insert(:user) - 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/pleroma/admin/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 - end - end - - describe "GET /api/pleroma/admin/chats/:id" do - setup do: admin_setup() - - test "it returns a chat", %{conn: conn} do - user = insert(:user) - other_user = insert(:user) - - {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) - - result = - conn - |> get("/api/pleroma/admin/chats/#{chat.id}") - |> json_response_and_validate_schema(200) - - assert result["id"] == to_string(chat.id) - assert %{} = result["sender"] - assert %{} = result["receiver"] - refute result["account"] - end - end - - describe "unauthorized chat moderation" do - setup do - user = insert(:user) - recipient = insert(:user) - - {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") - object = Object.normalize(message, false) - chat = Chat.get(user.id, recipient.ap_id) - cm_ref = MessageReference.for_chat_and_object(chat, object) - - %{conn: conn} = oauth_access(["read:chats", "write:chats"]) - %{conn: conn, chat: chat, cm_ref: cm_ref} - end - - test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ - conn: conn, - chat: chat, - cm_ref: cm_ref - } do - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") - |> json_response(403) - - assert MessageReference.get_by_id(cm_ref.id) == cm_ref - end - - test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do - conn - |> get("/api/pleroma/admin/chats/#{chat.id}/messages") - |> json_response(403) - end - - test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do - conn - |> get("/api/pleroma/admin/chats/#{chat.id}") - |> json_response(403) - end - end - - describe "unauthenticated chat moderation" do - setup do - user = insert(:user) - recipient = insert(:user) - - {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo") - object = Object.normalize(message, false) - chat = Chat.get(user.id, recipient.ap_id) - cm_ref = MessageReference.for_chat_and_object(chat, object) - - %{conn: build_conn(), chat: chat, cm_ref: cm_ref} - end - - test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{ - conn: conn, - chat: chat, - cm_ref: cm_ref - } do - conn - |> put_req_header("content-type", "application/json") - |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}") - |> json_response(403) - - assert MessageReference.get_by_id(cm_ref.id) == cm_ref - end - - test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do - conn - |> get("/api/pleroma/admin/chats/#{chat.id}/messages") - |> json_response(403) - end - - test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do - conn - |> get("/api/pleroma/admin/chats/#{chat.id}") - |> json_response(403) - end - end -end diff --git a/test/web/admin_api/controllers/instance_document_controller_test.exs b/test/web/admin_api/controllers/instance_document_controller_test.exs deleted file mode 100644 index 5f7b042f6..000000000 --- a/test/web/admin_api/controllers/instance_document_controller_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do - use Pleroma.Web.ConnCase, async: true - import Pleroma.Factory - alias Pleroma.Config - - @dir "test/tmp/instance_static" - @default_instance_panel ~s(

Welcome to Pleroma!

) - - setup do - File.mkdir_p!(@dir) - on_exit(fn -> File.rm_rf(@dir) end) - end - - setup do: clear_config([:instance, :static_dir], @dir) - - 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/instance_document/:name" do - test "return the instance document url", %{conn: conn} do - conn = get(conn, "/api/pleroma/admin/instance_document/instance-panel") - - assert content = html_response(conn, 200) - assert String.contains?(content, @default_instance_panel) - 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) - |> get("/api/pleroma/admin/instance_document/instance-panel") - - assert json_response(conn, :forbidden) - end - - test "it returns 404 if the instance document with the given name doesn't exist", %{ - conn: conn - } do - conn = get(conn, "/api/pleroma/admin/instance_document/1234") - - assert json_response_and_validate_schema(conn, 404) - end - end - - describe "PATCH /api/pleroma/admin/instance_document/:name" do - test "uploads the instance document", %{conn: conn} do - image = %Plug.Upload{ - content_type: "text/html", - path: Path.absname("test/fixtures/custom_instance_panel.html"), - filename: "custom_instance_panel.html" - } - - conn = - conn - |> put_req_header("content-type", "multipart/form-data") - |> patch("/api/pleroma/admin/instance_document/instance-panel", %{ - "file" => image - }) - - assert %{"url" => url} = json_response_and_validate_schema(conn, 200) - index = get(build_conn(), url) - assert html_response(index, 200) == "

Custom instance panel

" - end - end - - describe "DELETE /api/pleroma/admin/instance_document/:name" do - test "deletes the instance document", %{conn: conn} do - File.mkdir!(@dir <> "/instance/") - File.write!(@dir <> "/instance/panel.html", "Custom instance panel") - - conn_resp = - conn - |> get("/api/pleroma/admin/instance_document/instance-panel") - - assert html_response(conn_resp, 200) == "Custom instance panel" - - conn - |> delete("/api/pleroma/admin/instance_document/instance-panel") - |> json_response_and_validate_schema(200) - - conn_resp = - conn - |> get("/api/pleroma/admin/instance_document/instance-panel") - - assert content = html_response(conn_resp, 200) - assert String.contains?(content, @default_instance_panel) - end - end -end diff --git a/test/web/fed_sockets/fed_registry_test.exs b/test/web/fed_sockets/fed_registry_test.exs deleted file mode 100644 index 19ac874d6..000000000 --- a/test/web/fed_sockets/fed_registry_test.exs +++ /dev/null @@ -1,124 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FedSockets.FedRegistryTest do - use ExUnit.Case - - alias Pleroma.Web.FedSockets - alias Pleroma.Web.FedSockets.FedRegistry - alias Pleroma.Web.FedSockets.SocketInfo - - @good_domain "http://good.domain" - @good_domain_origin "good.domain:80" - - setup do - start_supervised({Pleroma.Web.FedSockets.Supervisor, []}) - build_test_socket(@good_domain) - Process.sleep(10) - - :ok - end - - describe "add_fed_socket/1 without conflicting sockets" do - test "can be added" do - Process.sleep(10) - assert {:ok, %SocketInfo{origin: origin}} = FedRegistry.get_fed_socket(@good_domain_origin) - assert origin == "good.domain:80" - end - - test "multiple origins can be added" do - build_test_socket("http://anothergood.domain") - Process.sleep(10) - - assert {:ok, %SocketInfo{origin: origin_1}} = - FedRegistry.get_fed_socket(@good_domain_origin) - - assert {:ok, %SocketInfo{origin: origin_2}} = - FedRegistry.get_fed_socket("anothergood.domain:80") - - assert origin_1 == "good.domain:80" - assert origin_2 == "anothergood.domain:80" - assert FedRegistry.list_all() |> Enum.count() == 2 - end - end - - describe "add_fed_socket/1 when duplicate sockets conflict" do - setup do - build_test_socket(@good_domain) - build_test_socket(@good_domain) - Process.sleep(10) - :ok - end - - test "will be ignored" do - assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = - FedRegistry.get_fed_socket(@good_domain_origin) - - assert origin == "good.domain:80" - - assert FedRegistry.list_all() |> Enum.count() == 1 - end - - test "the newer process will be closed" do - pid_two = build_test_socket(@good_domain) - - assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = - FedRegistry.get_fed_socket(@good_domain_origin) - - assert origin == "good.domain:80" - Process.sleep(10) - - refute Process.alive?(pid_two) - - assert FedRegistry.list_all() |> Enum.count() == 1 - end - end - - describe "get_fed_socket/1" do - test "returns missing for unknown hosts" do - assert {:error, :missing} = FedRegistry.get_fed_socket("not_a_dmoain") - end - - test "returns rejected for hosts previously rejected" do - "rejected.domain:80" - |> FedSockets.uri_for_origin() - |> FedRegistry.set_host_rejected() - - assert {:error, :rejected} = FedRegistry.get_fed_socket("rejected.domain:80") - end - - test "can retrieve a previously added SocketInfo" do - build_test_socket(@good_domain) - Process.sleep(10) - assert {:ok, %SocketInfo{origin: origin}} = FedRegistry.get_fed_socket(@good_domain_origin) - assert origin == "good.domain:80" - end - - test "removes references to SocketInfos when the process crashes" do - assert {:ok, %SocketInfo{origin: origin, pid: pid}} = - FedRegistry.get_fed_socket(@good_domain_origin) - - assert origin == "good.domain:80" - - Process.exit(pid, :testing) - Process.sleep(100) - assert {:error, :missing} = FedRegistry.get_fed_socket(@good_domain_origin) - end - end - - def build_test_socket(uri) do - Kernel.spawn(fn -> fed_socket_almost(uri) end) - end - - def fed_socket_almost(origin) do - FedRegistry.add_fed_socket(origin) - - receive do - :close -> - :ok - after - 5_000 -> :timeout - end - end -end diff --git a/test/web/fed_sockets/fetch_registry_test.exs b/test/web/fed_sockets/fetch_registry_test.exs deleted file mode 100644 index 7bd2d995a..000000000 --- a/test/web/fed_sockets/fetch_registry_test.exs +++ /dev/null @@ -1,67 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FedSockets.FetchRegistryTest do - use ExUnit.Case - - alias Pleroma.Web.FedSockets.FetchRegistry - alias Pleroma.Web.FedSockets.FetchRegistry.FetchRegistryData - - @json_message "hello" - @json_reply "hello back" - - setup do - start_supervised( - {Pleroma.Web.FedSockets.Supervisor, - [ - ping_interval: 8, - connection_duration: 15, - rejection_duration: 5, - fed_socket_fetches: [default: 10, interval: 10] - ]} - ) - - :ok - end - - test "fetches can be stored" do - uuid = FetchRegistry.register_fetch(@json_message) - - assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) - end - - test "fetches can return" do - uuid = FetchRegistry.register_fetch(@json_message) - task = Task.async(fn -> FetchRegistry.register_fetch_received(uuid, @json_reply) end) - - assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) - Task.await(task) - - assert {:ok, %FetchRegistryData{received_json: received_json}} = - FetchRegistry.check_fetch(uuid) - - assert received_json == @json_reply - end - - test "fetches are deleted once popped from stack" do - uuid = FetchRegistry.register_fetch(@json_message) - task = Task.async(fn -> FetchRegistry.register_fetch_received(uuid, @json_reply) end) - Task.await(task) - - assert {:ok, %FetchRegistryData{received_json: received_json}} = - FetchRegistry.check_fetch(uuid) - - assert received_json == @json_reply - assert {:ok, @json_reply} = FetchRegistry.pop_fetch(uuid) - - assert {:error, :missing} = FetchRegistry.check_fetch(uuid) - end - - test "fetches can time out" do - uuid = FetchRegistry.register_fetch(@json_message) - assert {:error, :waiting} = FetchRegistry.check_fetch(uuid) - Process.sleep(500) - assert {:error, :missing} = FetchRegistry.check_fetch(uuid) - end -end diff --git a/test/web/fed_sockets/socket_info_test.exs b/test/web/fed_sockets/socket_info_test.exs deleted file mode 100644 index db3d6edcd..000000000 --- a/test/web/fed_sockets/socket_info_test.exs +++ /dev/null @@ -1,118 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.FedSockets.SocketInfoTest do - use ExUnit.Case - - alias Pleroma.Web.FedSockets - alias Pleroma.Web.FedSockets.SocketInfo - - describe "uri_for_origin" do - test "provides the fed_socket URL given the origin information" do - endpoint = "example.com:4000" - assert FedSockets.uri_for_origin(endpoint) =~ "ws://" - assert FedSockets.uri_for_origin(endpoint) =~ endpoint - end - end - - describe "origin" do - test "will provide the origin field given a url" do - endpoint = "example.com:4000" - assert SocketInfo.origin("ws://#{endpoint}") == endpoint - assert SocketInfo.origin("http://#{endpoint}") == endpoint - assert SocketInfo.origin("https://#{endpoint}") == endpoint - end - - test "will proide the origin field given a uri" do - endpoint = "example.com:4000" - uri = URI.parse("http://#{endpoint}") - - assert SocketInfo.origin(uri) == endpoint - end - end - - describe "touch" do - test "will update the TTL" do - endpoint = "example.com:4000" - socket = SocketInfo.build("ws://#{endpoint}") - Process.sleep(2) - touched_socket = SocketInfo.touch(socket) - - assert socket.connected_until < touched_socket.connected_until - end - end - - describe "expired?" do - setup do - start_supervised( - {Pleroma.Web.FedSockets.Supervisor, - [ - ping_interval: 8, - connection_duration: 5, - rejection_duration: 5, - fed_socket_rejections: [lazy: true] - ]} - ) - - :ok - end - - test "tests if the TTL is exceeded" do - endpoint = "example.com:4000" - socket = SocketInfo.build("ws://#{endpoint}") - refute SocketInfo.expired?(socket) - Process.sleep(10) - - assert SocketInfo.expired?(socket) - end - end - - describe "creating outgoing connection records" do - test "can be passed a string" do - assert %{conn_pid: :pid, origin: _origin} = SocketInfo.build("example.com:4000", :pid) - end - - test "can be passed a URI" do - uri = URI.parse("http://example.com:4000") - assert %{conn_pid: :pid, origin: origin} = SocketInfo.build(uri, :pid) - assert origin =~ "example.com:4000" - end - - test "will include the port number" do - assert %{conn_pid: :pid, origin: origin} = SocketInfo.build("http://example.com:4000", :pid) - - assert origin =~ ":4000" - end - - test "will provide the port if missing" do - assert %{conn_pid: :pid, origin: "example.com:80"} = - SocketInfo.build("http://example.com", :pid) - - assert %{conn_pid: :pid, origin: "example.com:443"} = - SocketInfo.build("https://example.com", :pid) - end - end - - describe "creating incoming connection records" do - test "can be passed a string" do - assert %{pid: _, origin: _origin} = SocketInfo.build("example.com:4000") - end - - test "can be passed a URI" do - uri = URI.parse("example.com:4000") - assert %{pid: _, origin: _origin} = SocketInfo.build(uri) - end - - test "will include the port number" do - assert %{pid: _, origin: origin} = SocketInfo.build("http://example.com:4000") - - assert origin =~ ":4000" - end - - test "will provide the port if missing" do - assert %{pid: _, origin: "example.com:80"} = SocketInfo.build("http://example.com") - assert %{pid: _, origin: "example.com:443"} = SocketInfo.build("https://example.com") - end - end -end -- cgit v1.2.3