handle dangerous extensions

This commit is contained in:
Pete Matsyburka
2026-05-18 17:51:50 +03:00
parent 6806772346
commit 354bccd6e8
5 changed files with 53 additions and 11 deletions
+27 -11
View File
@@ -212,8 +212,8 @@ module Submitters
elsif type.in?(%w[signature initials]) && value.length < 60
find_or_create_blob_from_text(account, value, type)
elsif (data = Base64.decode64(value.sub(BASE64_PREFIX_REGEXP, ''))) &&
Marcel::MimeType.for(data).exclude?('octet-stream')
find_or_create_blob_from_base64(account, data, type)
(mime_type = Marcel::MimeType.for(data)).exclude?('octet-stream')
find_or_create_blob_from_base64(account, data, type, mime_type:)
elsif type == 'image' && (value.starts_with?('<html>') || value.starts_with?('<!DOCTYPE'))
raise InvalidDefaultValue, "Invalid #{type} value" unless purpose == :api
@@ -236,15 +236,27 @@ module Submitters
raise InvalidDefaultValue, "HTML content is not allowed: #{value.first(200)}..."
end
def find_or_create_blob_from_base64(account, data, type)
def find_or_create_blob_from_base64(account, data, type, mime_type: nil)
checksum = Digest::MD5.base64digest(data)
blob = find_blob_by_checksum(checksum, account)
blob || ActiveStorage::Blob.create_and_upload!(
io: StringIO.new(data),
filename: "#{type}.png"
)
return blob if blob
mime_type ||= Marcel::MimeType.for(data)
detected_extensions = Marcel::TYPE_EXTS[mime_type].to_a.map(&:downcase)
if detected_extensions.any? { |e| Submitters::DANGEROUS_EXTENSIONS.include?(e) }
raise InvalidDefaultValue, "File type '.#{detected_extensions.first}' is not allowed."
end
extension = detected_extensions.first
extension = 'png' if extension.blank? && type.in?(%w[signature initials stamp image])
filename = extension.present? ? "#{type}.#{extension}" : type
ActiveStorage::Blob.create_and_upload!(io: StringIO.new(data), filename:)
end
def find_or_create_blob_from_text(account, text, type)
@@ -261,6 +273,13 @@ module Submitters
end
def find_or_create_blob_from_url(account, url)
filename = Addressable::URI.parse(url).path.split('/').last.to_s
extension = File.extname(filename).delete_prefix('.').downcase
if Submitters::DANGEROUS_EXTENSIONS.include?(extension)
raise InvalidDefaultValue, "File type '.#{extension}' is not allowed."
end
cache_key = [account.id, url].join(':')
checksum = CHECKSUM_CACHE_STORE.fetch(cache_key)
@@ -276,10 +295,7 @@ module Submitters
blob = find_blob_by_checksum(checksum, account)
blob || ActiveStorage::Blob.create_and_upload!(
io: StringIO.new(data),
filename: Addressable::URI.parse(url).path.split('/').last
)
blob || ActiveStorage::Blob.create_and_upload!(io: StringIO.new(data), filename:)
end
def find_blob_by_checksum(checksum, account)