From 470a3e594b2a48e5f201e85fe7bcd3d0e4b4336a Mon Sep 17 00:00:00 2001
From: Thomas Citharel
Date: Mon, 31 Oct 2022 13:00:45 +0100
Subject: [PATCH] Correctly escape user-defined names in emails
Closes #1151
Signed-off-by: Thomas Citharel
---
lib/service/metadata/actor.ex | 23 +++++++----
lib/service/metadata/comment.ex | 4 +-
lib/service/metadata/event.ex | 16 +++++---
lib/service/metadata/post.ex | 8 ++--
lib/service/metadata/utils.ex | 7 ++++
.../activity/_comment_activity_item.html.heex | 16 ++++----
.../_discussion_activity_item.html.heex | 20 +++++-----
.../activity/_event_activity_item.html.heex | 20 +++++-----
.../activity/_group_activity_item.html.heex | 8 ++--
.../activity/_member_activity_item.html.heex | 28 +++++++-------
.../activity/_post_activity_item.html.heex | 12 +++---
.../_resource_activity_item.html.heex | 38 ++++++++++---------
...ymous_participation_confirmation.html.heex | 2 +-
lib/web/templates/email/email.html.heex | 2 +-
.../email/email_anonymous_activity.html.heex | 5 +--
.../event_participation_approved.html.heex | 4 +-
.../event_participation_confirmed.html.heex | 4 +-
.../event_participation_rejected.html.heex | 4 +-
.../templates/email/event_updated.html.heex | 2 +-
.../templates/email/group_invite.html.heex | 4 +-
.../email/group_member_removal.html.heex | 2 +-
.../email/group_membership_approval.html.heex | 4 +-
.../group_membership_rejection.html.heex | 4 +-
.../email/group_suspension.html.heex | 10 ++---
.../templates/email/instance_follow.html.heex | 4 +-
lib/web/templates/email/report.html.heex | 4 +-
lib/web/views/email_view.ex | 19 +++++++++-
test/service/metadata/metadata_test.exs | 6 +--
28 files changed, 162 insertions(+), 118 deletions(-)
diff --git a/lib/service/metadata/actor.ex b/lib/service/metadata/actor.ex
index 90046c361..e4174c45b 100644
--- a/lib/service/metadata/actor.ex
+++ b/lib/service/metadata/actor.ex
@@ -5,7 +5,10 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
alias Mobilizon.Web.Endpoint
alias Mobilizon.Web.JsonLD.ObjectView
alias Mobilizon.Web.Router.Helpers, as: Routes
- import Mobilizon.Service.Metadata.Utils, only: [process_description: 2, default_description: 1]
+
+ import Mobilizon.Service.Metadata.Utils,
+ only: [process_description: 2, default_description: 1, escape_text: 1]
+
import Mobilizon.Web.Gettext
def build_tags(_actor, _locale \\ "en")
@@ -19,7 +22,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
end)
[
- Tag.tag(:meta, property: "og:title", content: Actor.display_name_and_username(group)),
+ Tag.tag(:meta, property: "og:title", content: actor_display_name_escaped(group)),
Tag.tag(:meta,
property: "og:url",
content:
@@ -34,7 +37,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
Tag.tag(:meta, property: "og:type", content: "profile"),
Tag.tag(:meta,
property: "profile:username",
- content: Actor.preferred_username_and_domain(group)
+ content: group |> Actor.preferred_username_and_domain() |> escape_text()
),
Tag.tag(:meta, property: "twitter:card", content: "summary"),
Tag.tag(:meta, property: "twitter:site", content: "@joinmobilizon")
@@ -67,7 +70,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
%{
"@type" => "ListItem",
"position" => 1,
- "name" => Actor.display_name(group)
+ "name" => actor_display_name_escaped(group)
}
]
}
@@ -87,16 +90,14 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
Tag.tag(:link,
rel: "alternate",
type: "application/atom+xml",
- title:
- gettext("%{name}'s feed", name: group.name || group.preferred_username) |> HTML.raw(),
+ title: gettext("%{name}'s feed", name: actor_display_name_escaped(group)) |> HTML.raw(),
href:
Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), :atom)
),
Tag.tag(:link,
rel: "alternate",
type: "text/calendar",
- title:
- gettext("%{name}'s feed", name: group.name || group.preferred_username) |> HTML.raw(),
+ title: gettext("%{name}'s feed", name: actor_display_name_escaped(group)) |> HTML.raw(),
href:
Routes.feed_url(
Endpoint,
@@ -131,4 +132,10 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Actors.Actor do
|> ObjectView.render(%{group: group})
|> Jason.encode!()
end
+
+ defp actor_display_name_escaped(actor) do
+ actor
+ |> Actor.display_name()
+ |> escape_text()
+ end
end
diff --git a/lib/service/metadata/comment.ex b/lib/service/metadata/comment.ex
index d36aebc07..dcdcc0409 100644
--- a/lib/service/metadata/comment.ex
+++ b/lib/service/metadata/comment.ex
@@ -1,11 +1,13 @@
defimpl Mobilizon.Service.Metadata, for: Mobilizon.Discussions.Comment do
alias Phoenix.HTML.Tag
+ alias Mobilizon.Actors.Actor
alias Mobilizon.Discussions.Comment
+ import Mobilizon.Service.Metadata.Utils, only: [escape_text: 1]
@spec build_tags(Comment.t(), String.t()) :: list(Phoenix.HTML.safe())
def build_tags(%Comment{deleted_at: nil} = comment, _locale) do
[
- Tag.tag(:meta, property: "og:title", content: comment.actor.preferred_username),
+ Tag.tag(:meta, property: "og:title", content: escape_text(Actor.display_name(comment.actor))),
Tag.tag(:meta, property: "og:url", content: comment.url),
Tag.tag(:meta, property: "og:description", content: comment.text),
Tag.tag(:meta, property: "og:type", content: "website"),
diff --git a/lib/service/metadata/event.ex b/lib/service/metadata/event.ex
index aa6011e93..29b5a8059 100644
--- a/lib/service/metadata/event.ex
+++ b/lib/service/metadata/event.ex
@@ -9,15 +9,21 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Events.Event do
alias Mobilizon.Web.Router.Helpers, as: Routes
import Mobilizon.Service.Metadata.Utils,
- only: [process_description: 2, strip_tags: 1, datetime_to_string: 2, render_address!: 1]
+ only: [
+ process_description: 2,
+ strip_tags: 1,
+ datetime_to_string: 2,
+ render_address!: 1,
+ escape_text: 1
+ ]
def build_tags(%Event{} = event, locale \\ "en") do
formatted_description = description(event, locale)
tags = [
- Tag.content_tag(:title, event.title <> " - Mobilizon"),
+ Tag.content_tag(:title, escape_text(event.title) <> " - Mobilizon"),
Tag.tag(:meta, name: "description", content: process_description(event.description, locale)),
- Tag.tag(:meta, property: "og:title", content: event.title),
+ Tag.tag(:meta, property: "og:title", content: escape_text(event.title)),
Tag.tag(:meta, property: "og:url", content: event.url),
Tag.tag(:meta, property: "og:description", content: formatted_description),
Tag.tag(:meta, property: "og:type", content: "website"),
@@ -48,7 +54,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Events.Event do
%{
"@type" => "ListItem",
"position" => 1,
- "name" => Actor.display_name(event.attributed_to),
+ "name" => event.attributed_to |> Actor.display_name() |> escape_text(),
"item" =>
Endpoint
|> Routes.page_url(
@@ -85,7 +91,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Events.Event do
%{
"@type" => "ListItem",
"position" => 2,
- "name" => event.title
+ "name" => escape_text(event.title)
}
]
}
diff --git a/lib/service/metadata/post.ex b/lib/service/metadata/post.ex
index a0de60ae5..90daf3dc3 100644
--- a/lib/service/metadata/post.ex
+++ b/lib/service/metadata/post.ex
@@ -7,14 +7,16 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Posts.Post do
alias Mobilizon.Web.Endpoint
alias Mobilizon.Web.JsonLD.ObjectView
alias Mobilizon.Web.Router.Helpers, as: Routes
- import Mobilizon.Service.Metadata.Utils, only: [process_description: 2, strip_tags: 1]
+
+ import Mobilizon.Service.Metadata.Utils,
+ only: [process_description: 2, strip_tags: 1, escape_text: 1]
def build_tags(%Post{} = post, locale \\ "en") do
post = Map.put(post, :body, process_description(post.body, locale))
tags =
[
- Tag.tag(:meta, property: "og:title", content: post.title),
+ Tag.tag(:meta, property: "og:title", content: escape_text(post.title)),
Tag.tag(:meta, property: "og:url", content: post.url),
Tag.tag(:meta, property: "og:description", content: post.body),
Tag.tag(:meta, property: "og:type", content: "article"),
@@ -31,7 +33,7 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Posts.Post do
%{
"@type" => "ListItem",
"position" => 1,
- "name" => Actor.display_name(post.attributed_to),
+ "name" => post.attributed_to |> Actor.display_name() |> escape_text,
"item" =>
Endpoint
|> Routes.page_url(
diff --git a/lib/service/metadata/utils.ex b/lib/service/metadata/utils.ex
index a819f194c..990bf5115 100644
--- a/lib/service/metadata/utils.ex
+++ b/lib/service/metadata/utils.ex
@@ -74,4 +74,11 @@ defmodule Mobilizon.Service.Metadata.Utils do
@spec stringify_tag(String.t(), String.t()) :: String.t()
defp stringify_tag(tag, acc) when is_binary(tag), do: acc <> tag
+
+ @spec escape_text(String.t()) :: String.t()
+ def escape_text(text) do
+ text
+ |> HTML.html_escape()
+ |> HTML.safe_to_string()
+ end
end
diff --git a/lib/web/templates/email/activity/_comment_activity_item.html.heex b/lib/web/templates/email/activity/_comment_activity_item.html.heex
index 5da7aa527..8daa72140 100644
--- a/lib/web/templates/email/activity/_comment_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_comment_activity_item.html.heex
@@ -1,35 +1,35 @@
<%= case @activity.subject do %>
<% :event_comment_mention -> %>
<%= dgettext("activity", "%{profile} mentionned you in a comment under event %{event}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
<% :participation_event_comment -> %>
<%= dgettext("activity", "%{profile} has posted an announcement under event %{event}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
<% :event_new_comment -> %>
<%= if @activity.subject_params["comment_reply_to"] do %>
<%= dgettext("activity", "%{profile} has posted a new reply under your event %{event}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}#comment-#{@activity.subject_params["comment_reply_to_uuid"]}-#{@activity.subject_params["comment_uuid"]}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
@@ -38,12 +38,12 @@
"activity",
"%{profile} has posted a new comment under your event %{event}.",
%{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}#comment-#{@activity.subject_params["comment_uuid"]}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
}
)
diff --git a/lib/web/templates/email/activity/_discussion_activity_item.html.heex b/lib/web/templates/email/activity/_discussion_activity_item.html.heex
index 36f011e24..e5ba67bc4 100644
--- a/lib/web/templates/email/activity/_discussion_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_discussion_activity_item.html.heex
@@ -1,40 +1,40 @@
<%= case @activity.subject do %>
<% :discussion_created -> %>
<%= dgettext("activity", "%{profile} created the discussion %{discussion}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
discussion:
" URI.decode()}\">
- #{@activity.subject_params["discussion_title"]}"
+ #{escape_html(@activity.subject_params["discussion_title"])}"
})
|> raw %>
<% :discussion_replied -> %>
<%= dgettext("activity", "%{profile} replied to the discussion %{discussion}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
discussion:
" URI.decode()}\">
- #{@activity.subject_params["discussion_title"]}"
+ #{escape_html(@activity.subject_params["discussion_title"])}"
})
|> raw %>
<% :discussion_renamed -> %>
<%= dgettext("activity", "%{profile} renamed the discussion %{discussion}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
discussion:
" URI.decode()}\">
- #{@activity.subject_params["discussion_title"]}"
+ #{escape_html(@activity.subject_params["discussion_title"])}"
})
|> raw %>
<% :discussion_archived -> %>
<%= dgettext("activity", "%{profile} archived the discussion %{discussion}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
discussion:
" URI.decode()}\">
- #{@activity.subject_params["discussion_title"]}"
+ #{escape_html(@activity.subject_params["discussion_title"])}"
})
|> raw %>
<% :discussion_deleted -> %>
<%= dgettext("activity", "%{profile} deleted the discussion %{discussion}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
- discussion: "#{@activity.subject_params["discussion_title"]}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
+ discussion: "#{escape_html(@activity.subject_params["discussion_title"])}"
})
|> raw %>
<% end %>
diff --git a/lib/web/templates/email/activity/_event_activity_item.html.heex b/lib/web/templates/email/activity/_event_activity_item.html.heex
index ef371381f..9af392741 100644
--- a/lib/web/templates/email/activity/_event_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_event_activity_item.html.heex
@@ -1,52 +1,52 @@
<%= case @activity.subject do %>
<% :event_created -> %>
<%= dgettext("activity", "The event %{event} was created by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
<% :event_updated -> %>
<%= dgettext("activity", "The event %{event} was updated by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
<% :event_deleted -> %>
<%= dgettext("activity", "The event %{event} was deleted by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
- event: "#{@activity.subject_params["event_title"]}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
+ event: "#{escape_html(@activity.subject_params["event_title"])}"
})
|> raw %>
<% :comment_posted -> %>
<%= if @activity.subject_params["comment_reply_to"] do %>
<%= dgettext("activity", "%{profile} replied to a comment on the event %{event}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
<% else %>
<%= dgettext("activity", "%{profile} posted a comment on the event %{event}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
event:
" URI.decode()}\">
- #{@activity.subject_params["event_title"]}
+ #{escape_html(@activity.subject_params["event_title"])}
"
})
|> raw %>
diff --git a/lib/web/templates/email/activity/_group_activity_item.html.heex b/lib/web/templates/email/activity/_group_activity_item.html.heex
index ad4318f93..36ad49b16 100644
--- a/lib/web/templates/email/activity/_group_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_group_activity_item.html.heex
@@ -1,23 +1,23 @@
<%= case @activity.subject do %>
<% :group_created -> %>
<%= dgettext("activity", "%{profile} created the group %{group}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
group:
" URI.decode()}\">
- #{@activity.subject_params["group_name"]}
+ #{escape_html(@activity.subject_params["group_name"])}
"
})
|> raw %>
<% :group_updated -> %>
<%= dgettext("activity", "%{profile} updated the group %{group}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
group:
" URI.decode()}\">
- #{@activity.subject_params["group_name"]}
+ #{escape_html(@activity.subject_params["group_name"])}
"
})
|> raw %>
diff --git a/lib/web/templates/email/activity/_member_activity_item.html.heex b/lib/web/templates/email/activity/_member_activity_item.html.heex
index 807023200..f51fb6b92 100644
--- a/lib/web/templates/email/activity/_member_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_member_activity_item.html.heex
@@ -1,58 +1,58 @@
<%= case @activity.subject do %>
<% :member_request -> %>
<%= dgettext("activity", "%{member} requested to join the group.", %{
- member: "#{@activity.subject_params["member_actor_name"]}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}"
})
|> raw %>
<% :member_invited -> %>
<%= dgettext("activity", "%{member} was invited by %{profile}.", %{
- member: "#{@activity.subject_params["member_actor_name"]}",
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% :member_accepted_invitation -> %>
<%= dgettext("activity", "%{member} accepted the invitation to join the group.", %{
- member: "#{@activity.subject_params["member_actor_name"]}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}"
})
|> raw %>
<% :member_rejected_invitation -> %>
<%= dgettext("activity", "%{member} rejected the invitation to join the group.", %{
- member: "#{@activity.subject_params["member_actor_name"]}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}"
})
|> raw %>
<% :member_joined -> %>
<%= dgettext("activity", "%{member} joined the group.", %{
member:
- "#{@activity.subject_params["member_actor_name"]}"
+ "#{escape_html(@activity.subject_params["member_actor_name"])}"
})
|> raw %>
<% :member_added -> %>
<%= dgettext("activity", "%{profile} added the member %{member}.", %{
- member: "#{@activity.subject_params["member_actor_name"]}",
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% :member_approved -> %>
<%= dgettext("activity", "%{profile} approved the member %{member}.", %{
- member: "#{@activity.subject_params["member_actor_name"]}",
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% :member_updated -> %>
<%= dgettext("activity", "%{profile} updated the member %{member}.", %{
- member: "#{@activity.subject_params["member_actor_name"]}",
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ member: "#{escape_html(@activity.subject_params["member_actor_name"])}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% :member_removed -> %>
<%= dgettext("activity", "%{profile} excluded member %{member}.", %{
member: "#{@activity.subject_params["member_actor_name"]}",
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% :member_quit -> %>
<%= dgettext("activity", "%{profile} quit the group.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}"
})
|> raw %>
<% end %>
diff --git a/lib/web/templates/email/activity/_post_activity_item.html.heex b/lib/web/templates/email/activity/_post_activity_item.html.heex
index e9e3369ea..52c03e781 100644
--- a/lib/web/templates/email/activity/_post_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_post_activity_item.html.heex
@@ -1,30 +1,30 @@
<%= case @activity.subject do %>
<% :post_created -> %>
<%= dgettext("activity", "The post %{post} was created by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
post:
" URI.decode()}\">
- #{@activity.subject_params["post_title"]}
+ #{escape_html(@activity.subject_params["post_title"])}
"
})
|> raw %>
<% :post_updated -> %>
<%= dgettext("activity", "The post %{post} was updated by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
post:
" URI.decode()}\">
- #{@activity.subject_params["post_title"]}
+ #{escape_html(@activity.subject_params["post_title"])}
"
})
|> raw %>
<% :post_deleted -> %>
<%= dgettext("activity", "The post %{post} was deleted by %{profile}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
- post: "#{@activity.subject_params["post_title"]}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
+ post: "#{escape_html(@activity.subject_params["post_title"])}"
})
|> raw %>
<% end %>
diff --git a/lib/web/templates/email/activity/_resource_activity_item.html.heex b/lib/web/templates/email/activity/_resource_activity_item.html.heex
index 27915b9b0..67745aed6 100644
--- a/lib/web/templates/email/activity/_resource_activity_item.html.heex
+++ b/lib/web/templates/email/activity/_resource_activity_item.html.heex
@@ -2,23 +2,23 @@
<% :resource_created -> %>
<%= if @activity.subject_params["is_folder"] do %>
<%= dgettext("activity", "%{profile} created the folder %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
"
})
|> raw %>
<% else %>
<%= dgettext("activity", "%{profile} created the resource %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
"
})
|> raw %>
@@ -29,14 +29,15 @@
"activity",
"%{profile} renamed the folder from %{old_resource_title} to %{resource}.",
%{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
",
- old_resource_title: "#{@activity.subject_params["old_resource_title"]}"
+ old_resource_title:
+ "#{escape_html(@activity.subject_params["old_resource_title"])}"
}
)
|> raw %>
@@ -45,14 +46,15 @@
"activity",
"%{profile} renamed the resource from %{old_resource_title} to %{resource}.",
%{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
",
- old_resource_title: "#{@activity.subject_params["old_resource_title"]}"
+ old_resource_title:
+ "#{escape_html(@activity.subject_params["old_resource_title"])}"
}
)
|> raw %>
@@ -60,23 +62,23 @@
<% :resource_moved -> %>
<%= if @activity.subject_params["is_folder"] do %>
<%= dgettext("activity", "%{profile} moved the folder %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
"
})
|> raw %>
<% else %>
<%= dgettext("activity", "%{profile} moved the resource %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
resource:
" URI.decode()}\">
- #{@activity.subject_params["resource_title"]}
+ #{escape_html(@activity.subject_params["resource_title"])}
"
})
|> raw %>
@@ -84,14 +86,14 @@
<% :resource_deleted -> %>
<%= if @activity.subject_params["is_folder"] do %>
<%= dgettext("activity", "%{profile} deleted the folder %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
- resource: "#{@activity.subject_params["resource_title"]}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
+ resource: "#{escape_html(@activity.subject_params["resource_title"])}"
})
|> raw %>
<% else %>
<%= dgettext("activity", "%{profile} deleted the resource %{resource}.", %{
- profile: "#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}",
- resource: "#{@activity.subject_params["resource_title"]}"
+ profile: "#{escaped_display_name_and_username(@activity.author)}",
+ resource: "#{escape_html(@activity.subject_params["resource_title"])}"
})
|> raw %>
<% end %>
diff --git a/lib/web/templates/email/anonymous_participation_confirmation.html.heex b/lib/web/templates/email/anonymous_participation_confirmation.html.heex
index 8f13ea212..56c20f57b 100644
--- a/lib/web/templates/email/anonymous_participation_confirmation.html.heex
+++ b/lib/web/templates/email/anonymous_participation_confirmation.html.heex
@@ -46,7 +46,7 @@
<%= gettext(
"Hi there! You just registered to join this event: « %{title} ». Please confirm the e-mail address you provided:",
- title: @participant.event.title
+ title: escape_html(@participant.event.title)
)
|> raw %>
diff --git a/lib/web/templates/email/email.html.heex b/lib/web/templates/email/email.html.heex
index d8b34772e..ce2f81c37 100644
--- a/lib/web/templates/email/email.html.heex
+++ b/lib/web/templates/email/email.html.heex
@@ -109,7 +109,7 @@
<%= gettext("This is a demonstration site to test Mobilizon.") %>
- <%= gettext("Please do not use it for real purposes.") |> raw() %>
+ <%= gettext("Please do not use it for real purposes.") %>
<%= gettext(
"There have been changes for %{title} so we'd thought we'd let you know.",
- title: @old_event.title
+ title: escape_html(@old_event.title)
)
|> raw %>
<%= gettext(
"%{inviter} just invited you to join their group %{link_start}%{group}%{link_end}",
- group: @group.name,
- inviter: @inviter.name,
+ group: escape_html(display_name(@group)),
+ inviter: escape_html(display_name(@inviter)),
link_start: "",
link_end: ""
)
diff --git a/lib/web/templates/email/group_member_removal.html.heex b/lib/web/templates/email/group_member_removal.html.heex
index 3311538aa..001c8a127 100644
--- a/lib/web/templates/email/group_member_removal.html.heex
+++ b/lib/web/templates/email/group_member_removal.html.heex
@@ -46,7 +46,7 @@
<%= gettext(
"You have been removed from group %{link_start}%{group}%{link_end}. You will not be able to access this group's private content anymore.",
- group: @group.name,
+ group: escape_html(display_name(@group)),
link_start: "",
link_end: ""
)
diff --git a/lib/web/templates/email/group_membership_approval.html.heex b/lib/web/templates/email/group_membership_approval.html.heex
index a681bbc55..acefe2fb1 100644
--- a/lib/web/templates/email/group_membership_approval.html.heex
+++ b/lib/web/templates/email/group_membership_approval.html.heex
@@ -46,9 +46,9 @@
<%= gettext(
"Your membership request for group %{link_start}%{group}%{link_end} has been approved.",
- group: Mobilizon.Actors.Actor.display_name(@group),
+ group: escape_html(display_name(@group)),
link_start:
- " URI.decode()}\">",
+ " URI.decode()}\">",
link_end: ""
)
|> raw %>
diff --git a/lib/web/templates/email/group_membership_rejection.html.heex b/lib/web/templates/email/group_membership_rejection.html.heex
index 29343d5ed..e4d271200 100644
--- a/lib/web/templates/email/group_membership_rejection.html.heex
+++ b/lib/web/templates/email/group_membership_rejection.html.heex
@@ -46,9 +46,9 @@
<%= gettext(
"Your membership request for group %{link_start}%{group}%{link_end} has been rejected.",
- group: Mobilizon.Actors.Actor.display_name(@group),
+ group: escape_html(display_name(@group)),
link_start:
- " URI.decode()}\">",
+ " URI.decode()}\">",
link_end: ""
)
|> raw %>
diff --git a/lib/web/templates/email/group_suspension.html.heex b/lib/web/templates/email/group_suspension.html.heex
index 7524bd584..b1baacfcc 100644
--- a/lib/web/templates/email/group_suspension.html.heex
+++ b/lib/web/templates/email/group_suspension.html.heex
@@ -16,7 +16,7 @@
>
<%= gettext("The group %{group} has been suspended on %{instance}!",
- group: @group.name || @group.preferred_username,
+ group: display_name(@group),
instance: @instance_name
) %>
@@ -49,12 +49,8 @@
<%= gettext(
"Your instance's moderation team has decided to suspend %{group_name} (%{group_address}). You are no longer a member of this group.",
- group_name: @group.name,
- group_address:
- if(@group.domain,
- do: "@#{@group.preferred_username}@#{@group.domain}",
- else: "@#{@group.preferred_username}"
- )
+ group_name: escape_html(display_name(@group)),
+ group_address: preferred_username_and_domain(@group)
)
|> raw %>
<%= gettext("%{name} just requested to follow your instance.",
- name: Mobilizon.Actors.Actor.display_name_and_username(@follower)
+ name: escape_html(display_name_and_username(@follower))
)
|> raw %>
@@ -67,7 +67,7 @@
<%= gettext(
"Note: %{name} following you doesn't necessarily imply that you follow this instance, but you can ask to follow them too.",
- name: Mobilizon.Actors.Actor.display_name_and_username(@follower)
+ name: escape_html(display_name_and_username(@follower))
) %>
diff --git a/lib/web/templates/email/report.html.heex b/lib/web/templates/email/report.html.heex
index fd1885cbe..48c5a62e6 100644
--- a/lib/web/templates/email/report.html.heex
+++ b/lib/web/templates/email/report.html.heex
@@ -47,12 +47,12 @@
<%= if @report.reporter.type == :Application and @report.reporter.preferred_username == "relay" do %>
<%= gettext(
"Someone on %{instance} reported the following content for you to analyze:",
- instance: @report.reporter.domain
+ instance: escape_html(@report.reporter.domain)
)
|> raw %>
<% else %>
<%= gettext("%{reporter} reported the following content.",
- reporter: Mobilizon.Actors.Actor.display_name_and_username(@report.reporter)
+ reporter: escape_html(display_name_and_username(@report.reporter))
)
|> raw %>
<% end %>
diff --git a/lib/web/views/email_view.ex b/lib/web/views/email_view.ex
index d72a2eea3..c103e4fcf 100644
--- a/lib/web/views/email_view.ex
+++ b/lib/web/views/email_view.ex
@@ -4,12 +4,13 @@ defmodule Mobilizon.Web.EmailView do
pattern: "**/*",
namespace: Mobilizon.Web
+ alias Mobilizon.Actors.Actor
alias Mobilizon.Service.Address
alias Mobilizon.Service.DateTime, as: DateTimeRenderer
alias Mobilizon.Web.Router.Helpers, as: Routes
import Mobilizon.Web.Gettext
import Mobilizon.Service.Metadata.Utils, only: [process_description: 1]
- import Phoenix.HTML, only: [raw: 1]
+ import Phoenix.HTML, only: [raw: 1, html_escape: 1, safe_to_string: 1]
defdelegate datetime_to_string(datetime, locale \\ "en", format \\ :medium),
to: DateTimeRenderer
@@ -24,4 +25,20 @@ defmodule Mobilizon.Web.EmailView do
defdelegate datetime_relative(datetime, locale \\ "en"), to: DateTimeRenderer
defdelegate render_address(address), to: Address
defdelegate is_same_day?(one, two), to: DateTimeRenderer
+ defdelegate display_name_and_username(actor), to: Actor
+ defdelegate display_name(actor), to: Actor
+ defdelegate preferred_username_and_domain(actor), to: Actor
+
+ @spec escape_html(String.t()) :: String.t()
+ def escape_html(string) do
+ string
+ |> html_escape()
+ |> safe_to_string()
+ end
+
+ def escaped_display_name_and_username(actor) do
+ actor
+ |> Actor.display_name_and_username()
+ |> escape_html()
+ end
end
diff --git a/test/service/metadata/metadata_test.exs b/test/service/metadata/metadata_test.exs
index 43bdfc8f6..ef01ea137 100644
--- a/test/service/metadata/metadata_test.exs
+++ b/test/service/metadata/metadata_test.exs
@@ -18,7 +18,7 @@ defmodule Mobilizon.Service.MetadataTest do
assert group |> Metadata.build_tags() |> Metadata.Utils.stringify_tags() ==
String.trim("""
-
+
""")
assert group
@@ -26,7 +26,7 @@ defmodule Mobilizon.Service.MetadataTest do
|> Metadata.build_tags()
|> Metadata.Utils.stringify_tags() ==
String.trim("""
-
+
""")
end
@@ -144,7 +144,7 @@ defmodule Mobilizon.Service.MetadataTest do
|> Metadata.build_tags()
|> Metadata.Utils.stringify_tags() ==
String.trim("""
-
+
""")
end
end