[#58] pre-link MFM content (#59)
authorfloatingghost <hannah@coffee-and-dreams.uk>
Sun, 10 Jul 2022 17:06:25 +0000 (17:06 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Sun, 10 Jul 2022 17:06:25 +0000 (17:06 +0000)
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/59

docs/development/setting_up_akkoma_dev.md
lib/pleroma/application.ex
lib/pleroma/formatter.ex
lib/pleroma/http.ex
lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
lib/pleroma/web/common_api/utils.ex
test/fixtures/misskey/mfm_underscore_format.json [new file with mode: 0644]
test/fixtures/misskey/mfm_x_format.json [new file with mode: 0644]
test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs

index 33ec24f6c222156ec40b4ee2ec336bdacd631cb2..7184be485bd586939706c3e3c86827cade040331 100644 (file)
@@ -36,6 +36,33 @@ config :logger, :console,
   level: :info
 ```
 
+## Testing with HTTPS
+
+If you end up developing alongside other software like misskey,
+you will not be able to federate without an SSL certificate. You should
+be able to use the snakeoil certificate that comes standard with most
+distributions or generate one from scratch, then force elixir to accept it.
+
+HTTP clients are none too keen to accept self-signed certs, but we can do
+this:
+
+```elixir
+config :pleroma, :http,
+  adapter: [
+    pools: %{
+      default: [
+        conn_opts: [
+          transport_opts: [
+            verify: :verify_none
+          ]
+        ]
+      ]
+    }
+  ]
+```
+
+Now your SSL requests will work. Hooray.
+
 ## Testing
 
 1. Create a `test.secret.exs` file with the content as shown below
index 0f4f5a358d4a5c9555b19db17fb488141d2600a2..fcb1d65711c0d799e8635b9d90f7148a862608da 100644 (file)
@@ -58,9 +58,6 @@ defmodule Pleroma.Application do
     Pleroma.Docs.JSON.compile()
     limiters_setup()
 
-    Logger.info("Starting Finch")
-    Finch.start_link(name: MyFinch)
-
     # Define workers and child supervisors to be supervised
     children =
       [
@@ -70,6 +67,7 @@ defmodule Pleroma.Application do
         Pleroma.Web.Plugs.RateLimiter.Supervisor
       ] ++
         cachex_children() ++
+        http_children() ++
         [
           Pleroma.Stats,
           Pleroma.JobQueueMonitor,
@@ -276,4 +274,13 @@ defmodule Pleroma.Application do
       ConcurrentLimiter.new(module, max_running, max_waiting)
     end)
   end
+
+  defp http_children do
+    config =
+      [:http, :adapter]
+      |> Config.get([])
+      |> Keyword.put(:name, MyFinch)
+
+    [{Finch, config}]
+  end
 end
index ae37946ab79630af6111ae439a8849a33df4f379..78325095aac79befc8f5674870548d3c5e278b36 100644 (file)
@@ -133,7 +133,7 @@ defmodule Pleroma.Formatter do
     HTML.filter_tags(text)
   end
 
-  def html_escape(text, "text/plain") do
+  def html_escape(text, format) when format in ["text/plain", "text/x.misskeymarkdown"] do
     Regex.split(@link_regex, text, include_captures: true)
     |> Enum.map_every(2, fn chunk ->
       {:safe, part} = Phoenix.HTML.html_escape(chunk)
index 01f307d1770610ef475c4c2f81c7f06de22a4415..d8028651c881034c9d6cbe3a11bdbf3cc366e5a6 100644 (file)
@@ -65,7 +65,6 @@ defmodule Pleroma.HTTP do
     options = put_in(options[:adapter], adapter_opts)
     params = options[:params] || []
     request = build_request(method, headers, options, url, body, params)
-
     client = Tesla.client([Tesla.Middleware.FollowRedirects])
 
     request(client, request)
index a9f395c5eaf397614863bc71c4b5c91b4d792fd0..e11335170a6fc60252bee6944f12a36415589449 100644 (file)
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
 
   alias Pleroma.EctoType.ActivityPub.ObjectValidators
   alias Pleroma.Object.Fetcher
+  alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
   alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
   alias Pleroma.Web.ActivityPub.Transmogrifier
@@ -81,12 +82,22 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
   defp fix_replies(data), do: data
 
   # https://github.com/misskey-dev/misskey/pull/8787
-  defp fix_misskey_content(%{"source" => %{"mediaType" => "text/x.misskeymarkdown"}} = object),
-    do: object
+  defp fix_misskey_content(
+         %{"source" => %{"mediaType" => "text/x.misskeymarkdown", "content" => content}} = object
+       ) do
+    {linked, _, _} = Utils.format_input(content, "text/x.misskeymarkdown")
+    Map.put(object, "content", linked)
+  end
 
   defp fix_misskey_content(%{"_misskey_content" => content} = object) do
+    {linked, _, _} = Utils.format_input(content, "text/x.misskeymarkdown")
+
     object
-    |> Map.put("source", %{"content" => content, "mediaType" => "text/x.misskeymarkdown"})
+    |> Map.put("source", %{
+      "content" => content,
+      "mediaType" => "text/x.misskeymarkdown"
+    })
+    |> Map.put("content", linked)
     |> Map.delete("_misskey_content")
   end
 
index 8fde9ae156efb615addc05c51e2bbb10718382a6..f5bc3acf553a23ff178934da486c448500eb82a5 100644 (file)
@@ -259,7 +259,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
   @doc """
   Formatting text to plain text, BBCode, HTML, or Markdown
   """
-  def format_input(text, "text/plain", options) do
+  def format_input(text, format, options)
+      when format in ["text/plain", "text/x.misskeymarkdown"] do
     text
     |> Formatter.html_escape("text/plain")
     |> Formatter.linkify(options)
@@ -291,15 +292,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
     |> Formatter.html_escape("text/html")
   end
 
-  def format_input(text, "text/x.misskeymarkdown", options) do
-    text
-    |> Formatter.html_escape("text/plain")
-    |> Formatter.linkify(options)
-    |> (fn {text, mentions, tags} ->
-          {String.replace(text, ~r/\r?\n/, "<br>"), mentions, tags}
-        end).()
-  end
-
   def format_naive_asctime(date) do
     date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
   end
diff --git a/test/fixtures/misskey/mfm_underscore_format.json b/test/fixtures/misskey/mfm_underscore_format.json
new file mode 100644 (file)
index 0000000..e031a95
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  "id": "https://misskey.local.live/notes/92j1n3owja",
+  "type": "Note",
+  "attributedTo": "https://misskey.local.live/users/92hzkskwgy",
+  "summary": null,
+  "content": "<p><a href=\"https://akkoma.local.live/users/akkoma_user\" class=\"u-url mention\">@akkoma_user@akkoma.local.live</a><span> linkifylink </span><a href=\"https://misskey.local.live/tags/dancedance\" rel=\"tag\">#dancedance</a><span> </span><i><span> mfm goes here</span></i><span> <br><br>## aaa</span></p>",
+  "_misskey_content": "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
+  "published": "2022-07-10T15:37:36.368Z",
+  "to": [
+    "https://www.w3.org/ns/activitystreams#Public"
+  ],
+  "cc": [
+    "https://misskey.local.live/users/92hzkskwgy/followers",
+    "http://localhost:4001/users/akkoma_user"
+  ],
+  "inReplyTo": null,
+  "attachment": [],
+  "sensitive": false,
+  "tag": [
+    {
+      "type": "Hashtag",
+      "href": "https://misskey.local.live/tags/dancedance",
+      "name": "#dancedance"
+    },
+    {
+      "type": "Mention",
+      "href": "http://localhost:4001/users/akkoma_user",
+      "name": "@akkoma_user"
+    }
+  ]
+}
diff --git a/test/fixtures/misskey/mfm_x_format.json b/test/fixtures/misskey/mfm_x_format.json
new file mode 100644 (file)
index 0000000..31d6e53
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  "id": "https://misskey.local.live/notes/92j1n3owja",
+  "type": "Note",
+  "attributedTo": "https://misskey.local.live/users/92hzkskwgy",
+  "summary": null,
+  "content": "<p><a href=\"https://akkoma.local.live/users/akkoma_user\" class=\"u-url mention\">@akkoma_user@akkoma.local.live</a><span> linkifylink </span><a href=\"https://misskey.local.live/tags/dancedance\" rel=\"tag\">#dancedance</a><span> </span><i><span> mfm goes here</span></i><span> <br><br>## aaa</span></p>",
+  "source": {
+    "content": "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
+    "mediaType": "text/x.misskeymarkdown"
+  },
+  "published": "2022-07-10T15:37:36.368Z",
+  "to": [
+    "https://www.w3.org/ns/activitystreams#Public"
+  ],
+  "cc": [
+    "https://misskey.local.live/users/92hzkskwgy/followers",
+    "http://localhost:4001/users/akkoma_user"
+  ],
+  "inReplyTo": null,
+  "attachment": [],
+  "sensitive": false,
+  "tag": [
+    {
+      "type": "Hashtag",
+      "href": "https://misskey.local.live/tags/dancedance",
+      "name": "#dancedance"
+    },
+    {
+      "type": "Mention",
+      "href": "http://localhost:4001/users/akkoma_user",
+      "name": "@akkoma_user"
+    }
+  ]
+}
index 717a704d407649e0efe21d384953ed0d78902283..62526d95203551b8644498c1047cce549921f712 100644 (file)
@@ -10,6 +10,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
 
   import Pleroma.Factory
 
+  setup_all do
+    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+    :ok
+  end
+
   describe "Notes" do
     setup do
       user = insert(:user)
@@ -63,5 +69,55 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
 
       %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
     end
+
+    test "a misskey MFM status with a content field should work and be linked", _ do
+      local_user = insert(:user, %{nickname: "akkoma_user"})
+
+      insert(:user, %{ap_id: "https://misskey.local.live/users/92hzkskwgy"})
+
+      note =
+        "test/fixtures/misskey/mfm_x_format.json"
+        |> File.read!()
+        |> Jason.decode!()
+
+      expected_content =
+        "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{local_user.id}\" href=\"#{local_user.ap_id}\" rel=\"ugc\">@<span>akkoma_user</span></a></span> linkifylink <a class=\"hashtag\" data-tag=\"dancedance\" href=\"http://localhost:4001/tag/dancedance\" rel=\"tag ugc\">#dancedance</a> $[jelly mfm goes here] <br><br>## aaa"
+
+      %{
+        valid?: true,
+        changes: %{
+          content: ^expected_content,
+          source: %{
+            "content" => "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
+            "mediaType" => "text/x.misskeymarkdown"
+          }
+        }
+      } = ArticleNotePageValidator.cast_and_validate(note)
+    end
+
+    test "a misskey MFM status with a _misskey_content field should work and be linked", _ do
+      local_user = insert(:user, %{nickname: "akkoma_user"})
+
+      insert(:user, %{ap_id: "https://misskey.local.live/users/92hzkskwgy"})
+
+      note =
+        "test/fixtures/misskey/mfm_underscore_format.json"
+        |> File.read!()
+        |> Jason.decode!()
+
+      expected_content =
+        "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{local_user.id}\" href=\"#{local_user.ap_id}\" rel=\"ugc\">@<span>akkoma_user</span></a></span> linkifylink <a class=\"hashtag\" data-tag=\"dancedance\" href=\"http://localhost:4001/tag/dancedance\" rel=\"tag ugc\">#dancedance</a> $[jelly mfm goes here] <br><br>## aaa"
+
+      %{
+        valid?: true,
+        changes: %{
+          content: ^expected_content,
+          source: %{
+            "content" => "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
+            "mediaType" => "text/x.misskeymarkdown"
+          }
+        }
+      } = ArticleNotePageValidator.cast_and_validate(note)
+    end
   end
 end