From 05d111b622c7496260effd298163e9ca2aa59c3d Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 01:15:28 +0300
Subject: [PATCH 01/12] Use the default scrubber before mediaproxy
 transformation

---
 config/config.exs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config/config.exs b/config/config.exs
index a69d41d17..e2b00bda1 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -284,8 +284,8 @@
   allow_tables: false,
   allow_fonts: false,
   scrub_policy: [
-    Pleroma.HTML.Transform.MediaProxy,
-    Pleroma.HTML.Scrubber.Default
+    Pleroma.HTML.Scrubber.Default,
+    Pleroma.HTML.Transform.MediaProxy
   ]
 
 config :pleroma, :frontend_configurations,

From 9434e151a9f08067bf324ef027d857b67b0a96cb Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 01:16:22 +0300
Subject: [PATCH 02/12] Blacklist myhtmlex nodes from swarm

---
 config/config.exs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config/config.exs b/config/config.exs
index e2b00bda1..81d50cdee 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -603,6 +603,7 @@
   activity_pub: nil,
   activity_pub_question: 30_000
 
+config :swarm, node_blacklist: [~r/myhtmlex_.*$/]
 # Import environment specific config. This must remain at the bottom
 # of this file so it overrides the configuration defined above.
 import_config "#{Mix.env()}.exs"

From 2453928b57d3dbe60a5f6a4a85f2f03d3192108e Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 01:16:57 +0300
Subject: [PATCH 03/12] Ensure myhtmlex is started before swarm

Otherwise swarm is going to attempt resizing the cluster and timeout
---
 mix.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mix.exs b/mix.exs
index dcb9d9ea8..705d56f0e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -63,7 +63,7 @@ def copy_nginx_config(%{path: target_path} = release) do
   def application do
     [
       mod: {Pleroma.Application, []},
-      extra_applications: [:logger, :runtime_tools, :comeonin, :quack],
+      extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :myhtmlex, :swarm],
       included_applications: [:ex_syslogger]
     ]
   end

From 08f68370659597d6bc428e425925bcb9516d5706 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 01:18:08 +0300
Subject: [PATCH 04/12] Switch from HtmlSanitizeEx to FastSanitize

---
 lib/pleroma/html.ex                           | 129 +++++++++---------
 test/emoji/formatter_test.exs                 |   2 +-
 test/html_test.exs                            |  44 +++---
 .../mrf/normalize_markup_test.exs             |  10 +-
 test/web/common_api/common_api_test.exs       |   4 +-
 5 files changed, 95 insertions(+), 94 deletions(-)

diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 937bafed5..fd0495049 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -3,7 +3,6 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.HTML do
-  alias HtmlSanitizeEx.Scrubber
 
   defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber]
   defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
@@ -24,9 +23,13 @@ def filter_tags(html, scrubbers) when is_list(scrubbers) do
     end)
   end
 
-  def filter_tags(html, scrubber), do: Scrubber.scrub(html, scrubber)
+  def filter_tags(html, scrubber) do
+    {:ok, content} = FastSanitize.Sanitizer.scrub(html, scrubber)
+    content
+  end
+
   def filter_tags(html), do: filter_tags(html, nil)
-  def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags)
+  def strip_tags(html), do: filter_tags(html, FastSanitize.Sanitizer.StripTags)
 
   def get_cached_scrubbed_html_for_activity(
         content,
@@ -36,7 +39,6 @@ def get_cached_scrubbed_html_for_activity(
         callback \\ fn x -> x end
       ) do
     key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}"
-
     Cachex.fetch!(:scrubber_cache, key, fn _key ->
       object = Pleroma.Object.normalize(activity)
       ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback)
