lib/pdfkit/pdfkit.rb in pdfkit-0.8.0 vs lib/pdfkit/pdfkit.rb in pdfkit-0.8.1

- old
+ new

@@ -1,6 +1,7 @@ require 'shellwords' +require 'rbconfig' class PDFKit class NoExecutableError < StandardError def initialize msg = "No wkhtmltopdf executable found at #{PDFKit.configuration.wkhtmltopdf}\n" @@ -31,20 +32,19 @@ raise NoExecutableError.new unless File.exists?(PDFKit.configuration.wkhtmltopdf) end def command(path = nil) args = @options.to_a.flatten.compact + shell_escaped_command = [executable, shell_escape_for_os(args)].join ' ' - if @source.html? - args << '-' # Get HTML from stdin - else - args << @source.to_s - end + # In order to allow for URL parameters (e.g. https://www.google.com/search?q=pdfkit) we do + # not escape the source. The user is responsible for ensuring that no vulnerabilities exist + # in the source. Please see https://github.com/pdfkit/pdfkit/issues/164. + input_for_command = @source.to_input_for_command + output_for_command = path ? Shellwords.shellescape(path) : '-' - args << (path || '-') # Write to file or stdout - - [executable, args.shelljoin].join ' ' + "#{shell_escaped_command} #{input_for_command} #{output_for_command}" end def executable default = PDFKit.configuration.wkhtmltopdf return default if default !~ /^\// # its not a path, so nothing we can do @@ -159,11 +159,11 @@ when Hash value.to_a.flatten.collect{|x| normalize_value(x)}.compact when Array value.flatten.collect{|x| x.to_s} else - value.to_s + (host_is_windows? && value.to_s.index(' ')) ? "'#{ value.to_s }'" : value.to_s end end def normalize_repeatable_value(option_name, value) case value @@ -193,7 +193,21 @@ def error_handling? @options.key?('--ignore-load-errors') || # wkhtmltopdf v0.10.0 beta4 replaces ignore-load-errors with load-error-handling # https://code.google.com/p/wkhtmltopdf/issues/detail?id=55 %w(skip ignore).include?(@options['--load-error-handling']) + end + + def host_is_windows? + @host_is_windows ||= !(RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince/).nil? + end + + def shell_escape_for_os(args) + if (host_is_windows?) + # Windows reserved shell characters are: & | ( ) < > ^ + # See http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection123121120120 + args.map { |arg| arg.gsub(/([&|()<>^])/,'^\1') }.join(" ") + else + args.shelljoin + end end end