mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-09-13 03:52:05 +09:00
Keep a link preview's link and image off this Campfire's own host
A preview belongs to the page it previews, so both URLs point somewhere else. An absolute URL on our own host passed the scheme and host checks, and every reader's browser fetched it with their session attached, which turns a message into a GET request made on the reader's behalf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
This commit is contained in:
@@ -23,20 +23,25 @@ class ActionText::Attachment::OpengraphEmbed
|
||||
}
|
||||
end
|
||||
|
||||
# A link preview points at what we unfurled, which is always an absolute
|
||||
# http or https URL naming a host. Drop anything else the message body asks
|
||||
# for, so a body written by hand can't aim the preview's link or its image at
|
||||
# another scheme or at a path on this Campfire. A URL like "https:/rooms/1"
|
||||
# needs the host check as well as the scheme one: Ruby parses it as HTTPS,
|
||||
# and a browser resolves it against whatever origin Campfire is served from.
|
||||
# A link preview points at what we unfurled: an absolute http or https URL
|
||||
# on some other host. Drop anything else a message body asks for, so it
|
||||
# can't aim the preview's link or its image at this Campfire and have every
|
||||
# reader's browser fetch it with their session attached.
|
||||
def web_url(value)
|
||||
return if value.blank?
|
||||
|
||||
parsed = URI.parse(value)
|
||||
value if parsed.is_a?(URI::HTTP) && parsed.host.present?
|
||||
value if parsed.is_a?(URI::HTTP) && elsewhere?(parsed.host)
|
||||
rescue URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
||||
# "https:/rooms/1" parses as HTTPS with no host at all, and a browser
|
||||
# resolves both that and our own hostname against the origin Campfire is
|
||||
# served from.
|
||||
def elsewhere?(host)
|
||||
host.present? && !host.casecmp?(Current.request_host.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :href, :url, :filename, :description
|
||||
|
||||
@@ -35,6 +35,22 @@ class RoomsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_match "Free cookies", response.body
|
||||
end
|
||||
|
||||
test "show renders a link preview written by hand without its image pointed at this Campfire" do
|
||||
room = rooms(:watercooler)
|
||||
own_url = room_url(room, host: "www.example.com")
|
||||
post room_messages_url(room, format: :turbo_stream), params: { message: {
|
||||
body: link_preview_body(href: own_url, url: own_url),
|
||||
client_message_id: "same-host-preview" } }
|
||||
assert_response :success
|
||||
|
||||
get room_url(room)
|
||||
|
||||
assert_response :success
|
||||
assert_no_match %r{<img src="#{Regexp.escape(own_url)}"}, response.body
|
||||
assert_no_match %r{<a rel="noreferrer" target="_blank" href="#{Regexp.escape(own_url)}"}, response.body
|
||||
assert_match "Free cookies", response.body
|
||||
end
|
||||
|
||||
test "show renders an unfurled link preview" do
|
||||
room = rooms(:watercooler)
|
||||
post room_messages_url(room, format: :turbo_stream), params: { message: {
|
||||
|
||||
@@ -19,6 +19,22 @@ class ActionText::Attachment::OpengraphEmbedTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test "drops a link and an image on this Campfire's own host" do
|
||||
Current.set request: ActionDispatch::TestRequest.create("HTTP_HOST" => "once.campfire.test") do
|
||||
[ "https://once.campfire.test/rooms/1", "http://once.campfire.test/rooms/1",
|
||||
"https://ONCE.Campfire.Test/rooms/1" ].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
|
||||
|
||||
embed = embed_from href: "https://example.com/page", url: "https://example.com/image.png"
|
||||
assert_equal "https://example.com/page", embed.href
|
||||
assert_equal "https://example.com/image.png", embed.url
|
||||
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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user