@@ -46,7 +48,7 @@ def get_cached_scrubbed_html_for_activity(
   def get_cached_stripped_html_for_activity(content, activity, key) do
     get_cached_scrubbed_html_for_activity(
       content,
-      HtmlSanitizeEx.Scrubber.StripTags,
+      FastSanitize.Sanitizer.StripTags,
       activity,
       key,
       &HtmlEntities.decode/1
@@ -109,13 +111,12 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
   require HtmlSanitizeEx.Scrubber.Meta
   alias HtmlSanitizeEx.Scrubber.Meta
 
-  Meta.remove_cdata_sections_before_scrub()
   Meta.strip_comments()
 
   # links
-  Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
+  Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes)
 
-  Meta.allow_tag_with_this_attribute_values("a", "class", [
+  Meta.allow_tag_with_this_attribute_values(:a, "class", [
     "hashtag",
     "u-url",
     "mention",
@@ -123,29 +124,29 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
     "mention u-url"
   ])
 
-  Meta.allow_tag_with_this_attribute_values("a", "rel", [
+  Meta.allow_tag_with_this_attribute_values(:a, "rel", [
     "tag",
     "nofollow",
     "noopener",
     "noreferrer"
   ])
 
-  Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+  Meta.allow_tag_with_these_attributes(:a, ["name", "title"])
 
   # paragraphs and linebreaks
-  Meta.allow_tag_with_these_attributes("br", [])
-  Meta.allow_tag_with_these_attributes("p", [])
+  Meta.allow_tag_with_these_attributes(:br, [])
+  Meta.allow_tag_with_these_attributes(:p, [])
 
   # microformats
-  Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
-  Meta.allow_tag_with_these_attributes("span", [])
+  Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"])
+  Meta.allow_tag_with_these_attributes(:span, [])
 
   # allow inline images for custom emoji
   if Pleroma.Config.get([:markup, :allow_inline_images]) do
     # restrict img tags to http/https only, because of MediaProxy.
-    Meta.allow_tag_with_uri_attributes("img", ["src"], ["http", "https"])
+    Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])
 
-    Meta.allow_tag_with_these_attributes("img", [
+    Meta.allow_tag_with_these_attributes(:img, [
       "width",
       "height",
       "class",
@@ -160,19 +161,19 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
 defmodule Pleroma.HTML.Scrubber.Default do
   @doc "The default HTML scrubbing policy: no "
 
-  require HtmlSanitizeEx.Scrubber.Meta
-  alias HtmlSanitizeEx.Scrubber.Meta
+  require FastSanitize.Sanitizer.Meta
+  alias FastSanitize.Sanitizer.Meta
   # credo:disable-for-previous-line
   # No idea how to fix this oneā€¦
 
   @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
 
-  Meta.remove_cdata_sections_before_scrub()
+#  Meta.remove_cdata_sections_before_scrub()
   Meta.strip_comments()
 
-  Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
+  Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes)
 
-  Meta.allow_tag_with_this_attribute_values("a", "class", [
+  Meta.allow_tag_with_this_attribute_values(:a, "class", [
     "hashtag",
     "u-url",
     "mention",
@@ -180,7 +181,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
     "mention u-url"
   ])
 
-  Meta.allow_tag_with_this_attribute_values("a", "rel", [
+  Meta.allow_tag_with_this_attribute_values(:a, "rel", [
     "tag",
     "nofollow",
     "noopener",
@@ -188,37 +189,37 @@ defmodule Pleroma.HTML.Scrubber.Default do
     "ugc"
   ])
 
-  Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+  Meta.allow_tag_with_these_attributes(:a, ["name", "title"])
 
-  Meta.allow_tag_with_these_attributes("abbr", ["title"])
+  Meta.allow_tag_with_these_attributes(:abbr, ["title"])
 
-  Meta.allow_tag_with_these_attributes("b", [])
-  Meta.allow_tag_with_these_attributes("blockquote", [])
-  Meta.allow_tag_with_these_attributes("br", [])
-  Meta.allow_tag_with_these_attributes("code", [])
-  Meta.allow_tag_with_these_attributes("del", [])
-  Meta.allow_tag_with_these_attributes("em", [])
-  Meta.allow_tag_with_these_attributes("i", [])
-  Meta.allow_tag_with_these_attributes("li", [])
-  Meta.allow_tag_with_these_attributes("ol", [])
-  Meta.allow_tag_with_these_attributes("p", [])
-  Meta.allow_tag_with_these_attributes("pre", [])
-  Meta.allow_tag_with_these_attributes("strong", [])
-  Meta.allow_tag_with_these_attributes("sub", [])
-  Meta.allow_tag_with_these_attributes("sup", [])
-  Meta.allow_tag_with_these_attributes("u", [])
-  Meta.allow_tag_with_these_attributes("ul", [])
+  Meta.allow_tag_with_these_attributes(:b, [])
+  Meta.allow_tag_with_these_attributes(:blockquote, [])
+  Meta.allow_tag_with_these_attributes(:br, [])
+  Meta.allow_tag_with_these_attributes(:code, [])
+  Meta.allow_tag_with_these_attributes(:del, [])
+  Meta.allow_tag_with_these_attributes(:em, [])
+  Meta.allow_tag_with_these_attributes(:i, [])
+  Meta.allow_tag_with_these_attributes(:li, [])
+  Meta.allow_tag_with_these_attributes(:ol, [])
+  Meta.allow_tag_with_these_attributes(:p, [])
+  Meta.allow_tag_with_these_attributes(:pre, [])
+  Meta.allow_tag_with_these_attributes(:strong, [])
+  Meta.allow_tag_with_these_attributes(:sub, [])
+  Meta.allow_tag_with_these_attributes(:sup, [])
+  Meta.allow_tag_with_these_attributes(:u, [])
+  Meta.allow_tag_with_these_attributes(:ul, [])
 
-  Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
-  Meta.allow_tag_with_these_attributes("span", [])
+  Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"])
+  Meta.allow_tag_with_these_attributes(:span, [])
 
   @allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images])
 
   if @allow_inline_images do
     # restrict img tags to http/https only, because of MediaProxy.
-    Meta.allow_tag_with_uri_attributes("img", ["src"], ["http", "https"])
+    Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])
 
-    Meta.allow_tag_with_these_attributes("img", [
+    Meta.allow_tag_with_these_attributes(:img, [
       "width",
       "height",
       "class",
@@ -228,24 +229,24 @@ defmodule Pleroma.HTML.Scrubber.Default do
   end
 
   if Pleroma.Config.get([:markup, :allow_tables]) do
-    Meta.allow_tag_with_these_attributes("table", [])
-    Meta.allow_tag_with_these_attributes("tbody", [])
-    Meta.allow_tag_with_these_attributes("td", [])
-    Meta.allow_tag_with_these_attributes("th", [])
-    Meta.allow_tag_with_these_attributes("thead", [])
-    Meta.allow_tag_with_these_attributes("tr", [])
+    Meta.allow_tag_with_these_attributes(:table, [])
+    Meta.allow_tag_with_these_attributes(:tbody, [])
+    Meta.allow_tag_with_these_attributes(:td, [])
+    Meta.allow_tag_with_these_attributes(:th, [])
+    Meta.allow_tag_with_these_attributes(:thead, [])
+    Meta.allow_tag_with_these_attributes(:tr, [])
   end
 
   if Pleroma.Config.get([:markup, :allow_headings]) do
-    Meta.allow_tag_with_these_attributes("h1", [])
-    Meta.allow_tag_with_these_attributes("h2", [])
-    Meta.allow_tag_with_these_attributes("h3", [])
-    Meta.allow_tag_with_these_attributes("h4", [])
-    Meta.allow_tag_with_these_attributes("h5", [])
+    Meta.allow_tag_with_these_attributes(:h1, [])
+    Meta.allow_tag_with_these_attributes(:h2, [])
+    Meta.allow_tag_with_these_attributes(:h3, [])
+    Meta.allow_tag_with_these_attributes(:h4, [])
+    Meta.allow_tag_with_these_attributes(:h5, [])
   end
 
   if Pleroma.Config.get([:markup, :allow_fonts]) do
-    Meta.allow_tag_with_these_attributes("font", ["face"])
+    Meta.allow_tag_with_these_attributes(:font, ["face"])
   end
 
   Meta.strip_everything_not_covered()
@@ -258,7 +259,7 @@ defmodule Pleroma.HTML.Transform.MediaProxy do
 
   def before_scrub(html), do: html
 
-  def scrub_attribute("img", {"src", "http" <> target}) do
+  def scrub_attribute(:img, {"src", "http" <> target}) do
     media_url =
       ("http" <> target)
       |> MediaProxy.url()
@@ -268,16 +269,16 @@ def scrub_attribute("img", {"src", "http" <> target}) do
 
   def scrub_attribute(_tag, attribute), do: attribute
 
-  def scrub({"img", attributes, children}) do
+  def scrub({:img, attributes, children}) do
     attributes =
       attributes
-      |> Enum.map(fn attr -> scrub_attribute("img", attr) end)
+      |> Enum.map(fn attr -> scrub_attribute(:img, attr) end)
       |> Enum.reject(&is_nil(&1))
 
-    {"img", attributes, children}
+    {:img, attributes, children}
   end
 
-  def scrub({:comment, _children}), do: ""
+  def scrub({:comment, _text, _children}), do: ""
 
   def scrub({tag, attributes, children}), do: {tag, attributes, children}
   def scrub({_tag, children}), do: children
@@ -298,9 +299,9 @@ defmodule Pleroma.HTML.Scrubber.LinksOnly do
   Meta.strip_comments()
 
   # links
-  Meta.allow_tag_with_uri_attributes("a", ["href"], @valid_schemes)
+  Meta.allow_tag_with_uri_attributes(:a, ["href"], @valid_schemes)
 
-  Meta.allow_tag_with_this_attribute_values("a", "rel", [
+  Meta.allow_tag_with_this_attribute_values(:a, "rel", [
     "tag",
     "nofollow",
     "noopener",
@@ -309,6 +310,6 @@ defmodule Pleroma.HTML.Scrubber.LinksOnly do
     "ugc"
   ])
 
-  Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+  Meta.allow_tag_with_these_attributes(:a, ["name", "title"])
   Meta.strip_everything_not_covered()
 end
diff --git a/test/emoji/formatter_test.exs b/test/emoji/formatter_test.exs
index 6d25fc453..3e37ae3f0 100644
--- a/test/emoji/formatter_test.exs
+++ b/test/emoji/formatter_test.exs
@@ -12,7 +12,7 @@ test "it adds cool emoji" do
       text = "I love :firefox:"
 
       expected_result =
-        "I love <img class=\"emoji\" alt=\"firefox\" title=\"firefox\" src=\"/emoji/Firefox.gif\" />"
+        "I love <img class=\"emoji\" alt=\"firefox\" title=\"firefox\" src=\"/emoji/Firefox.gif\"/>"
 
       assert Formatter.emojify(text) == expected_result
     end
diff --git a/test/html_test.exs b/test/html_test.exs
index 306ad3b3b..f0869534c 100644
--- a/test/html_test.exs
+++ b/test/html_test.exs
@@ -21,31 +21,31 @@ defmodule Pleroma.HTMLTest do
   """
 
   @html_onerror_sample """
-    <img src="http://example.com/image.jpg" onerror="alert('hacked')">
+  <img src="http://example.com/image.jpg" onerror="alert('hacked')">
   """
 
   @html_span_class_sample """
-    <span class="animate-spin">hi</span>
+  <span class="animate-spin">hi</span>
   """
 
   @html_span_microformats_sample """
-    <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>
+  <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>
   """
 
   @html_span_invalid_microformats_sample """
-    <span class="h-card"><a class="u-url mention animate-spin">@<span>foo</span></a></span>
+  <span class="h-card"><a class="u-url mention animate-spin">@<span>foo</span></a></span>
   """
 
   describe "StripTags scrubber" do
     test "works as expected" do
       expected = """
-      this is in bold
+        this is in bold
         this is a paragraph
         this is a linebreak
-        this is a link with allowed "rel" attribute: example.com
-        this is a link with not allowed "rel" attribute: example.com
+        this is a link with allowed &quot;rel&quot; attribute: example.com
+        this is a link with not allowed &quot;rel&quot; attribute: example.com
         this is an image: 
-        alert('hacked')
+        alert(&#39;hacked&#39;)
       """
 
       assert expected == HTML.strip_tags(@html_sample)
@@ -61,13 +61,13 @@ test "does not allow attribute-based XSS" do
   describe "TwitterText scrubber" do
     test "normalizes HTML as expected" do
       expected = """
-      this is in bold
+        this is in bold
         <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')
+        this is a linebreak<br/>
+        this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
+        this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
+        this is an image: <img src="http://example.com/image.jpg"/><br/>
+        alert(&#39;hacked&#39;)
       """
 
       assert expected == HTML.filter_tags(@html_sample, Pleroma.HTML.Scrubber.TwitterText)
@@ -75,7 +75,7 @@ test "normalizes HTML as expected" do
 
     test "does not allow attribute-based XSS" do
       expected = """
-      <img src="http://example.com/image.jpg" />
+      <img src="http://example.com/image.jpg"/>
       """
 
       assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.TwitterText)
@@ -115,13 +115,13 @@ test "filters invalid microformats markup" do
   describe "default scrubber" do
     test "normalizes HTML as expected" do
       expected = """
-      <b>this is in bold</b>
+        <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')
+        this is a linebreak<br/>
+        this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
+        this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
+        this is an image: <img src="http://example.com/image.jpg"/><br/>
+        alert(&#39;hacked&#39;)
       """
 
       assert expected == HTML.filter_tags(@html_sample, Pleroma.HTML.Scrubber.Default)
@@ -129,7 +129,7 @@ test "normalizes HTML as expected" do
 
     test "does not allow attribute-based XSS" do
       expected = """
-      <img src="http://example.com/image.jpg" />
+      <img src="http://example.com/image.jpg"/>
       """
 
       assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.Default)
diff --git a/test/web/activity_pub/mrf/normalize_markup_test.exs b/test/web/activity_pub/mrf/normalize_markup_test.exs
index 3916a1f35..0207be56b 100644
--- a/test/web/activity_pub/mrf/normalize_markup_test.exs
+++ b/test/web/activity_pub/mrf/normalize_markup_test.exs
@@ -20,11 +20,11 @@ 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')
+    this is a linebreak<br/>
+    this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
+    this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
+    this is an image: <img src="http://example.com/image.jpg"/><br/>
+    alert(&#39;hacked&#39;)
     """
 
     message = %{"type" => "Create", "object" => %{"content" => @html_sample}}
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 1d2f20617..212b00cbb 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -140,7 +140,7 @@ test "it filters out obviously bad tags when accepting a post as HTML" do
 
       object = Object.normalize(activity)
 
-      assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
+      assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
     end
 
     test "it filters out obviously bad tags when accepting a post as Markdown" do
@@ -156,7 +156,7 @@ test "it filters out obviously bad tags when accepting a post as Markdown" do
 
       object = Object.normalize(activity)
 
-      assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
+      assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
     end
 
     test "it does not allow replies to direct messages that are not direct messages themselves" do

From 9cde3321a3b4ac6a8df16d7e59f169b545afe55f Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 01:21:00 +0300
Subject: [PATCH 05/12] Add fast_sanitize to dependencies

---
 mix.exs  |  1 +
 mix.lock | 49 ++++++++++++++++++++++++++-----------------------
 2 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/mix.exs b/mix.exs
index 705d56f0e..0e7c6a6f8 100644
--- a/mix.exs
+++ b/mix.exs
@@ -109,6 +109,7 @@ defp deps do
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
       {:html_sanitize_ex, "~> 1.3.0"},
+      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "2820d841393b3c2f2183d0377f572bf00f513b7c"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},
diff --git a/mix.lock b/mix.lock
index 5f740638c..18e2572dd 100644
--- a/mix.lock
+++ b/mix.lock
@@ -13,44 +13,45 @@
   "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"},
   "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
   "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
-  "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
-  "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
+  "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
+  "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"},
   "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
-  "crontab": {:hex, :crontab, "1.1.7", "b9219f0bdc8678b94143655a8f229716c5810c0636a4489f98c0956137e53985", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
+  "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
   "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"},
   "db_connection": {:hex, :db_connection, "2.1.1", "a51e8a2ee54ef2ae6ec41a668c85787ed40cb8944928c191280fe34c15b76ae5", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
   "decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
   "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"},
-  "earmark": {:hex, :earmark, "1.3.6", "ce1d0675e10a5bb46b007549362bd3f5f08908843957687d8484fe7f37466b19", [:mix], [], "hexpm"},
-  "ecto": {:hex, :ecto, "3.2.0", "940e2598813f205223d60c78d66e514afe1db5167ed8075510a59e496619cfb5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
+  "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
+  "ecto": {:hex, :ecto, "3.2.3", "51274df79862845b388733fddcf6f107d0c8c86e27abe7131fa98f8d30761bda", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
   "ecto_sql": {:hex, :ecto_sql, "3.2.0", "751cea597e8deb616084894dd75cbabfdbe7255ff01e8c058ca13f0353a3921b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"},
-  "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"},
+  "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"},
   "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
-  "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
-  "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
+  "ex_aws": {:hex, :ex_aws, "2.1.1", "1e4de2106cfbf4e837de41be41cd15813eabc722315e388f0d6bb3732cec47cd", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
+  "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.2", "c0258bbdfea55de4f98f0b2f0ca61fe402cc696f573815134beb1866e778f47b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
   "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm"},
   "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
   "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
-  "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
+  "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
+  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "2820d841393b3c2f2183d0377f572bf00f513b7c", [ref: "2820d841393b3c2f2183d0377f572bf00f513b7c"]},
   "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
-  "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"},
-  "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"},
+  "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
+  "gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"},
   "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
-  "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
+  "gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"},
   "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
   "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"},
   "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
   "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
-  "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
+  "httpoison": {:hex, :httpoison, "1.6.1", "2ce5bf6e535cd0ab02e905ba8c276580bab80052c5c549f53ddea52d72e81f33", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
   "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
   "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm"},
   "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
-  "joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"},
+  "joken": {:hex, :joken, "2.1.0", "bf21a73105d82649f617c5e59a7f8919aa47013d2519ebcc39d998d8d12adda9", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"},
   "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
   "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
   "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
@@ -63,16 +64,18 @@
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
   "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
+  "myhtmlex": {:git, "https://github.com/rinpatch/myhtmlex.git", "d973dfb1b252b1c6e6eddddc18c0895aa977091c", [ref: "d973dfb1b252b1c6e6eddddc18c0895aa977091c", submodules: true]},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
+  "nodex": {:git, "https://github.com/rinpatch/nodex", "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8", [ref: "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8"]},
   "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
-  "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"},
-  "phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
+  "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"},
+  "phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
-  "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+  "phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"},
   "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"},
-  "plug": {:hex, :plug, "1.8.2", "0bcce1daa420f189a6491f3940cc77ea7fb1919761175c9c3b59800d897440fc", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
+  "plug": {:hex, :plug, "1.8.3", "12d5f9796dc72e8ac9614e94bda5e51c4c028d0d428e9297650d09e15a684478", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
   "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
   "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
@@ -80,7 +83,7 @@
   "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"},
   "postgrex": {:hex, :postgrex, "0.15.1", "23ce3417de70f4c0e9e7419ad85bdabcc6860a6925fe2c6f3b1b5b1e8e47bf2f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
   "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"},
-  "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"},
+  "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"},
   "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"},
   "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"},
   "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"},
