mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-04 13:53:38 +09:00
eab554aa4b
Main strips a javascript: href from a preview node before it's parsed, so tell legacy Trix attachments apart by their filename instead. escapeHTML moved to the string helpers, and the unfurling system test now drives the Lexxy editor.
102 lines
2.9 KiB
Ruby
102 lines
2.9 KiB
Ruby
require "application_system_test_case"
|
|
require "socket"
|
|
|
|
class UnfurlingLinksTest < ApplicationSystemTestCase
|
|
setup do
|
|
@website = Website.new
|
|
@website.start
|
|
RestrictedHTTP::PrivateNetworkGuard.stubs(:resolve).returns("127.0.0.1")
|
|
|
|
sign_in "jz@37signals.com"
|
|
join_room rooms(:designers)
|
|
end
|
|
|
|
teardown do
|
|
@website.stop
|
|
end
|
|
|
|
test "a quote in the opengraph image URL cannot add attributes to the preview" do
|
|
paste_in_composer @website.page_url
|
|
|
|
assert_selector "#composer lexxy-editor .og-embed__title", text: "A normal looking link"
|
|
|
|
assert_equal @website.image_url, preview_image_attributes["src"]
|
|
assert_empty preview_image_attributes.keys - %w[ src class alt ]
|
|
end
|
|
|
|
private
|
|
def preview_image_attributes
|
|
page.evaluate_script(<<~JS)
|
|
Object.fromEntries(Array.from(document.querySelector("#composer lexxy-editor .og-embed__image img").attributes, attribute => [ attribute.name, attribute.value ]))
|
|
JS
|
|
end
|
|
|
|
# Serves a page whose og:image URL carries a double quote, so an unescaped
|
|
# preview closes the src attribute early and takes the rest as attributes.
|
|
class Website
|
|
def start
|
|
@socket = TCPServer.new("127.0.0.1", 0)
|
|
@thread = Thread.new { serve }
|
|
end
|
|
|
|
def stop
|
|
@thread&.kill
|
|
@socket&.close
|
|
end
|
|
|
|
def page_url
|
|
"http://127.0.0.1:#{port}/page.html"
|
|
end
|
|
|
|
def image_url
|
|
%(http://127.0.0.1:#{port}/image.png?from=" style="outline:9px solid red)
|
|
end
|
|
|
|
private
|
|
def port
|
|
@socket.addr[1]
|
|
end
|
|
|
|
def serve
|
|
loop do
|
|
client = @socket.accept
|
|
Thread.new(client) { |connection| respond_to(connection) }
|
|
end
|
|
rescue IOError, Errno::EBADF
|
|
nil
|
|
end
|
|
|
|
def respond_to(client)
|
|
request_line = client.gets.to_s
|
|
nil while (line = client.gets) && line != "\r\n"
|
|
|
|
method, path = request_line.split(" ")
|
|
|
|
if path.to_s.start_with?("/image.png")
|
|
respond client, "image/png", method == "HEAD" ? "" : "not really a PNG"
|
|
else
|
|
respond client, "text/html", page
|
|
end
|
|
rescue IOError, Errno::ECONNRESET
|
|
nil
|
|
ensure
|
|
client.close rescue nil
|
|
end
|
|
|
|
def respond(client, content_type, body)
|
|
client.write "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{body.bytesize}\r\nConnection: close\r\n\r\n#{body}"
|
|
end
|
|
|
|
def page
|
|
<<~HTML
|
|
<html><head>
|
|
<meta property="og:url" content="https://example.com/harmless">
|
|
<meta property="og:title" content="A normal looking link">
|
|
<meta property="og:description" content="Nothing to see here">
|
|
<meta property="og:image" content='#{image_url}'>
|
|
</head><body>Hello</body></html>
|
|
HTML
|
|
end
|
|
end
|
|
end
|