From 07841722ac71919787d42f1e07615eb0084f58e3 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 21 May 2026 15:38:16 +0300 Subject: [PATCH] adjust image load --- Dockerfile | 1 + app/controllers/api/attachments_controller.rb | 6 ++-- lib/image_utils.rb | 15 ++++++++++ lib/submissions/generate_audit_trail.rb | 2 +- .../generate_result_attachments.rb | 25 ++++------------ lib/submitters.rb | 29 +++++++------------ lib/submitters/create_stamp_attachment.rb | 2 +- lib/templates/detect_fields.rb | 2 +- lib/templates/process_document.rb | 11 ++----- 9 files changed, 42 insertions(+), 51 deletions(-) diff --git a/Dockerfile b/Dockerfile index 722223b2..61a2269f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -94,6 +94,7 @@ WORKDIR /data/docuseal ENV HOME=/home/docuseal ENV WORKDIR=/data/docuseal ENV VIPS_MAX_COORD=17000 +ENV VIPS_BLOCK_UNTRUSTED=1 EXPOSE 3000 CMD ["/app/bin/bundle", "exec", "puma", "-C", "/app/config/puma.rb", "--dir", "/app"] diff --git a/app/controllers/api/attachments_controller.rb b/app/controllers/api/attachments_controller.rb index 2f615878..1d24f8ca 100644 --- a/app/controllers/api/attachments_controller.rb +++ b/app/controllers/api/attachments_controller.rb @@ -16,8 +16,10 @@ module Api return render json: { error: I18n.t('form_has_been_archived') }, status: :unprocessable_content end + file = params[:file] + if params[:type].in?(%w[initials signature]) - image = Vips::Image.new_from_file(params[:file].path) + image = ImageUtils.load_vips(file.read, content_type: file.content_type) if ImageUtils.blank?(image) Rollbar.error("Empty signature: #{@submitter.id}") if defined?(Rollbar) @@ -33,7 +35,7 @@ module Api end end - attachment = Submitters.create_attachment!(@submitter, params) + attachment = Submitters.create_attachment!(@submitter, file) if params[:remember_signature] == 'true' && @submitter.email.present? cookies.encrypted[:signature_uuids] = build_new_cookie_signatures_json(@submitter, attachment) diff --git a/lib/image_utils.rb b/lib/image_utils.rb index 8e7aa094..c0325736 100644 --- a/lib/image_utils.rb +++ b/lib/image_utils.rb @@ -1,8 +1,23 @@ # frozen_string_literal: true module ImageUtils + ICO_REGEXP = %r{\Aimage/(?:x-icon|vnd\.microsoft\.icon)\z} + BMP_REGEXP = %r{\Aimage/(?:bmp|x-bmp|x-ms-bmp)\z} + module_function + def load_vips(data, content_type: nil) + content_type ||= Marcel::MimeType.for(data) + + if ICO_REGEXP.match?(content_type) + LoadIco.call(data) + elsif BMP_REGEXP.match?(content_type) + LoadBmp.call(data) + else + Vips::Image.new_from_buffer(data, '') + end + end + def blank?(image) stats = image.stats diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb index 2778ee4e..57a9d1c1 100644 --- a/lib/submissions/generate_audit_trail.rb +++ b/lib/submissions/generate_audit_trail.rb @@ -363,7 +363,7 @@ module Submissions image = begin - Submissions::GenerateResultAttachments.load_vips_image(attachment).autorot + ImageUtils.load_vips(attachment.download, content_type: attachment.content_type).autorot rescue Vips::Error next unless attachment.content_type.starts_with?('image/') next if attachment.byte_size.zero? diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index 50022b9b..03cfeba0 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -11,9 +11,6 @@ module Submissions 'Helvetica' end - ICO_REGEXP = %r{\Aimage/(?:x-icon|vnd\.microsoft\.icon)\z} - BMP_REGEXP = %r{\Aimage/(?:bmp|x-bmp|x-ms-bmp)\z} - FONT_BOLD_NAME = if File.exist?(FONT_BOLD_PATH) FONT_BOLD_PATH else @@ -313,7 +310,9 @@ module Submissions image = begin - load_vips_image(attachment, attachments_data_cache).autorot + attachments_data_cache[attachment.uuid] ||= attachment.download + + ImageUtils.load_vips(attachments_data_cache[attachment.uuid], content_type: attachment.content_type).autorot rescue Vips::Error next unless attachment.content_type.starts_with?('image/') next if attachment.byte_size.zero? @@ -451,7 +450,9 @@ module Submissions image = begin - load_vips_image(attachment, attachments_data_cache).autorot + attachments_data_cache[attachment.uuid] ||= attachment.download + + ImageUtils.load_vips(attachments_data_cache[attachment.uuid], content_type: attachment.content_type).autorot rescue Vips::Error next unless attachment.content_type.starts_with?('image/') next if attachment.byte_size.zero? @@ -1021,20 +1022,6 @@ module Submissions [] end - def load_vips_image(attachment, cache = {}) - cache[attachment.uuid] ||= attachment.download - - data = cache[attachment.uuid] - - if ICO_REGEXP.match?(attachment.content_type) - LoadIco.call(data) - elsif BMP_REGEXP.match?(attachment.content_type) - LoadBmp.call(data) - else - Vips::Image.new_from_buffer(data, '') - end - end - def r Rails.application.routes.url_helpers end diff --git a/lib/submitters.rb b/lib/submitters.rb index 6e14b594..cdb4ee43 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -122,27 +122,20 @@ module Submitters end end - def create_attachment!(submitter, params) - blob = - if (file = params[:file]) - extension = File.extname(file.original_filename).delete_prefix('.').downcase + def create_attachment!(submitter, file) + raise ParamsError, 'file param is missing' if file.blank? - if DANGEROUS_EXTENSIONS.include?(extension) - raise MaliciousFileExtension, "File type '.#{extension}' is not allowed." - end + extension = File.extname(file.original_filename).delete_prefix('.').downcase - ActiveStorage::Blob.create_and_upload!(io: file.open, - filename: file.original_filename, - content_type: file.content_type) - else - raise ParamsError, 'file param is missing' - end + if DANGEROUS_EXTENSIONS.include?(extension) + raise MaliciousFileExtension, "File type '.#{extension}' is not allowed." + end - ActiveStorage::Attachment.create!( - blob:, - name: 'attachments', - record: submitter - ) + blob = ActiveStorage::Blob.create_and_upload!(io: file.tap(&:rewind).open, + filename: file.original_filename, + content_type: file.content_type) + + ActiveStorage::Attachment.create!(blob:, name: 'attachments', record: submitter) end def normalize_preferences(account, user, params) diff --git a/lib/submitters/create_stamp_attachment.rb b/lib/submitters/create_stamp_attachment.rb index 18e6830a..9e6700c8 100644 --- a/lib/submitters/create_stamp_attachment.rb +++ b/lib/submitters/create_stamp_attachment.rb @@ -40,7 +40,7 @@ module Submitters def generate_stamp_image(submitter, with_logo: true) logo = if with_logo - Vips::Image.new_from_buffer(load_logo(submitter).read, '') + ImageUtils.load_vips(load_logo(submitter).read) else Vips::Image.new_from_buffer(TRANSPARENT_PIXEL, '').resize(WIDTH) end diff --git a/lib/templates/detect_fields.rb b/lib/templates/detect_fields.rb index 4d2fa0a7..4a620d1b 100755 --- a/lib/templates/detect_fields.rb +++ b/lib/templates/detect_fields.rb @@ -77,7 +77,7 @@ module Templates split_page: false, aspect_ratio: false, padding: nil, page_number: nil) return [[], nil] if page_number && page_number != 0 - image = Vips::Image.new_from_buffer(io.read, '') + image = ImageUtils.load_vips(io.read, content_type: attachment.content_type) fields = inference.call(image, confidence:, nms:, nmm:, split_page:, temperature:, aspect_ratio:, padding:) diff --git a/lib/templates/process_document.rb b/lib/templates/process_document.rb index af4e1697..4b216dba 100644 --- a/lib/templates/process_document.rb +++ b/lib/templates/process_document.rb @@ -7,7 +7,6 @@ module Templates PREVIEW_FORMAT = '.jpg' ATTACHMENT_NAME = 'preview_images' - BMP_REGEXP = %r{\Aimage/(?:bmp|x-bmp|x-ms-bmp)\z} PDF_CONTENT_TYPE = 'application/pdf' CONCURRENCY = 2 Q = 95 @@ -59,14 +58,8 @@ module Templates def generate_preview_image(attachment, data) ActiveStorage::Attachment.where(name: ATTACHMENT_NAME, record: attachment).destroy_all - image = - if BMP_REGEXP.match?(attachment.content_type) - LoadBmp.call(data) - else - Vips::Image.new_from_buffer(data, '') - end - - image = image.autorot.resize(MAX_WIDTH / image.width.to_f) + image = ImageUtils.load_vips(data, content_type: attachment.content_type).autorot + image = image.resize(MAX_WIDTH / image.width.to_f) bitdepth = 2**image.stats.to_a[1..3].pluck(2).uniq.size