@@ -92,16 +95,16 @@
   "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
   "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"},
   "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"},
-  "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
+  "swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
   "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
   "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
   "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
   "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
   "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
-  "tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
-  "ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+  "tzdata": {:hex, :tzdata, "0.5.22", "f2ba9105117ee0360eae2eca389783ef7db36d533899b2e84559404dbc77ebb8", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
+  "ueberauth": {:hex, :ueberauth, "0.6.2", "25a31111249d60bad8b65438b2306a4dc91f3208faa62f5a8c33e8713989b2e8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
   "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"},
-  "web_push_encryption": {:hex, :web_push_encryption, "0.2.1", "d42cecf73420d9dc0053ba3299cc8c8d6ff2be2487d67ca2a57265868e4d9a98", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
+  "web_push_encryption": {:hex, :web_push_encryption, "0.2.3", "a0ceab85a805a30852f143d22d71c434046fbdbafbc7292e7887cec500826a80", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
   "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []},
 }

From 41c23251f16ea1951cfea7da3fc809b9e71c25e8 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 13:05:20 +0300
Subject: [PATCH 06/12] Bump fast_sanitize version

---
 mix.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mix.exs b/mix.exs
index 0e7c6a6f8..faff7033c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -109,7 +109,7 @@ defp deps do
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
       {:html_sanitize_ex, "~> 1.3.0"},
-      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "2820d841393b3c2f2183d0377f572bf00f513b7c"},
+      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "0d996cac23e86afc342a24047e77443661bbbb13"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},

