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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> raw %> <% :participation_event_comment -> %> <%= dgettext("activity", "%{profile} has posted an announcement under event %{event}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> 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"])} </a>" }) |> raw %> @@ -38,12 +38,12 @@ "activity", "%{profile} has posted a new comment under your event %{event}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}#comment-#{@activity.subject_params["comment_uuid"]}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" } ) 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", discussion: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :discussion, Mobilizon.Actors.Actor.preferred_username_and_domain(@activity.group), @activity.subject_params["discussion_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["discussion_title"]}</a>" + #{escape_html(@activity.subject_params["discussion_title"])}</a>" }) |> raw %> <% :discussion_replied -> %> <%= dgettext("activity", "%{profile} replied to the discussion %{discussion}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", discussion: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :discussion, Mobilizon.Actors.Actor.preferred_username_and_domain(@activity.group), @activity.subject_params["discussion_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["discussion_title"]}</a>" + #{escape_html(@activity.subject_params["discussion_title"])}</a>" }) |> raw %> <% :discussion_renamed -> %> <%= dgettext("activity", "%{profile} renamed the discussion %{discussion}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", discussion: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :discussion, Mobilizon.Actors.Actor.preferred_username_and_domain(@activity.group), @activity.subject_params["discussion_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["discussion_title"]}</a>" + #{escape_html(@activity.subject_params["discussion_title"])}</a>" }) |> raw %> <% :discussion_archived -> %> <%= dgettext("activity", "%{profile} archived the discussion %{discussion}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", discussion: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :discussion, Mobilizon.Actors.Actor.preferred_username_and_domain(@activity.group), @activity.subject_params["discussion_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["discussion_title"]}</a>" + #{escape_html(@activity.subject_params["discussion_title"])}</a>" }) |> raw %> <% :discussion_deleted -> %> <%= dgettext("activity", "%{profile} deleted the discussion %{discussion}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", - discussion: "<b>#{@activity.subject_params["discussion_title"]}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", + discussion: "<b>#{escape_html(@activity.subject_params["discussion_title"])}</b>" }) |> 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> raw %> <% :event_updated -> %> <%= dgettext("activity", "The event %{event} was updated by %{profile}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> raw %> <% :event_deleted -> %> <%= dgettext("activity", "The event %{event} was deleted by %{profile}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", - event: "<b>#{@activity.subject_params["event_title"]}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", + event: "<b>#{escape_html(@activity.subject_params["event_title"])}</b>" }) |> raw %> <% :comment_posted -> %> <%= if @activity.subject_params["comment_reply_to"] do %> <%= dgettext("activity", "%{profile} replied to a comment on the event %{event}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> raw %> <% else %> <%= dgettext("activity", "%{profile} posted a comment on the event %{event}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" }) |> 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", group: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, @activity.subject_params["group_federated_username"]) |> URI.decode()}\"> - #{@activity.subject_params["group_name"]} + #{escape_html(@activity.subject_params["group_name"])} </a>" }) |> raw %> <% :group_updated -> %> <%= dgettext("activity", "%{profile} updated the group %{group}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", group: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, @activity.subject_params["group_federated_username"]) |> URI.decode()}\"> - #{@activity.subject_params["group_name"]} + #{escape_html(@activity.subject_params["group_name"])} </a>" }) |> 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: "<b>#{@activity.subject_params["member_actor_name"]}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>" }) |> raw %> <% :member_invited -> %> <%= dgettext("activity", "%{member} was invited by %{profile}.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>", - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> raw %> <% :member_accepted_invitation -> %> <%= dgettext("activity", "%{member} accepted the invitation to join the group.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>" }) |> raw %> <% :member_rejected_invitation -> %> <%= dgettext("activity", "%{member} rejected the invitation to join the group.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>" }) |> raw %> <% :member_joined -> %> <%= dgettext("activity", "%{member} joined the group.", %{ member: - "<b title=\"#{@activity.subject_params["member_actor_federated_username"]}\">#{@activity.subject_params["member_actor_name"]}</b>" + "<b title=\"#{@activity.subject_params["member_actor_federated_username"]}\">#{escape_html(@activity.subject_params["member_actor_name"])}</b>" }) |> raw %> <% :member_added -> %> <%= dgettext("activity", "%{profile} added the member %{member}.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>", - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> raw %> <% :member_approved -> %> <%= dgettext("activity", "%{profile} approved the member %{member}.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>", - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> raw %> <% :member_updated -> %> <%= dgettext("activity", "%{profile} updated the member %{member}.", %{ - member: "<b>#{@activity.subject_params["member_actor_name"]}</b>", - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + member: "<b>#{escape_html(@activity.subject_params["member_actor_name"])}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> raw %> <% :member_removed -> %> <%= dgettext("activity", "%{profile} excluded member %{member}.", %{ member: "<b>#{@activity.subject_params["member_actor_name"]}</b>", - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> raw %> <% :member_quit -> %> <%= dgettext("activity", "%{profile} quit the group.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>" }) |> 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", post: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :post, @activity.subject_params["post_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["post_title"]} + #{escape_html(@activity.subject_params["post_title"])} </a>" }) |> raw %> <% :post_updated -> %> <%= dgettext("activity", "The post %{post} was updated by %{profile}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", post: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :post, @activity.subject_params["post_slug"]) |> URI.decode()}\"> - #{@activity.subject_params["post_title"]} + #{escape_html(@activity.subject_params["post_title"])} </a>" }) |> raw %> <% :post_deleted -> %> <%= dgettext("activity", "The post %{post} was deleted by %{profile}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", - post: "<b>#{@activity.subject_params["post_title"]}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", + post: "<b>#{escape_html(@activity.subject_params["post_title"])}</b>" }) |> 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: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>" }) |> raw %> <% else %> <%= dgettext("activity", "%{profile} created the resource %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>" }) |> raw %> @@ -29,14 +29,15 @@ "activity", "%{profile} renamed the folder from %{old_resource_title} to %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>", - old_resource_title: "<b>#{@activity.subject_params["old_resource_title"]}</b>" + old_resource_title: + "<b>#{escape_html(@activity.subject_params["old_resource_title"])}</b>" } ) |> raw %> @@ -45,14 +46,15 @@ "activity", "%{profile} renamed the resource from %{old_resource_title} to %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>", - old_resource_title: "<b>#{@activity.subject_params["old_resource_title"]}</b>" + old_resource_title: + "<b>#{escape_html(@activity.subject_params["old_resource_title"])}</b>" } ) |> raw %> @@ -60,23 +62,23 @@ <% :resource_moved -> %> <%= if @activity.subject_params["is_folder"] do %> <%= dgettext("activity", "%{profile} moved the folder %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>" }) |> raw %> <% else %> <%= dgettext("activity", "%{profile} moved the resource %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", resource: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :resource, @activity.subject_params["resource_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["resource_title"]} + #{escape_html(@activity.subject_params["resource_title"])} </a>" }) |> raw %> @@ -84,14 +86,14 @@ <% :resource_deleted -> %> <%= if @activity.subject_params["is_folder"] do %> <%= dgettext("activity", "%{profile} deleted the folder %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", - resource: "<b>#{@activity.subject_params["resource_title"]}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", + resource: "<b>#{escape_html(@activity.subject_params["resource_title"])}</b>" }) |> raw %> <% else %> <%= dgettext("activity", "%{profile} deleted the resource %{resource}.", %{ - profile: "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", - resource: "<b>#{@activity.subject_params["resource_title"]}</b>" + profile: "<b>#{escaped_display_name_and_username(@activity.author)}</b>", + resource: "<b>#{escape_html(@activity.subject_params["resource_title"])}</b>" }) |> 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 @@ <p style="margin: 0;"> <%= gettext( "Hi there! You just registered to join this event: « <b>%{title}</b> ». Please confirm the e-mail address you provided:", - title: @participant.event.title + title: escape_html(@participant.event.title) ) |> raw %> </p> 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.") %> </p> <p style="margin: 0; color: #3A384C;"> - <%= gettext("<b>Please do not use it for real purposes.</b>") |> raw() %> + <b><%= gettext("Please do not use it for real purposes.") %></b> </p> </td> </tr> diff --git a/lib/web/templates/email/email_anonymous_activity.html.heex b/lib/web/templates/email/email_anonymous_activity.html.heex index 9687b0dc3..4e0d9421e 100644 --- a/lib/web/templates/email/email_anonymous_activity.html.heex +++ b/lib/web/templates/email/email_anonymous_activity.html.heex @@ -49,13 +49,12 @@ "activity", "%{profile} has posted an announcement under event %{event}.", %{ - profile: - "<b>#{Mobilizon.Actors.Actor.display_name_and_username(@activity.author)}</b>", + profile: "<b>#{escape_html(display_name_and_username(@activity.author))}</b>", event: "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :event, @activity.subject_params["event_uuid"]) |> URI.decode()}\"> - #{@activity.subject_params["event_title"]} + #{escape_html(@activity.subject_params["event_title"])} </a>" } ) diff --git a/lib/web/templates/email/event_participation_approved.html.heex b/lib/web/templates/email/event_participation_approved.html.heex index 06b00b895..eedd2836c 100644 --- a/lib/web/templates/email/event_participation_approved.html.heex +++ b/lib/web/templates/email/event_participation_approved.html.heex @@ -44,7 +44,9 @@ style="padding: 20px 30px 0px 30px; color: #474467; font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;" > <p style="margin: 0;"> - <%= gettext("You recently requested to attend <b>%{title}</b>.", title: @event.title) + <%= gettext("You recently requested to attend <b>%{title}</b>.", + title: escape_html(@event.title) + ) |> raw %> </p> </td> diff --git a/lib/web/templates/email/event_participation_confirmed.html.heex b/lib/web/templates/email/event_participation_confirmed.html.heex index 26e0f623d..8e57958d3 100644 --- a/lib/web/templates/email/event_participation_confirmed.html.heex +++ b/lib/web/templates/email/event_participation_confirmed.html.heex @@ -44,7 +44,9 @@ style="padding: 20px 30px 0px 30px; color: #474467; font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;" > <p style="margin: 0;"> - <%= gettext("You recently requested to attend <b>%{title}</b>.", title: @event.title) + <%= gettext("You recently requested to attend <b>%{title}</b>.", + title: escape_html(@event.title) + ) |> raw %> </p> </td> diff --git a/lib/web/templates/email/event_participation_rejected.html.heex b/lib/web/templates/email/event_participation_rejected.html.heex index 44e503948..8d2d673fa 100644 --- a/lib/web/templates/email/event_participation_rejected.html.heex +++ b/lib/web/templates/email/event_participation_rejected.html.heex @@ -44,7 +44,9 @@ style="padding: 20px 30px 0px 30px; color: #474467; font-family: 'Roboto', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;" > <p style="margin: 0;"> - <%= gettext("You issued a request to attend <b>%{title}</b>.", title: @event.title) + <%= gettext("You issued a request to attend <b>%{title}</b>.", + title: escape_html(@event.title) + ) |> raw %> </p> </td> diff --git a/lib/web/templates/email/event_updated.html.heex b/lib/web/templates/email/event_updated.html.heex index 5b11f8166..92e53021d 100644 --- a/lib/web/templates/email/event_updated.html.heex +++ b/lib/web/templates/email/event_updated.html.heex @@ -46,7 +46,7 @@ <p style="margin: 0;"> <%= gettext( "There have been changes for <b>%{title}</b> so we'd thought we'd let you know.", - title: @old_event.title + title: escape_html(@old_event.title) ) |> raw %> </p> diff --git a/lib/web/templates/email/group_invite.html.heex b/lib/web/templates/email/group_invite.html.heex index 68ccbfa83..1a34b44e8 100644 --- a/lib/web/templates/email/group_invite.html.heex +++ b/lib/web/templates/email/group_invite.html.heex @@ -46,8 +46,8 @@ <p style="margin: 0;"> <%= gettext( "<b>%{inviter}</b> just invited you to join their group %{link_start}<b>%{group}</b>%{link_end}", - group: @group.name, - inviter: @inviter.name, + group: escape_html(display_name(@group)), + inviter: escape_html(display_name(@inviter)), link_start: "<a href=\"#{@group.url}\">", link_end: "</a>" ) 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 @@ <p style="margin: 0;"> <%= gettext( "You have been removed from group %{link_start}<b>%{group}</b>%{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: "<a href=\"#{@group.url}\">", link_end: "</a>" ) 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 @@ <p style="margin: 0;"> <%= gettext( "Your membership request for group %{link_start}<b>%{group}</b>%{link_end} has been approved.", - group: Mobilizon.Actors.Actor.display_name(@group), + group: escape_html(display_name(@group)), link_start: - "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, Mobilizon.Actors.Actor.preferred_username_and_domain(@group)) |> URI.decode()}\">", + "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, preferred_username_and_domain(@group)) |> URI.decode()}\">", link_end: "</a>" ) |> 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 @@ <p style="margin: 0;"> <%= gettext( "Your membership request for group %{link_start}<b>%{group}</b>%{link_end} has been rejected.", - group: Mobilizon.Actors.Actor.display_name(@group), + group: escape_html(display_name(@group)), link_start: - "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, Mobilizon.Actors.Actor.preferred_username_and_domain(@group)) |> URI.decode()}\">", + "<a href=\"#{Routes.page_url(Mobilizon.Web.Endpoint, :actor, preferred_username_and_domain(@group)) |> URI.decode()}\">", link_end: "</a>" ) |> 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 @@ > <h1 style="font-size: 48px; font-weight: 400; margin: 0;"> <%= gettext("The group %{group} has been suspended on %{instance}!", - group: @group.name || @group.preferred_username, + group: display_name(@group), instance: @instance_name ) %> </h1> @@ -49,12 +49,8 @@ <p style="margin: 0;"> <%= gettext( "Your instance's moderation team has decided to suspend <b>%{group_name}</b> (%{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 %> </p> diff --git a/lib/web/templates/email/instance_follow.html.heex b/lib/web/templates/email/instance_follow.html.heex index f2e551f71..67e9a94bb 100644 --- a/lib/web/templates/email/instance_follow.html.heex +++ b/lib/web/templates/email/instance_follow.html.heex @@ -45,7 +45,7 @@ > <p style="margin: 0;"> <%= gettext("<b>%{name}</b> just requested to follow your instance.", - name: Mobilizon.Actors.Actor.display_name_and_username(@follower) + name: escape_html(display_name_and_username(@follower)) ) |> raw %> <br /> @@ -67,7 +67,7 @@ <p style="margin: 0;"> <%= 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)) ) %> </p> </td> 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 <b>%{instance}</b> reported the following content for you to analyze:", - instance: @report.reporter.domain + instance: escape_html(@report.reporter.domain) ) |> raw %> <% else %> <%= gettext("<b>%{reporter}</b> 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(""" - <meta content="#{group.name} (@#{group.preferred_username}@#{group.domain})" property="og:title"><meta content="#{URI.decode(Routes.page_url(Endpoint, :actor, Actor.preferred_username_and_domain(group)))}" property="og:url"><meta content="The event organizer didn't add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{Actor.preferred_username_and_domain(group)}" property="profile:username"><meta content="summary" property="twitter:card"><meta content="@joinmobilizon" property="twitter:site"><meta content="#{group.avatar.url}" property="og:image"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"#{group.name}","position":1}]}</script><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"image":"#{group.banner.url}","name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar"><link href="#{group.url}" rel="alternate" type="application/activity+json"><link href="#{group.url}" rel="canonical"><meta content="noindex" name="robots"> + <meta content="#{group.name}" property="og:title"><meta content="#{URI.decode(Routes.page_url(Endpoint, :actor, Actor.preferred_username_and_domain(group)))}" property="og:url"><meta content="The event organizer didn't add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{Actor.preferred_username_and_domain(group)}" property="profile:username"><meta content="summary" property="twitter:card"><meta content="@joinmobilizon" property="twitter:site"><meta content="#{group.avatar.url}" property="og:image"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"#{group.name}","position":1}]}</script><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"image":"#{group.banner.url}","name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar"><link href="#{group.url}" rel="alternate" type="application/activity+json"><link href="#{group.url}" rel="canonical"><meta content="noindex" name="robots"> """) assert group @@ -26,7 +26,7 @@ defmodule Mobilizon.Service.MetadataTest do |> Metadata.build_tags() |> Metadata.Utils.stringify_tags() == String.trim(""" - <meta content="#{group.name} (@#{group.preferred_username}@#{group.domain})" property="og:title"><meta content="#{URI.decode(Routes.page_url(Endpoint, :actor, Actor.preferred_username_and_domain(group)))}" property="og:url"><meta content="The event organizer didn't add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{Actor.preferred_username_and_domain(group)}" property="profile:username"><meta content="summary" property="twitter:card"><meta content="@joinmobilizon" property="twitter:site"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"#{group.name}","position":1}]}</script><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"image":"#{group.banner.url}","name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar"><link href="#{group.url}" rel="alternate" type="application/activity+json"><link href="#{group.url}" rel="canonical"><meta content="noindex" name="robots"> + <meta content="#{group.name}" property="og:title"><meta content="#{URI.decode(Routes.page_url(Endpoint, :actor, Actor.preferred_username_and_domain(group)))}" property="og:url"><meta content="The event organizer didn't add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{Actor.preferred_username_and_domain(group)}" property="profile:username"><meta content="summary" property="twitter:card"><meta content="@joinmobilizon" property="twitter:site"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"#{group.name}","position":1}]}</script><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"image":"#{group.banner.url}","name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, Actor.preferred_username_and_domain(group), "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar"><link href="#{group.url}" rel="alternate" type="application/activity+json"><link href="#{group.url}" rel="canonical"><meta content="noindex" name="robots"> """) end @@ -144,7 +144,7 @@ defmodule Mobilizon.Service.MetadataTest do |> Metadata.build_tags() |> Metadata.Utils.stringify_tags() == String.trim(""" - <meta content="#{comment.actor.preferred_username}" property="og:title"><meta content="#{comment.url}" property="og:url"><meta content="#{comment.text}" property="og:description"><meta content="website" property="og:type"><meta content="summary" property="twitter:card"> + <meta content="#{comment.actor.name}" property="og:title"><meta content="#{comment.url}" property="og:url"><meta content="#{comment.text}" property="og:description"><meta content="website" property="og:type"><meta content="summary" property="twitter:card"> """) end end