discourse/lib/validators/upload_validator.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

140 lines
3.8 KiB
Ruby

# frozen_string_literal: true
require_dependency "file_helper"
module Validators; end
class Validators::UploadValidator < ActiveModel::Validator
def validate(upload)
# staff can upload any file in PM
if (upload.for_private_message && SiteSetting.allow_staff_to_upload_any_file_in_pm)
return true if upload.user&.staff?
end
# check the attachment blacklist
if upload.for_group_message && SiteSetting.allow_all_attachments_for_group_messages
return upload.original_filename =~ SiteSetting.attachment_filename_blacklist_regex
end
extension = File.extname(upload.original_filename)[1..-1] || ""
if upload.for_site_setting &&
upload.user&.staff? &&
FileHelper.is_supported_image?(upload.original_filename)
return true
end
if is_authorized?(upload, extension)
if FileHelper.is_supported_image?(upload.original_filename)
authorized_image_extension(upload, extension)
maximum_image_file_size(upload)
else
authorized_attachment_extension(upload, extension)
maximum_attachment_file_size(upload)
end
end
end
def is_authorized?(upload, extension)
extension_authorized?(upload, extension, authorized_extensions(upload))
end
def authorized_image_extension(upload, extension)
extension_authorized?(upload, extension, authorized_images(upload))
end
def maximum_image_file_size(upload)
maximum_file_size(upload, "image")
end
def authorized_attachment_extension(upload, extension)
extension_authorized?(upload, extension, authorized_attachments(upload))
end
def maximum_attachment_file_size(upload)
maximum_file_size(upload, "attachment")
end
private
def extensions_to_set(exts)
extensions = Set.new
exts
.gsub(/[\s\.]+/, "")
.downcase
.split("|")
.each { |extension| extensions << extension unless extension.include?("*") }
extensions
end
def authorized_extensions(upload)
extensions = if upload.for_theme
SiteSetting.theme_authorized_extensions
elsif upload.for_export
SiteSetting.export_authorized_extensions
else
SiteSetting.authorized_extensions
end
extensions_to_set(extensions)
end
def authorized_images(upload)
authorized_extensions(upload) & FileHelper.supported_images
end
def authorized_attachments(upload)
authorized_extensions(upload) - FileHelper.supported_images
end
def authorizes_all_extensions?(upload)
if upload.user&.staff?
return true if SiteSetting.authorized_extensions_for_staff.include?("*")
end
extensions = if upload.for_theme
SiteSetting.theme_authorized_extensions
elsif upload.for_export
SiteSetting.export_authorized_extensions
else
SiteSetting.authorized_extensions
end
extensions.include?("*")
end
def extension_authorized?(upload, extension, extensions)
return true if authorizes_all_extensions?(upload)
staff_extensions = Set.new
if upload.user&.staff?
staff_extensions = extensions_to_set(SiteSetting.authorized_extensions_for_staff)
return true if staff_extensions.include?(extension.downcase)
end
unless authorized = extensions.include?(extension.downcase)
message = I18n.t("upload.unauthorized", authorized_extensions: (extensions | staff_extensions).to_a.join(", "))
upload.errors.add(:original_filename, message)
end
authorized
end
def maximum_file_size(upload, type)
max_size_kb = if upload.for_export
SiteSetting.max_export_file_size_kb
else
SiteSetting.get("max_#{type}_size_kb")
end
max_size_bytes = max_size_kb.kilobytes
if upload.filesize > max_size_bytes
message = I18n.t("upload.#{type}s.too_large", max_size_kb: max_size_kb)
upload.errors.add(:filesize, message)
end
end
end