mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-03-21 21:49:05 +09:00
44 lines
1.8 KiB
Ruby
44 lines
1.8 KiB
Ruby
ActiveSupport.on_load(:action_text_content) do
|
|
class ActionText::Attachment
|
|
class << self
|
|
def from_node(node, attachable = nil)
|
|
new(node, attachable || ActionText::Attachment::OpengraphEmbed.from_node(node) || attachable_from_possibly_expired_sgid(node["sgid"]) || ActionText::Attachable.from_node(node))
|
|
end
|
|
|
|
private
|
|
# Our @mentions use ActionText attachments, which are signed. If someone rotates SECRET_KEY_BASE, the existing attachments become invalid.
|
|
# This allows ignoring invalid signatures for User attachments in ActionText.
|
|
ATTACHABLES_PERMITTED_WITH_INVALID_SIGNATURES = %w[ User ]
|
|
|
|
def attachable_from_possibly_expired_sgid(sgid)
|
|
if message = sgid&.split("--")&.first
|
|
encoded_message = JSON.parse(decode_base64(message))
|
|
|
|
decoded_gid = if data = encoded_message.dig("_rails", "data")
|
|
data
|
|
elsif data = encoded_message.dig("_rails", "message")
|
|
# Rails 7 used an older format of GID that serialized the payload using Marshall
|
|
# Since we intentionally skip signature verification, we can't safely unmarshal the data
|
|
# To work around this, we manually extract the GID from the marshaled data
|
|
decode_base64(data).match(%r{(gid://campfire/[^/]+/\d+)})&.to_s
|
|
else
|
|
nil
|
|
end
|
|
|
|
if model = GlobalID.find(decoded_gid)
|
|
model.model_name.to_s.in?(ATTACHABLES_PERMITTED_WITH_INVALID_SIGNATURES) ? model : nil
|
|
end
|
|
end
|
|
rescue ActiveRecord::RecordNotFound
|
|
nil
|
|
end
|
|
|
|
def decode_base64(message)
|
|
Base64.strict_decode64(message)
|
|
rescue => _e
|
|
Base64.urlsafe_decode64(message)
|
|
end
|
|
end
|
|
end
|
|
end
|