mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-09-16 21:42:04 +09:00
ef4b88d748
Ruby leaves a percent-escape in URI#host, so "https://%77ww.example.com" read as a different host than the one Campfire answers on while a browser unescaped it straight back to us. A host that carries an escape, or a trailing dot, is now measured the way the browser will read it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
73 lines
2.1 KiB
Ruby
73 lines
2.1 KiB
Ruby
class ActionText::Attachment::OpengraphEmbed
|
|
include ActiveModel::Model
|
|
|
|
OPENGRAPH_EMBED_CONTENT_TYPE = "application/vnd.actiontext.opengraph-embed"
|
|
|
|
class << self
|
|
def from_node(node)
|
|
if node["content-type"]
|
|
if matches = node["content-type"].match(OPENGRAPH_EMBED_CONTENT_TYPE)
|
|
attachment = new(attributes_from_node(node))
|
|
attachment if attachment.valid?
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
def attributes_from_node(node)
|
|
{
|
|
href: web_url(node["href"]),
|
|
url: web_url(node["url"]),
|
|
filename: node["filename"],
|
|
description: node["caption"]
|
|
}
|
|
end
|
|
|
|
# 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) && 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. A percent-escape hides our hostname from this comparison
|
|
# 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?("%")
|
|
|
|
canonical_host(host) != canonical_host(Current.request_host.to_s)
|
|
end
|
|
|
|
def canonical_host(host)
|
|
host.downcase.delete_suffix(".")
|
|
end
|
|
end
|
|
|
|
attr_accessor :href, :url, :filename, :description
|
|
|
|
def attachable_content_type
|
|
OPENGRAPH_EMBED_CONTENT_TYPE
|
|
end
|
|
|
|
def attachable_plain_text_representation(caption)
|
|
""
|
|
end
|
|
|
|
def to_partial_path
|
|
"action_text/attachables/opengraph_embed"
|
|
end
|
|
|
|
def to_trix_content_attachment_partial_path
|
|
"action_text/attachables/opengraph_embed"
|
|
end
|
|
end
|