From 8ae9424edb753097f4c2093bbded946f938d99e7 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 01:10:53 +0000 Subject: [PATCH 1/7] html: default to using normal scrub policy if provided scrub policy is nil --- lib/pleroma/html.ex | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index ab62dd1da..878fac28c 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -12,17 +12,19 @@ def get_scrubbers() do |> get_scrubbers end - def filter_tags(html, scrubber) do - html |> Scrubber.scrub(scrubber) - end - - def filter_tags(html) do + def filter_tags(html, nil) do get_scrubbers() |> Enum.reduce(html, fn scrubber, html -> filter_tags(html, scrubber) end) end + def filter_tags(html, scrubber) do + html |> Scrubber.scrub(scrubber) + end + + def filter_tags(html), do: filter_tags(html, nil) + def strip_tags(html) do html |> Scrubber.scrub(Scrubber.StripTags) end From 735cdfb8481af7ff78a0637fe5045d3f10961141 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 01:37:05 +0000 Subject: [PATCH 2/7] user: add User.html_filter_policy() --- lib/pleroma/user.ex | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e3e6aa0d8..487bfce32 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -669,6 +669,12 @@ def delete(%User{} = user) do :ok end + def html_filter_policy(%User{info: %{"no_rich_text" => true}}) do + Pleroma.HTML.Scrubber.TwitterText + end + + def html_filter_policy(_), do: nil + def get_or_fetch_by_ap_id(ap_id) do user = get_by_ap_id(ap_id) From 2f5b026548a52d700a15f52243596f7010d3af57 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 02:13:54 +0000 Subject: [PATCH 3/7] twitter api: add support for user-specified html policy --- .../web/twitter_api/representers/activity_representer.ex | 2 +- lib/pleroma/web/twitter_api/views/activity_view.ex | 2 +- lib/pleroma/web/twitter_api/views/user_view.ex | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex index 5c4eed671..b21bbb205 100644 --- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex @@ -168,7 +168,7 @@ def to_map( {summary, content} = ActivityView.render_content(object) html = - HTML.filter_tags(content) + HTML.filter_tags(content, User.html_filter_policy(opts[:for])) |> Formatter.emojify(object["emoji"]) video = diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 666a35a24..b9fd062d6 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -233,7 +233,7 @@ def render( {summary, content} = render_content(object) html = - HTML.filter_tags(content) + HTML.filter_tags(content, User.html_filter_policy(opts[:for])) |> Formatter.emojify(object["emoji"]) %{ diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index f2641047f..cec9e11a0 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -40,7 +40,7 @@ def render("user.json", %{user: user = %User{}} = assigns) do data = %{ "created_at" => user.inserted_at |> Utils.format_naive_asctime(), "description" => HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), - "description_html" => HTML.filter_tags(user.bio), + "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(assigns[:for])), "favourites_count" => 0, "followers_count" => user_info[:follower_count], "following" => following, From 958e085acb88d8bdcac4834a290238bc8527e678 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 02:14:25 +0000 Subject: [PATCH 4/7] mastodon api: add support for user-supplied html policy --- .../mastodon_api/mastodon_api_controller.ex | 20 +++++++++---------- .../web/mastodon_api/views/account_view.ex | 6 ++++-- .../web/mastodon_api/views/status_view.ex | 14 +++++++------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 3d292182d..47ae61b5b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -98,7 +98,7 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do CommonAPI.update(user) end - json(conn, AccountView.render("account.json", %{user: user})) + json(conn, AccountView.render("account.json", %{user: user, for: user})) else _e -> conn @@ -108,13 +108,13 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end def verify_credentials(%{assigns: %{user: user}} = conn, _) do - account = AccountView.render("account.json", %{user: user}) + account = AccountView.render("account.json", %{user: user, for: user}) json(conn, account) end - def user(conn, %{"id" => id}) do + def user(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do with %User{} = user <- Repo.get(User, id) do - account = AccountView.render("account.json", %{user: user}) + account = AccountView.render("account.json", %{user: user, for: for_user}) json(conn, account) else _e -> @@ -588,7 +588,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do with %User{} = followed <- Repo.get_by(User, nickname: uri), {:ok, follower} <- User.maybe_direct_follow(follower, followed), {:ok, _activity} <- ActivityPub.follow(follower, followed) do - render(conn, AccountView, "account.json", %{user: followed}) + render(conn, AccountView, "account.json", %{user: followed, for: follower}) else {:error, message} -> conn @@ -858,7 +858,7 @@ def index(%{assigns: %{user: user}} = conn, _params) do if user && token do mastodon_emoji = mastodonized_emoji() - accounts = Map.put(%{}, user.id, AccountView.render("account.json", %{user: user})) + accounts = Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user})) initial_state = %{ @@ -1038,7 +1038,7 @@ def render_notification(user, %{id: id, activity: activity, inserted_at: created id: id, type: "mention", created_at: created_at, - account: AccountView.render("account.json", %{user: actor}), + account: AccountView.render("account.json", %{user: actor, for: user}), status: StatusView.render("status.json", %{activity: activity, for: user}) } @@ -1049,7 +1049,7 @@ def render_notification(user, %{id: id, activity: activity, inserted_at: created id: id, type: "favourite", created_at: created_at, - account: AccountView.render("account.json", %{user: actor}), + account: AccountView.render("account.json", %{user: actor, for: user}), status: StatusView.render("status.json", %{activity: liked_activity, for: user}) } @@ -1060,7 +1060,7 @@ def render_notification(user, %{id: id, activity: activity, inserted_at: created id: id, type: "reblog", created_at: created_at, - account: AccountView.render("account.json", %{user: actor}), + account: AccountView.render("account.json", %{user: actor, for: user}), status: StatusView.render("status.json", %{activity: announced_activity, for: user}) } @@ -1069,7 +1069,7 @@ def render_notification(user, %{id: id, activity: activity, inserted_at: created id: id, type: "follow", created_at: created_at, - account: AccountView.render("account.json", %{user: actor}) + account: AccountView.render("account.json", %{user: actor, for: user}) } _ -> diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 3c8f93486..96795c420 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -10,7 +10,7 @@ def render("accounts.json", %{users: users} = opts) do render_many(users, AccountView, "account.json", opts) end - def render("account.json", %{user: user}) do + def render("account.json", %{user: user} = opts) do image = User.avatar_url(user) |> MediaProxy.url() header = User.banner_url(user) |> MediaProxy.url() user_info = User.user_info(user) @@ -33,6 +33,8 @@ def render("account.json", %{user: user}) do |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) + %{ id: to_string(user.id), username: username_from_nickname(user.nickname), @@ -43,7 +45,7 @@ def render("account.json", %{user: user}) do followers_count: user_info.follower_count, following_count: user_info.following_count, statuses_count: user_info.note_count, - note: HTML.filter_tags(user.bio) || "", + note: bio || "", url: user.ap_id, avatar: image, avatar_static: image, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index ffc105196..ef46ba4fc 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -122,6 +122,10 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} %{shortcode: name, url: url, static_url: url, visible_in_picker: false} end) + content = + render_content(object) + |> HTML.filter_tags(User.html_filter_policy(opts[:for])) + %{ id: to_string(activity.id), uri: object["id"], @@ -130,7 +134,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} in_reply_to_id: reply_to && to_string(reply_to.id), in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id), reblog: nil, - content: render_content(object), + content: content, created_at: created_at, reblogs_count: announcement_count, replies_count: 0, @@ -224,7 +228,7 @@ def render_content(%{"type" => "Video"} = object) do object["content"] end - HTML.filter_tags(content) + content end def render_content(%{"type" => "Article"} = object) do @@ -237,10 +241,8 @@ def render_content(%{"type" => "Article"} = object) do object["content"] end - HTML.filter_tags(content) + content end - def render_content(object) do - HTML.filter_tags(object["content"]) - end + def render_content(object), do: object["content"] end From c2b69798dd924f287a720ad5a57feed99b14d609 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 02:17:19 +0000 Subject: [PATCH 5/7] twitter api: add support for disabling rich text --- .../web/twitter_api/twitter_api_controller.ex | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index b3a56b27e..cd2bb5b57 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -443,6 +443,20 @@ def update_profile(%{assigns: %{user: user}} = conn, params) do user end + user = + if no_rich_text = params["no_rich_text"] do + with no_rich_text <- no_rich_text == "true", + new_info <- Map.put(user.info, "no_rich_text", no_rich_text), + change <- User.info_changeset(user, %{info: new_info}), + {:ok, user} <- User.update_and_set_cache(change) do + user + else + _e -> user + end + else + user + end + user = if default_scope = params["default_scope"] do with new_info <- Map.put(user.info, "default_scope", default_scope), From df00a364fb08263fa91d19bf8ed815f172c922da Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 02:48:42 +0000 Subject: [PATCH 6/7] mastodon api: formatting --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 47ae61b5b..391a79885 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -858,7 +858,9 @@ def index(%{assigns: %{user: user}} = conn, _params) do if user && token do mastodon_emoji = mastodonized_emoji() - accounts = Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user})) + + accounts = + Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user})) initial_state = %{ From bd03644ca8d3877fd1abb0c8f8d58603c5a4329e Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 22 Sep 2018 03:01:01 +0000 Subject: [PATCH 7/7] test: add tests for new User.html_filter_policy() --- test/user_test.exs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/user_test.exs b/test/user_test.exs index 58fe6eeda..4b0f0739e 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -526,4 +526,18 @@ test "insert or update a user from given data" do assert {:ok, %User{}} = User.insert_or_update_user(data) end + + describe "per-user rich-text filtering" do + test "html_filter_policy returns nil when rich-text is enabled" do + user = insert(:user) + + assert nil == User.html_filter_policy(user) + end + + test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do + user = insert(:user, %{info: %{"no_rich_text" => true}}) + + assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user) + end + end end