From 7358cf1f2041329f0924fc60106dfb5ec0288feb Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 17:00:03 +0300
Subject: [PATCH 07/12] Bump fast_sanitize dependency

---
 mix.exs  | 2 +-
 mix.lock | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mix.exs b/mix.exs
index faff7033c..e46f9b2a4 100644
--- a/mix.exs
+++ b/mix.exs
@@ -109,7 +109,7 @@ defp deps do
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
       {:html_sanitize_ex, "~> 1.3.0"},
-      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "0d996cac23e86afc342a24047e77443661bbbb13"},
+      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "a23fbf1bd77b002a8f72a53c39c53b176f98f81a"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},
diff --git a/mix.lock b/mix.lock
index 18e2572dd..01f6860a6 100644
--- a/mix.lock
+++ b/mix.lock
@@ -36,7 +36,7 @@
   "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
   "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
-  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "2820d841393b3c2f2183d0377f572bf00f513b7c", [ref: "2820d841393b3c2f2183d0377f572bf00f513b7c"]},
+  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "a23fbf1bd77b002a8f72a53c39c53b176f98f81a", [ref: "a23fbf1bd77b002a8f72a53c39c53b176f98f81a"]},
   "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
   "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
@@ -64,7 +64,7 @@
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
   "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
-  "myhtmlex": {:git, "https://github.com/rinpatch/myhtmlex.git", "d973dfb1b252b1c6e6eddddc18c0895aa977091c", [ref: "d973dfb1b252b1c6e6eddddc18c0895aa977091c", submodules: true]},
+  "myhtmlex": {:git, "https://github.com/rinpatch/myhtmlex.git", "2031aeb1098e128f35a6a0b54841e259fc7672d5", [ref: "2031aeb1098e128f35a6a0b54841e259fc7672d5", submodules: true]},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
   "nodex": {:git, "https://github.com/rinpatch/nodex", "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8", [ref: "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8"]},
   "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},

