diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1f5d3ae55..95b0d76fe 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -144,7 +144,7 @@ module ApplicationHelper popover_for_user_name(user, team, false, false, base64_encoded_imgs) end - new_text + sanitize_input(new_text) end # Generate smart annotation link for one user object diff --git a/app/helpers/input_sanitize_helper.rb b/app/helpers/input_sanitize_helper.rb index 2dfc2ae00..e8a98be6a 100644 --- a/app/helpers/input_sanitize_helper.rb +++ b/app/helpers/input_sanitize_helper.rb @@ -4,8 +4,16 @@ require 'sanitize' require 'cgi' module InputSanitizeHelper - def sanitize_input(html, _tags = [], _attributes = [], sanitizer_config: Constants::INPUT_SANITIZE_CONFIG) - Sanitize.fragment(html, sanitizer_config).html_safe + def sanitize_input(html, _tags = [], _attributes = [], sanitizer_config: nil) + config = + if Rails.application.config.x.custom_sanitizer_config.present? + Rails.application.config.x.custom_sanitizer_config + elsif sanitizer_config.present? + sanitizer_config + else + Constants::INPUT_SANITIZE_CONFIG + end + Sanitize.fragment(html, config).html_safe end def escape_input(text) diff --git a/app/jobs/reports/pdf_job.rb b/app/jobs/reports/pdf_job.rb index 2bce30b56..e17dbe74c 100644 --- a/app/jobs/reports/pdf_job.rb +++ b/app/jobs/reports/pdf_job.rb @@ -34,19 +34,22 @@ module Reports proxy.set_user(user, scope: :user, store: false) ApplicationController.renderer.defaults[:http_host] = Rails.application.routes.default_url_options[:host] renderer = ApplicationController.renderer.new(warden: proxy) + Rails.application.config.x.custom_sanitizer_config = build_custom_sanitizer_config file << renderer.render( - pdf: 'report', header: { html: { template: "reports/templates/#{template}/header", - locals: { report: report, user: user, logo: report_logo }, - layout: 'reports/footer_header' } }, - footer: { html: { template: "reports/templates/#{template}/footer", - locals: { report: report, user: user, logo: report_logo }, - layout: 'reports/footer_header' } }, - assigns: { settings: report.settings }, - locals: { report: report }, - disable_javascript: false, - template: 'reports/report', - formats: :pdf + pdf: 'report', + header: { html: { template: "reports/templates/#{template}/header", + locals: { report: report, user: user, logo: report_logo }, + layout: 'reports/footer_header' } }, + footer: { html: { template: "reports/templates/#{template}/footer", + locals: { report: report, user: user, logo: report_logo }, + layout: 'reports/footer_header' } }, + assigns: { settings: report.settings }, + locals: { report: report }, + disable_javascript: false, + disable_external_links: true, + template: 'reports/report', + formats: :pdf ) file.rewind @@ -69,6 +72,7 @@ module Reports ) notification.create_user_notification(user) ensure + Rails.application.config.x.custom_sanitizer_config = nil I18n.backend.date_format = nil file.close(true) end @@ -178,6 +182,15 @@ module Reports 'scinote_logo.svg' end + def build_custom_sanitizer_config + sanitizer_config = Constants::INPUT_SANITIZE_CONFIG.deep_dup + sanitizer_config[:protocols] = { + 'a' => { 'href' => ['http', 'https', :relative] }, + 'img' => { 'src' => %w(data) } + } + sanitizer_config + end + # Overrides method from FailedDeliveryNotifiableJob concern def failed_notification_title I18n.t('projects.reports.index.generation.error_pdf_notification_title') diff --git a/app/models/concerns/tiny_mce_images.rb b/app/models/concerns/tiny_mce_images.rb index dd59f6a2d..5cf536180 100644 --- a/app/models/concerns/tiny_mce_images.rb +++ b/app/models/concerns/tiny_mce_images.rb @@ -13,7 +13,7 @@ module TinyMceImages before_save :clean_tiny_mce_image_urls after_create :ensure_extracted_image_object_references - def prepare_for_report(field, base64_encoded_imgs = false) + def prepare_for_report(field) description = self[field] # Check tinymce for old format @@ -21,13 +21,9 @@ module TinyMceImages tiny_mce_assets.each do |tm_asset| next unless tm_asset&.image&.attached? + begin - new_tm_asset_src = - if base64_encoded_imgs - tm_asset.convert_variant_to_base64(tm_asset.preview) - else - tm_asset.preview.processed.url(expires_in: Constants::URL_LONG_EXPIRE_TIME) - end + new_tm_asset_src = tm_asset.convert_variant_to_base64(tm_asset.preview) rescue ActiveStorage::FileNotFoundError next end @@ -114,13 +110,17 @@ module TinyMceImages next if asset.object == self next unless asset.can_read?(user) else - url = image['src'] - image_type = FastImage.type(url).to_s - next unless image_type - + image_type = nil begin - new_image = Down.download(url, max_size: Rails.configuration.x.file_max_size_mb.megabytes) - rescue Down::TooLarge => e + uri = URI.parse(image['src']) + if uri.scheme != 'https' + uri.scheme = Rails.application.config.force_ssl ? 'https' : 'http' + end + image_type = FastImage.type(uri.to_s).to_s + next unless image_type + + new_image = Down.download(uri.to_s, max_size: Rails.configuration.x.file_max_size_mb.megabytes) + rescue StandardError => e Rails.logger.error e.message next end diff --git a/app/views/reports/elements/_my_module_element.html.erb b/app/views/reports/elements/_my_module_element.html.erb index 7056f4356..254f5c7be 100644 --- a/app/views/reports/elements/_my_module_element.html.erb +++ b/app/views/reports/elements/_my_module_element.html.erb @@ -51,7 +51,7 @@