From cf74c88c5d431f694a36106615dd4ce34ccb19a6 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Thu, 15 Jun 2023 14:40:22 +0200 Subject: [PATCH] Correctly escape issue text in Gantt PNG export for ImageMagick convert According to https://imagemagick.org/Usage/draw/#text, we need to quote the passed text and only escape the quote character and backslash with backslashes respectively. Redmine::Utils::Shell.shell_quote escapes the single quote for a wrong environment (namely a shell) which results in errors if an issue subject contains a single quote character. --- lib/redmine/helpers/gantt.rb | 14 ++++++++++---- test/unit/lib/redmine/helpers/gantt_test.rb | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index 3614829db8..b33fc3223c 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -420,7 +420,7 @@ def to_image(format='PNG') gc.stroke('transparent') gc.strokewidth(1) gc.draw('text %d,%d %s' % [ - left.round + 8, 14, Redmine::Utils::Shell.shell_quote("#{month_f.year}-#{month_f.month}") + left.round + 8, 14, magick_text("#{month_f.year}-#{month_f.month}") ]) left = left + width month_f = month_f >> 1 @@ -456,7 +456,7 @@ def to_image(format='PNG') gc.stroke('transparent') gc.strokewidth(1) gc.draw('text %d,%d %s' % [ - left.round + 2, header_height + 14, Redmine::Utils::Shell.shell_quote(week_f.cweek.to_s) + left.round + 2, header_height + 14, magick_text(week_f.cweek.to_s) ]) left = left + width week_f = week_f + 7 @@ -822,7 +822,7 @@ def image_subject(params, subject, options={}) params[:image].stroke('transparent') params[:image].strokewidth(1) params[:image].draw('text %d,%d %s' % [ - params[:indent], params[:top] + 2, Redmine::Utils::Shell.shell_quote(subject) + params[:indent], params[:top] + 2, magick_text(subject) ]) end @@ -1072,10 +1072,16 @@ def image_task(params, coords, markers, label, object) params[:image].draw('text %d,%d %s' % [ params[:subject_width] + (coords[:bar_end] || 0) + 5, params[:top] + 1, - Redmine::Utils::Shell.shell_quote(label) + magick_text(label) ]) end end + + # Escape the passed string as a text argument in a draw rule for + # mini_magick. Note that the returned string is not shell-safe on its own. + def magick_text(str) + "'#{str.to_s.gsub(/['\\]/, '\\\\\0')}'" + end end end end diff --git a/test/unit/lib/redmine/helpers/gantt_test.rb b/test/unit/lib/redmine/helpers/gantt_test.rb index 0b97a7f207..b494ecb197 100644 --- a/test/unit/lib/redmine/helpers/gantt_test.rb +++ b/test/unit/lib/redmine/helpers/gantt_test.rb @@ -574,4 +574,9 @@ def test_sort_versions assert_equal versions.sort, Redmine::Helpers::Gantt.sort_versions!(versions.dup) end + + def test_magick_text + create_gantt + assert_equal "'foo\\'bar\\\\baz'", @gantt.send(:magick_text, "foo'bar\\baz") + end end -- 2.39.2