From 61400d7eb785f41ab853f42d0a221357253c39eb Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 20:49:32 +0300
Subject: [PATCH 08/12] Fix XSS emoji test

---
 mix.exs                       | 2 +-
 mix.lock                      | 6 +++---
 test/emoji/formatter_test.exs | 5 +----
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/mix.exs b/mix.exs
index e46f9b2a4..2e64b79ad 100644
--- a/mix.exs
+++ b/mix.exs
@@ -109,7 +109,7 @@ defp deps do
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
       {:html_sanitize_ex, "~> 1.3.0"},
-      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "a23fbf1bd77b002a8f72a53c39c53b176f98f81a"},
+      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},
diff --git a/mix.lock b/mix.lock
index 01f6860a6..6cbe54a76 100644
--- a/mix.lock
+++ b/mix.lock
@@ -36,7 +36,7 @@
   "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
   "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
-  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "a23fbf1bd77b002a8f72a53c39c53b176f98f81a", [ref: "a23fbf1bd77b002a8f72a53c39c53b176f98f81a"]},
+  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c", [ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"]},
   "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
   "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
@@ -64,9 +64,9 @@
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
   "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
-  "myhtmlex": {:git, "https://github.com/rinpatch/myhtmlex.git", "2031aeb1098e128f35a6a0b54841e259fc7672d5", [ref: "2031aeb1098e128f35a6a0b54841e259fc7672d5", submodules: true]},
+  "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "eafbba443260c0055ef2da3918b351b112ff356f", [ref: "eafbba443260c0055ef2da3918b351b112ff356f", submodules: true]},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
-  "nodex": {:git, "https://github.com/rinpatch/nodex", "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8", [ref: "12ca7a2c5b5791f1e847d73ed646cf006d4c8ca8"]},
+  "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "2927091d96900fb76f6bc897e46a6abb9070ebbd", [ref: "2927091d96900fb76f6bc897e46a6abb9070ebbd"]},
   "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"},
