From 5e2545a578eabc8a52b9df3a64558f6d2bf2dfa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 20 Jun 2016 10:22:13 +0200 Subject: [PATCH] FEATURE: improve support for (whitelisted) SVGs as images --- Gemfile | 2 +- Gemfile.lock | 4 ++-- app/models/upload.rb | 49 ++++++++++++++++++++++++++++++++-------- config/nginx.sample.conf | 2 +- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 4d733fc2572..adcd78187dd 100644 --- a/Gemfile +++ b/Gemfile @@ -61,7 +61,7 @@ gem 'fast_xs' gem 'fast_xor' # while we sort out https://github.com/sdsykes/fastimage/pull/46 -gem 'discourse_fastimage', '2.0.2', require: 'fastimage' +gem 'discourse_fastimage', '2.0.3', require: 'fastimage' gem 'aws-sdk', require: false gem 'excon', require: false gem 'unf', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 3a4935e2984..f5eb9a748aa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,7 +73,7 @@ GEM diff-lcs (1.2.5) discourse-qunit-rails (0.0.9) railties - discourse_fastimage (2.0.2) + discourse_fastimage (2.0.3) docile (1.1.5) domain_name (0.5.25) unf (>= 0.0.5, < 1.0.0) @@ -410,7 +410,7 @@ DEPENDENCIES byebug certified discourse-qunit-rails - discourse_fastimage (= 2.0.2) + discourse_fastimage (= 2.0.3) email_reply_trimmer (= 0.1.3) ember-rails (= 0.18.5) ember-source (= 1.12.2) diff --git a/app/models/upload.rb b/app/models/upload.rb index 1b911097143..9295a3613a1 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -59,6 +59,32 @@ class Upload < ActiveRecord::Base # list of image types that will be cropped CROPPED_IMAGE_TYPES ||= %w{avatar profile_background card_background} + WHITELISTED_SVG_ELEMENTS ||= %w{ + circle + clippath + defs + ellipse + g + line + linearGradient + path + polygon + polyline + radialGradient + rect + stop + svg + text + textpath + tref + tspan + use + } + + def self.svg_whitelist_xpath + @@svg_whitelist_xpath ||= "//*[#{WHITELISTED_SVG_ELEMENTS.map { |e| "name()!='#{e}'" }.join(" and ") }]" + end + # options # - content_type # - origin (url) @@ -68,18 +94,21 @@ class Upload < ActiveRecord::Base DistributedMutex.synchronize("upload_#{user_id}_#{filename}") do # do some work on images if FileHelper.is_image?(filename) && is_actual_image?(file) - if filename =~ /\.svg$/i - svg = Nokogiri::XML(file).at_css("svg") - w = svg["width"].to_i - h = svg["height"].to_i + if filename[/\.svg$/i] + # whitelist svg elements + doc = Nokogiri::XML(file) + doc.xpath(svg_whitelist_xpath).remove + File.write(file.path, doc.to_s) + file.rewind else # fix orientation first fix_image_orientation(file.path) if should_optimize?(file.path) - # retrieve image info - image_info = FastImage.new(file) rescue nil - w, h = *(image_info.try(:size) || [0, 0]) end + # retrieve image info + image_info = FastImage.new(file) + w, h = *(image_info.try(:size) || [0, 0]) + # default size width, height = ImageSizer.resize(w, h) @@ -107,7 +136,7 @@ class Upload < ActiveRecord::Base end end - # optimize image (except GIFs and large PNGs) + # optimize image (except GIFs, SVGs and large PNGs) if should_optimize?(file.path) ImageOptim.new.optimize_image!(file.path) rescue nil # update the file size @@ -178,8 +207,8 @@ class Upload < ActiveRecord::Base LARGE_PNG_SIZE ||= 3.megabytes def self.should_optimize?(path) - # don't optimize GIFs - return false if path =~ /\.gif$/i + # don't optimize GIFs or SVGs + return false if path =~ /\.(gif|svg)$/i return true if path !~ /\.png$/i image_info = FastImage.new(path) rescue nil w, h = *(image_info.try(:size) || [0, 0]) diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf index 4f44e620154..4a3f659d203 100644 --- a/config/nginx.sample.conf +++ b/config/nginx.sample.conf @@ -157,7 +157,7 @@ server { try_files $uri =404; } # this allows us to bypass rails - location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff)$ { + location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|svg)$ { try_files $uri =404; } # thumbnails & optimized images