From 9e19658ee0e4d7902fb81e87dc6fcc35ffbd88f9 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Fri, 11 Sep 2026 20:21:01 +0200 Subject: [PATCH] Take a link preview's host as a domain name, not an address A browser rewrites the many spellings of an address into one before it fetches, so "http://2130706433/rooms/1" arrives at 127.0.0.1 while a comparison here still reads the digits. A preview names a page on the public internet, so require its host to look like a domain name and leave the rewriting race alone. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt --- lib/rails_ext/actiontext_opengraph_embeds.rb | 10 +++++++++- test/lib/rails_ext/actiontext_opengraph_embeds_test.rb | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/rails_ext/actiontext_opengraph_embeds.rb b/lib/rails_ext/actiontext_opengraph_embeds.rb index 888b405..712844d 100644 --- a/lib/rails_ext/actiontext_opengraph_embeds.rb +++ b/lib/rails_ext/actiontext_opengraph_embeds.rb @@ -42,11 +42,19 @@ class ActionText::Attachment::OpengraphEmbed # while a browser still unescapes it back to us, so an escaped host is out # too, and neither case is anything an unfurl could have produced. def elsewhere?(host) - return false if host.blank? || host.include?("%") + return false unless named_host?(host) canonical_host(host) != canonical_host(Current.request_host.to_s) end + # A preview names a page on the public internet, so its host is a domain + # name: it has a dot and a letter in it, and no escapes. A bare address is + # not one, and a browser rewrites the many spellings of an address into a + # single one before it fetches, which is a race a comparison here loses. + def named_host?(host) + host.present? && host.exclude?("%") && host.include?(".") && host.match?(/[a-z]/i) + end + def canonical_host(host) host.downcase.delete_suffix(".") end diff --git a/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb b/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb index 523232f..a93360b 100644 --- a/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb +++ b/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb @@ -36,6 +36,16 @@ class ActionText::Attachment::OpengraphEmbedTest < ActiveSupport::TestCase end end + test "drops a link and an image on a bare address rather than a domain name" do + [ "http://127.0.0.1/rooms/1", "http://2130706433/rooms/1", "http://0177.0.0.1/rooms/1", + "http://[::1]/rooms/1", "http://localhost/rooms/1", "https://203.0.113.10/image.png" ].each do |value| + embed = embed_from href: value, url: value + + assert_nil embed.href, "expected #{value.inspect} to be dropped as a link" + assert_nil embed.url, "expected #{value.inspect} to be dropped as an image" + end + end + test "renders the image and the link when both are web URLs" do html = render_embed href: "https://example.com/page", url: "https://example.com/image.png"