diff --git a/lib/puppet/parser/functions/batch_escape.rb b/lib/puppet/parser/functions/batch_escape.rb new file mode 100644 index 000000000..53fc3491c --- /dev/null +++ b/lib/puppet/parser/functions/batch_escape.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# +# batch_escape.rb +# +module Puppet::Parser::Functions + newfunction(:batch_escape, type: :rvalue, doc: <<-DOC + @summary + Escapes a string so that it can be safely used in a batch shell command line. + + @return + A string of characters with special characters converted to their escaped form. + + >* Note:* that the resulting string should be used unquoted and is not intended for use in double quotes nor in single + quotes. + DOC + ) do |arguments| + raise(Puppet::ParseError, "batch_escape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + string = arguments[0].to_s + + result = '' + + string.chars.each do |char| + result += case char + when '"' then '""' + when '$', '\\' then "\\#{char}" + else char + end + end + + return %("#{result}") + end +end + +# vim: set ts=2 sw=2 et : diff --git a/lib/puppet/parser/functions/powershell_escape.rb b/lib/puppet/parser/functions/powershell_escape.rb new file mode 100644 index 000000000..44e5f0cc7 --- /dev/null +++ b/lib/puppet/parser/functions/powershell_escape.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# +# powershell_escape.rb +# +module Puppet::Parser::Functions + newfunction(:powershell_escape, type: :rvalue, doc: <<-DOC + @summary + Escapes a string so that it can be safely used in a PowerShell command line. + + @return + A string of characters with special characters converted to their escaped form. + + >* Note:* that the resulting string should be used unquoted and is not intended for use in double quotes nor in single + quotes. + DOC + ) do |arguments| + raise(Puppet::ParseError, "shell_escape(): Wrong number of arguments given (#{arguments.size} for 1)") if arguments.size != 1 + + string = arguments[0].to_s + + result = '' + + string.chars.each do |char| + result += case char + when ' ', "'", '`', '|', "\n", '$' then "`#{char}" + when '"' then '\`"' + else char + end + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/spec/functions/batch_escape_spec.rb b/spec/functions/batch_escape_spec.rb new file mode 100644 index 000000000..b10b7019f --- /dev/null +++ b/spec/functions/batch_escape_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'batch_escape' do + it { is_expected.not_to eq(nil) } + + describe 'signature validation' do + it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) } + it { is_expected.to run.with_params('foo', 'bar').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) } + end + + describe 'stringification' do + it { is_expected.to run.with_params(10).and_return('"10"') } + it { is_expected.to run.with_params(false).and_return('"false"') } + end + + describe 'escaping' do + it { is_expected.to run.with_params('foo').and_return('"foo"') } + it { is_expected.to run.with_params('foo bar').and_return('"foo bar"') } + it { + is_expected.to run.with_params('~`!@#$%^&*()_-=[]\{}|;\':",./<>?') + .and_return('"~`!@#\\$%^&*()_-=[]\\\{}|;\':"",./<>?"') + } + end +end diff --git a/spec/functions/powershell_escape_spec.rb b/spec/functions/powershell_escape_spec.rb new file mode 100644 index 000000000..c108362a6 --- /dev/null +++ b/spec/functions/powershell_escape_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'powershell_escape' do + it { is_expected.not_to eq(nil) } + + describe 'signature validation' do + it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) } + it { is_expected.to run.with_params('foo', 'bar').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) } + end + + describe 'stringification' do + it { is_expected.to run.with_params(10).and_return('10') } + it { is_expected.to run.with_params(false).and_return('false') } + end + + describe 'escaping' do + it { is_expected.to run.with_params('foo').and_return('foo') } + it { is_expected.to run.with_params('foo bar').and_return('foo` bar') } + it { + is_expected.to run.with_params('~`!@#$%^&*()_-=[]\{}|;\':",./<>?') + .and_return('~``!@#`$%^&*()_-=[]\{}`|;`\':\\`",./<>?') + } + end +end