Use custom sanitizer config for PDF reports generation [SCI-9368]

This commit is contained in:
Oleksii Kriuchykhin 2023-10-03 09:31:13 +02:00
parent 9745ef62dc
commit d9404df361
9 changed files with 58 additions and 35 deletions

View file

@ -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

View file

@ -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)

View file

@ -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')

View file

@ -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

View file

@ -51,7 +51,7 @@
<div class="row">
<div class="col-xs-12">
<% if my_module.description.present? %>
<%= custom_auto_link(my_module.prepare_for_report(:description, export_all),
<%= custom_auto_link(my_module.prepare_for_report(:description),
team: current_team,
simple_format: false,
base64_encoded_imgs: export_all) %>

View file

@ -14,7 +14,7 @@
</div>
<div class="row module-protocol-description">
<% if @settings.dig('task', 'protocol', 'description') && protocol.description.present? %>
<%= custom_auto_link(protocol.prepare_for_report(:description, export_all),
<%= custom_auto_link(protocol.prepare_for_report(:description),
team: current_team,
simple_format: false,
base64_encoded_imgs: export_all) %>

View file

@ -19,7 +19,7 @@
<div class="row">
<div class="col-xs-12">
<div class="text-container ql-editor">
<%= custom_auto_link(result_text.prepare_for_report(:text, export_all),
<%= custom_auto_link(result_text.prepare_for_report(:text),
team: current_team,
simple_format: false,
tags: %w(img),

View file

@ -1,11 +1,11 @@
<div class="report-element report-step-attachment-element report-step-text-element">
<div class="report-element-body">
<% if step_text.text.present? %>
<%= custom_auto_link(step_text.prepare_for_report(:text, export_all),
team: current_team,
simple_format: false,
tags: %w(img),
base64_encoded_imgs: export_all) %>
<%= custom_auto_link(step_text.prepare_for_report(:text),
team: current_team,
simple_format: false,
tags: %w(img),
base64_encoded_imgs: export_all) %>
<% else %>
<em><%= t('projects.reports.elements.step.no_description') %></em>
<% end %>

View file

@ -60,6 +60,8 @@ module Scinote
config.x.connected_devices_enabled = ENV['CONNECTED_DEVICES_ENABLED'] == 'true'
config.x.custom_sanitizer_config = nil
# Logging
config.log_formatter = proc do |severity, datetime, progname, msg|
"[#{datetime}] #{severity}: #{msg}\n"