diff --git a/test/emoji/formatter_test.exs b/test/emoji/formatter_test.exs
index 3e37ae3f0..fda80d470 100644
--- a/test/emoji/formatter_test.exs
+++ b/test/emoji/formatter_test.exs
@@ -28,10 +28,7 @@ test "it does not add XSS emoji" do
         }
         |> Pleroma.Emoji.build()
 
-      expected_result =
-        "I love <img class=\"emoji\" alt=\"\" title=\"\" src=\"https://placehold.it/1x1\" />"
-
-      assert Formatter.emojify(text, [{custom_emoji.code, custom_emoji}]) == expected_result
+      refute Formatter.emojify(text, [{custom_emoji.code, custom_emoji}]) =~ text
     end
   end
 

From 77cfb08b8c4c07406af8b338ce010307f6af75cb Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 29 Oct 2019 20:58:54 +0300
Subject: [PATCH 09/12] Remove commented-out code

---
 lib/pleroma/html.ex | 3 +--
 mix.exs             | 4 +++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index fd0495049..294bc75f9 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -3,7 +3,6 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.HTML do
-
   defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber]
   defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
   defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]
@@ -39,6 +38,7 @@ def get_cached_scrubbed_html_for_activity(
         callback \\ fn x -> x end
       ) do
     key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}"
