From 9b271d0e1986399236eb39d44e4c612d4cd555d2 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Thu, 15 Oct 2026 17:28:02 -0700 Subject: [PATCH] Hand auto_link text escaped the way the serializer writes it That's exactly what it was given before, with quotes and apostrophes left as they are, rather than relying on its own sanitize pass to undo h's '. Covers an email address with an apostrophe. --- app/helpers/messages_helper.rb | 4 ++-- test/helpers/messages_helper_test.rb | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb index 687d9a4..6bef743 100644 --- a/app/helpers/messages_helper.rb +++ b/app/helpers/messages_helper.rb @@ -118,13 +118,13 @@ module MessagesHelper # auto_link finds URLs and email addresses with regular expressions, which # can't tell an attribute value from text. Hand it one text node at a time, - # escaped, so a link can only land between tags. + # escaped as the serializer writes text, so a link can only land between tags. def auto_link_text(html) fragment = Nokogiri::HTML5.fragment(sanitize(html, tags: AUTO_LINK_ALLOWED_TAGS, attributes: AUTO_LINK_ALLOWED_ATTRIBUTES)) fragment.xpath(".//text()[not(ancestor::a)]").each do |node| if node.text.match?(LINKABLE_TEXT) - text = h(node.text) + text = node.to_html linked = auto_link(text, html: { target: "_blank" }) node.replace Nokogiri::HTML5.fragment(linked) unless linked == text end diff --git a/test/helpers/messages_helper_test.rb b/test/helpers/messages_helper_test.rb index 911317a..83902f5 100644 --- a/test/helpers/messages_helper_test.rb +++ b/test/helpers/messages_helper_test.rb @@ -46,6 +46,13 @@ class MessagesHelperTest < ActionView::TestCase assert_equal [ "https://example.com/a?b=1&c=2", "me@example.com" ], links.map(&:text) end + test "message_presentation links an email address with an apostrophe whole" do + message = Message.create! room: rooms(:pets), body: "
Write to o'brien@example.com
", client_message_id: "0015", creator: users(:jason) + + links = Nokogiri::HTML5.fragment(view.message_presentation(message)).css("a") + assert_equal [ [ "mailto:o%27brien@example.com", "o'brien@example.com" ] ], links.map { [ it["href"], it.text ] } + end + test "message_presentation leaves URLs and email addresses in attribute values as they are" do [ "class", "title" ].product([ "https://example.com", "www.example.com", "me@example.com" ]).each do |attribute, linkable| value = "a> #{linkable} b "