diff --git a/lib/chef-vault/exceptions.rb b/lib/chef-vault/exceptions.rb index 67ee744..baefa8a 100644 --- a/lib/chef-vault/exceptions.rb +++ b/lib/chef-vault/exceptions.rb @@ -51,5 +51,8 @@ class IdMismatch < Exceptions class V1Format < Exceptions end + + class InvalidValue < Exceptions + end end end diff --git a/lib/chef/knife/mixin/helper.rb b/lib/chef/knife/mixin/helper.rb index 2212935..c60daa4 100644 --- a/lib/chef/knife/mixin/helper.rb +++ b/lib/chef/knife/mixin/helper.rb @@ -39,10 +39,38 @@ def values_from_file(file) end def values_from_json(json) + validate_json(json) JSON.parse(json) rescue JSON::ParserError raise JSON::ParserError, "#{json} is not valid JSON!" end + + # I/P: json string + # Raises `InvalidValue` if any of the json's values contain non-printable characters. + def validate_json(json) + begin + evaled_json = eval(json) + rescue SyntaxError => e + raise ChefVault::Exceptions::InvalidValue, "#{json} is not valid JSON!" + end + + if evaled_json.is_a?(Hash) + evaled_json.each do |key, value| + next unless printable?(value.to_s) + + msg = "Value '#{value}' of key '#{key}' contains non-printable characters. Check that backslashes are escaped with another backslash (e.g. C:\\\\Windows) in double-quoted strings." + raise ChefVault::Exceptions::InvalidValue, msg + end + end + end + + # I/P: String + # O/P: true/false + # returns true if string is free of non-printable characters (escape sequences) + # this returns false for whitespace escape sequences as well, e.g. \n\t + def printable?(string) + /[^[:print:]]/.match(string) + end end end end diff --git a/spec/chef/helper_spec.rb b/spec/chef/helper_spec.rb new file mode 100644 index 0000000..694f7eb --- /dev/null +++ b/spec/chef/helper_spec.rb @@ -0,0 +1,24 @@ +require "spec_helper" +require "chef/knife/mixin/helper" + +RSpec.describe ChefVault::Mixin::Helper do + include ChefVault::Mixin::Helper + + let(:json_data) { '{"username": "root", "password": "abcabc"}' } + let(:json_data_control_char) { '{"username": "root", "password": "abc\abc"}' } + let(:buggy_json_data) { '{"username": "root", "password": "abc\abc"' } + + describe "#validate_json" do + it "Raises InvalidValue Exception when invalid data provided" do + expect { validate_json(buggy_json_data) }.to raise_error(ChefVault::Exceptions::InvalidValue) + end + + it "Raises InvalidValue Exception when value consist of control characters" do + expect { validate_json(json_data_control_char) }.to raise_error(ChefVault::Exceptions::InvalidValue) + end + + it "Not to raise error if valid data provided" do + expect { validate_json(json_data) }.to_not raise_error + end + end +end \ No newline at end of file