+
     Cachex.fetch!(:scrubber_cache, key, fn _key ->
       object = Pleroma.Object.normalize(activity)
       ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback)
@@ -168,7 +168,6 @@ defmodule Pleroma.HTML.Scrubber.Default do
 
   @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
 
-#  Meta.remove_cdata_sections_before_scrub()
   Meta.strip_comments()
 
   Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes)
diff --git a/mix.exs b/mix.exs
index 2e64b79ad..91b79dde2 100644
--- a/mix.exs
+++ b/mix.exs
@@ -109,7 +109,9 @@ defp deps do
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
       {:html_sanitize_ex, "~> 1.3.0"},
-      {:fast_sanitize, git: "https://git.pleroma.social/pleroma/fast_sanitize.git", ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"},
+      {:fast_sanitize,
+       git: "https://git.pleroma.social/pleroma/fast_sanitize.git",
+       ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},

From ae59b38203b5358ddbf7f2cc5e2cbc816d171452 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Wed, 30 Oct 2019 09:20:13 +0300
Subject: [PATCH 10/12] Rip out the rest of htmlsanitizeex

---
 lib/pleroma/bbs/handler.ex                       | 3 ++-
 lib/pleroma/html.ex                              | 9 ++++-----
 mix.exs                                          | 1 -
 test/web/mastodon_api/views/status_view_test.exs | 9 +++++----
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
index fa838a4e4..386afee89 100644
--- a/lib/pleroma/bbs/handler.ex
+++ b/lib/pleroma/bbs/handler.ex
@@ -5,6 +5,7 @@
 defmodule Pleroma.BBS.Handler do
   use Sshd.ShellHandler
   alias Pleroma.Activity
+  alias Pleroma.HTML
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.CommonAPI
 
@@ -44,7 +45,7 @@ defp loop(state) do
   def puts_activity(activity) do
     status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
     IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
-    IO.puts(HtmlSanitizeEx.strip_tags(status.content))
+    IO.puts(HTML.strip_tags(status.content))
     IO.puts("")
   end
 
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 294bc75f9..997e965f0 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -108,8 +108,8 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
 
   @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
 
-  require HtmlSanitizeEx.Scrubber.Meta
-  alias HtmlSanitizeEx.Scrubber.Meta
+  require FastSanitize.Sanitizer.Meta
+  alias FastSanitize.Sanitizer.Meta
 
   Meta.strip_comments()
 
@@ -291,10 +291,9 @@ defmodule Pleroma.HTML.Scrubber.LinksOnly do
 
   @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
 
-  require HtmlSanitizeEx.Scrubber.Meta
-  alias HtmlSanitizeEx.Scrubber.Meta
+  require FastSanitize.Sanitizer.Meta
+  alias FastSanitize.Sanitizer.Meta
 
-  Meta.remove_cdata_sections_before_scrub()
   Meta.strip_comments()
 
   # links
diff --git a/mix.exs b/mix.exs
index 91b79dde2..e85c2aa50 100644
--- a/mix.exs
+++ b/mix.exs
@@ -108,7 +108,6 @@ defp deps do
       {:comeonin, "~> 4.1.1"},
       {:pbkdf2_elixir, "~> 0.12.3"},
       {:trailing_format_plug, "~> 0.0.7"},
-      {:html_sanitize_ex, "~> 1.3.0"},
       {:fast_sanitize,
        git: "https://git.pleroma.social/pleroma/fast_sanitize.git",
        ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"},
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index c200ad8fe..7526f2f27 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
 
   alias Pleroma.Activity
   alias Pleroma.Bookmark
+  alias Pleroma.HTML
   alias Pleroma.Object
   alias Pleroma.Repo
   alias Pleroma.User
@@ -107,7 +108,7 @@ test "a note activity" do
       in_reply_to_account_id: nil,
       card: nil,
       reblog: nil,
-      content: HtmlSanitizeEx.basic_html(object_data["content"]),
+      content: HTML.filter_tags(object_data["content"]),
       created_at: created_at,
       reblogs_count: 0,
       replies_count: 0,
@@ -119,7 +120,7 @@ test "a note activity" do
       pinned: false,
       sensitive: false,
       poll: nil,
-      spoiler_text: HtmlSanitizeEx.basic_html(object_data["summary"]),
+      spoiler_text: HTML.filter_tags(object_data["summary"]),
       visibility: "public",
       media_attachments: [],
       mentions: [],
@@ -146,8 +147,8 @@ test "a note activity" do
         local: true,
         conversation_id: convo_id,
         in_reply_to_account_acct: nil,
-        content: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["content"])},
-        spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])},
+        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

