# Pleroma: A lightweight social networking server # Copyright © 2017-2023 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTMLTest do alias Pleroma.HTML alias Pleroma.Object alias Pleroma.Web.CommonAPI use Pleroma.DataCase, async: true import Pleroma.Factory @html_sample """ this is in bold

this is a paragraph

this is a linebreak
this is a link with allowed "rel" attribute: this is a link with not allowed "rel" attribute: example.com this is an image:
this is an inline emoji:
""" @html_onerror_sample """ """ @html_stillimage_sample """ """ @html_span_class_sample """ hi """ @html_span_microformats_sample """ @foo """ @html_span_invalid_microformats_sample """ @foo """ describe "StripTags scrubber" do test "works as expected" do expected = """ 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 an image: this is an inline emoji: alert('hacked') """ assert expected == HTML.strip_tags(@html_sample) end test "does not allow attribute-based XSS" do expected = "\n" assert expected == HTML.strip_tags(@html_onerror_sample) end end describe "TwitterText scrubber" do test "normalizes HTML as expected" do expected = """ this is in bold

this is a paragraph

this is a linebreak
this is a link with allowed "rel" attribute: this is a link with not allowed "rel" attribute: example.com this is an image:
this is an inline emoji:
alert('hacked') """ assert expected == HTML.filter_tags(@html_sample, Pleroma.HTML.Scrubber.TwitterText) end test "does not allow attribute-based XSS" do expected = """ """ assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.TwitterText) end test "does not allow spans with invalid classes" do expected = """ hi """ assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.TwitterText) end test "does not allow images with invalid classes" do expected = """ """ assert expected == HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText) end test "does allow microformats" do expected = """ @foo """ assert expected == HTML.filter_tags(@html_span_microformats_sample, Pleroma.HTML.Scrubber.TwitterText) end test "filters invalid microformats markup" do expected = """ @foo """ assert expected == HTML.filter_tags( @html_span_invalid_microformats_sample, Pleroma.HTML.Scrubber.TwitterText ) end end describe "default scrubber" do test "normalizes HTML as expected" do expected = """ this is in bold

this is a paragraph

this is a linebreak
this is a link with allowed "rel" attribute: this is a link with not allowed "rel" attribute: example.com this is an image:
this is an inline emoji:
alert('hacked') """ assert expected == HTML.filter_tags(@html_sample, Pleroma.HTML.Scrubber.Default) end test "does not allow attribute-based XSS" do expected = """ """ assert expected == HTML.filter_tags(@html_onerror_sample, Pleroma.HTML.Scrubber.Default) end test "does not allow spans with invalid classes" do expected = """ hi """ assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.Default) end test "does not allow images with invalid classes" do expected = """ """ assert expected == HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText) end test "does allow microformats" do expected = """ @foo """ assert expected == HTML.filter_tags(@html_span_microformats_sample, Pleroma.HTML.Scrubber.Default) end test "filters invalid microformats markup" do expected = """ @foo """ assert expected == HTML.filter_tags( @html_span_invalid_microformats_sample, Pleroma.HTML.Scrubber.Default ) end end describe "extract_first_external_url_from_object" do test "extracts the url" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{ status: "I think I just found the best github repo https://github.com/komeiji-satori/Dress" }) object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://github.com/komeiji-satori/Dress" end test "skips mentions" do user = insert(:user) other_user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{ status: "@#{other_user.nickname} install misskey! https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md" }) object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md" refute url == other_user.ap_id end test "skips hashtags" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{ status: "#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" }) object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" end test "skips microformats hashtags" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{ status: "#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140", content_type: "text/html" }) object = Object.normalize(activity, fetch: false) {:ok, url} = HTML.extract_first_external_url_from_object(object) assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140" end test "does not crash when there is an HTML entity in a link" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "\"http://cofe.com/?boomer=ok&foo=bar\""}) object = Object.normalize(activity, fetch: false) assert {:ok, nil} = HTML.extract_first_external_url_from_object(object) end test "skips attachment links" do user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{ status: "image.png" }) object = Object.normalize(activity, fetch: false) assert {:ok, nil} = HTML.extract_first_external_url_from_object(object) end end end