[Pleroma.Formatter]: Add support for non-HTTP schemes in URIs
authorHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Mon, 18 Jun 2018 10:45:15 +0000 (12:45 +0200)
committerHaelwenn (lanodan) Monnier <contact@hacktivis.me>
Mon, 30 Jul 2018 20:01:48 +0000 (22:01 +0200)
The call to the regex in add_links is there just to be sure it’s a legal URI, it can be removed if you want to get more performance.

The URI Schemes list is sorted, but with http(s) at the start (in case it might make it faster for common links).

Closes: https://git.pleroma.social/pleroma/pleroma/issues/127
lib/pleroma/formatter.ex

index 0aaf215383c6168f32fe4b4e06a988a9e6f27f5a..fe3da09ac3e1e02481c6f3d1e76cf07e5961b86d 100644 (file)
@@ -165,8 +165,29 @@ defmodule Pleroma.Formatter do
     @emoji
   end
 
-  @link_regex ~r/https?:\/\/[\w\.\/?=\-#\+%&@~'\(\):]+[\w\/]/u
+  @link_regex ~r/[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+/ui
+
+  # IANA got a list https://www.iana.org/assignments/uri-schemes/ but
+  # Stuff like ipfs isn’t in it
+  # There is very niche stuff
+  @uri_schemes [
+    "https://",
+    "http://",
+    "dat://",
+    "dweb://",
+    "gopher://",
+    "ipfs://",
+    "ipns://",
+    "irc:",
+    "ircs:",
+    "magnet:",
+    "mailto:",
+    "mumble:",
+    "ssb://",
+    "xmpp:"
+  ]
 
+  # TODO: make it use something other than @link_regex
   def html_escape(text) do
     Regex.split(@link_regex, text, include_captures: true)
     |> Enum.map_every(2, fn chunk ->
@@ -176,11 +197,14 @@ defmodule Pleroma.Formatter do
     |> Enum.join("")
   end
 
-  @doc "changes http:... links to html links"
+  @doc "changes scheme:... urls to html links"
   def add_links({subs, text}) do
     links =
-      Regex.scan(@link_regex, text)
-      |> Enum.map(fn [url] -> {Ecto.UUID.generate(), url} end)
+      text
+      |> String.split([" ", "\t", "<br>"])
+      |> Enum.filter(fn word -> String.starts_with?(word, @uri_schemes) end)
+      |> Enum.filter(fn word -> Regex.match?(@link_regex, word) end)
+      |> Enum.map(fn url -> {Ecto.UUID.generate(), url} end)
       |> Enum.sort_by(fn {_, url} -> -String.length(url) end)
 
     uuid_text =