From bd0f7f2e09ec4d2883b87fd3c5d3784319de7cc7 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@FreeBSD.org>
Date: Wed, 30 Oct 2019 17:57:08 -0500
Subject: [PATCH 11/12] Bump fast_sanitize dependency so this builds on more
 than just Linux

---
 mix.exs  | 2 +-
 mix.lock | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/mix.exs b/mix.exs
index e85c2aa50..66cea7b89 100644
--- a/mix.exs
+++ b/mix.exs
@@ -110,7 +110,7 @@ defp deps do
       {:trailing_format_plug, "~> 0.0.7"},
       {:fast_sanitize,
        git: "https://git.pleroma.social/pleroma/fast_sanitize.git",
-       ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"},
+       ref: "d5c47d580a018c4e7f6fadfca63834b9ae28c18c"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},
diff --git a/mix.lock b/mix.lock
index 6cbe54a76..802cb2959 100644
--- a/mix.lock
+++ b/mix.lock
@@ -36,7 +36,7 @@
   "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
   "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
-  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c", [ref: "37f55e2bbe6eb44e8a9c4b3831a5ce73a2f6955c"]},
+  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "d5c47d580a018c4e7f6fadfca63834b9ae28c18c", [ref: "d5c47d580a018c4e7f6fadfca63834b9ae28c18c"]},
   "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
   "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
@@ -64,9 +64,9 @@
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
   "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
-  "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "eafbba443260c0055ef2da3918b351b112ff356f", [ref: "eafbba443260c0055ef2da3918b351b112ff356f", submodules: true]},
+  "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "99140014f5da4081d2db437e6d769b81c70bf510", [ref: "99140014f5da4081d2db437e6d769b81c70bf510", submodules: true]},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
-  "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "2927091d96900fb76f6bc897e46a6abb9070ebbd", [ref: "2927091d96900fb76f6bc897e46a6abb9070ebbd"]},
+  "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
   "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"},

From 55ef88ef95ecda94ea416bd3a8492f992488ea83 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Fri, 1 Nov 2019 20:58:24 +0300
Subject: [PATCH 12/12] Bump fast_sanitize version

---
 mix.exs  | 2 +-
 mix.lock | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mix.exs b/mix.exs
index 66cea7b89..f3ef8d955 100644
--- a/mix.exs
+++ b/mix.exs
@@ -110,7 +110,7 @@ defp deps do
       {:trailing_format_plug, "~> 0.0.7"},
       {:fast_sanitize,
        git: "https://git.pleroma.social/pleroma/fast_sanitize.git",
-       ref: "d5c47d580a018c4e7f6fadfca63834b9ae28c18c"},
+       ref: "cb92cc6f63b183863f5cecb0c740c34642da5216"},
       {:html_entities, "~> 0.4"},
       {:phoenix_html, "~> 2.10"},
       {:calendar, "~> 0.17.4"},
diff --git a/mix.lock b/mix.lock
index 802cb2959..c867a9605 100644
--- a/mix.lock
+++ b/mix.lock
@@ -36,7 +36,7 @@
   "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
   "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
-  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "d5c47d580a018c4e7f6fadfca63834b9ae28c18c", [ref: "d5c47d580a018c4e7f6fadfca63834b9ae28c18c"]},
+  "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "cb92cc6f63b183863f5cecb0c740c34642da5216", [ref: "cb92cc6f63b183863f5cecb0c740c34642da5216"]},
   "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
   "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
@@ -64,7 +64,7 @@
   "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
   "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
-  "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "99140014f5da4081d2db437e6d769b81c70bf510", [ref: "99140014f5da4081d2db437e6d769b81c70bf510", submodules: true]},
+  "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "4288bda52c53a2d416afa09e1007a881eb2dafab", [ref: "4288bda52c53a2d416afa09e1007a881eb2dafab", submodules: true]},
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"},
   "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
   "oban": {:hex, :oban, "0.8.1", "4bbf62eb1829f856d69aeb5069ac7036afe07db8221a17de2a9169cc7a58a318", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},