mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-09-15 21:12:04 +09:00
5742dfaf73
Link previews fetch a page's OpenGraph title and description, and Opengraph::Metadata strips tags from both before the values reach the browser. When a field consists entirely of a markup tag, stripping leaves it blank, the metadata fails its presence validation, and the unfurl endpoint returns no content, so no preview is produced. Add regression tests at the model and controller layers that pin this: a title or description made only of a markup tag is stripped to blank and rejected, and the endpoint answers 204. The existing sanitize tests only cover fields that keep non-blank text after stripping, so this blank-and-rejected path was previously untested. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
194 lines
8.1 KiB
Ruby
194 lines
8.1 KiB
Ruby
require "test_helper"
|
|
|
|
class Opengraph::MetadataTest < ActiveSupport::TestCase
|
|
test "successful fetch" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:url" content="https://example.com">
|
|
<meta property="og:title" content="Hey!">
|
|
<meta property="og:description" content="Hello">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
assert metadata.valid?
|
|
|
|
assert_equal "https://example.com", metadata.url
|
|
assert_equal "Hey!", metadata.title
|
|
assert_equal "Hello", metadata.description
|
|
assert_equal "https://example.com/image.png", metadata.image
|
|
end
|
|
|
|
test "missing opengraph meta tags" do
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: "<html><head></head></html>", headers: { content_type: "text/html" })
|
|
opengraph = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert_not opengraph.valid?
|
|
assert_equal [ "Title can't be blank", "Description can't be blank" ], opengraph.errors.full_messages
|
|
end
|
|
|
|
test "URL uses the provided value if the returned value is missing" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:title" content="Hey!">
|
|
<meta property="og:description" content="Hello">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert metadata.valid?
|
|
assert_equal "https://www.example.com", metadata.url
|
|
end
|
|
|
|
test "URL uses the provided value if the returned value is invalid" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:url" content="/foo">
|
|
<meta property="og:title" content="Hey!">
|
|
<meta property="og:description" content="Hello">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/foo").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com/foo")
|
|
|
|
assert metadata.valid?
|
|
assert_equal "https://www.example.com/foo", metadata.url
|
|
end
|
|
|
|
test "missing response body" do
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 403, body: "", headers: { content_type: "text/html" })
|
|
assert_not Opengraph::Metadata.from_url("https://www.example.com").valid?
|
|
end
|
|
|
|
test "non html response" do
|
|
WebMock.stub_request(:get, "https://www.example.com/image").to_return(status: 200, body: "[blob]", headers: { content_type: "image/jpeg" })
|
|
assert_not Opengraph::Metadata.from_url("https://www.example.com/image").valid?
|
|
end
|
|
|
|
test "relative and invalid image URLs are ignored" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:url" content="https://example.com">
|
|
<meta property="og:title" content="Hey!">
|
|
<meta property="og:description" content="Hello">
|
|
<meta property="og:image" content="%s">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
[ "/image.png", "foo", "https/incorrect", "~/etc/password" ].each do |invalid_image_url|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body % invalid_image_url, headers: { content_type: "text/html" })
|
|
opengraph = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert opengraph.valid?
|
|
assert_nil opengraph.image
|
|
end
|
|
end
|
|
|
|
test "sanitize title and description" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:title" content="Hey!<script>alert('hi')</script>">
|
|
<meta property="og:description" content="Hello<script>alert('hi')</script>">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert metadata.valid?
|
|
assert_equal "Hey!alert('hi')", metadata.title
|
|
assert_equal "Helloalert('hi')", metadata.description
|
|
end
|
|
|
|
test "remove encoded tags from title and description" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:title" content="Hey!</script><img src=a onerror=prompt(1)>">
|
|
<meta property="og:description" content="Hello</script><img src=a onerror=prompt(2)></script>">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert metadata.valid?
|
|
assert_equal "Hey!", metadata.title
|
|
assert_equal "Hello", metadata.description
|
|
end
|
|
|
|
test "a title or description that is entirely a markup tag is stripped to blank and rejected" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:title" content="<img src='x' onerror='alert(document.domain)'/>">
|
|
<meta property="og:description" content="<img src='x' onerror='alert(document.domain)'/>">
|
|
<meta property="og:image" content="https://example.com/image.png">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.png").to_return(status: 200, headers: { content_type: "image/png" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
|
|
assert_not metadata.valid?
|
|
assert_equal "", metadata.title
|
|
assert_equal "", metadata.description
|
|
assert_includes metadata.errors.full_messages, "Title can't be blank"
|
|
assert_includes metadata.errors.full_messages, "Description can't be blank"
|
|
end
|
|
|
|
test "does not allow SVG content type for preview image" do
|
|
body = <<~HTML
|
|
<html>
|
|
<head>
|
|
<meta property="og:url" content="https://example.com">
|
|
<meta property="og:title" content="Hey!">
|
|
<meta property="og:description" content="Hello">
|
|
<meta property="og:image" content="https://example.com/image.svg">
|
|
</head>
|
|
</html>
|
|
HTML
|
|
|
|
WebMock.stub_request(:get, "https://www.example.com/").to_return(status: 200, body: body, headers: { content_type: "text/html" })
|
|
WebMock.stub_request(:head, "https://example.com/image.svg").to_return(status: 200, headers: { content_type: "image/svg+xml" })
|
|
|
|
metadata = Opengraph::Metadata.from_url("https://www.example.com")
|
|
assert metadata.valid?
|
|
|
|
assert_nil metadata.image
|
|
end
|
|
end
|