diff --git a/VERSION b/VERSION index e5fe74de9..43dc7e517 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.102 +3.7.103 diff --git a/lib/gooddata/helpers/global_helpers_params.rb b/lib/gooddata/helpers/global_helpers_params.rb index 6b977e351..62f52dace 100644 --- a/lib/gooddata/helpers/global_helpers_params.rb +++ b/lib/gooddata/helpers/global_helpers_params.rb @@ -71,15 +71,17 @@ def decode_params(params, options = {}) end reference_values = [] + sanitize_values = {} # Replace reference parameters by the actual values. Use backslash to escape a reference parameter, e.g: \${not_a_param}, # the ${not_a_param} will not be replaced if options[:resolve_reference_params] - data_params, reference_values = resolve_reference_params(data_params, params) + data_params, reference_values, sanitize_values = resolve_reference_params(data_params, params) hidden_data_params, = resolve_reference_params(hidden_data_params, params) end begin parsed_data_params = data_params.is_a?(Hash) ? data_params : JSON.parse(data_params) + revert_sanitize_value(parsed_data_params, sanitize_values) if sanitize_values.any? rescue JSON::ParserError => exception reason = exception.message reference_values.each { |secret_value| reason.gsub!("\"#{secret_value}\"", '"***"') } @@ -240,8 +242,23 @@ def stringify_values(value) private + def invalid_ascii_value(data) + data.include?("\n") + end + + def revert_sanitize_value(parsed_data_params, sanitize_values) + parsed_data_params.map do |k, v| + if v.is_a?(Hash) + revert_sanitize_value(v, sanitize_values) + else + parsed_data_params[k] = sanitize_values[v] if sanitize_values.include?(v) + end + end + end + def resolve_reference_params(data_params, params) reference_values = [] + sanitize_values = {} regexps = Regexp.union(/\\\\/, /\\\$/, /\$\{([^\n\{\}]+)\}/) resolve_reference = lambda do |v| if v.is_a? Hash @@ -266,7 +283,13 @@ def resolve_reference_params(data_params, params) val = params["#{$1}"] if val reference_values << val - val + if invalid_ascii_value(val) + escape_value = val.gsub("\n", "\\n") + sanitize_values[escape_value] = val + escape_value + else + val + end else GoodData.logger.warn "Reference '#{$1}' is not found!" match @@ -284,7 +307,7 @@ def resolve_reference_params(data_params, params) resolve_reference.call(data_params) end - [data_params, reference_values] + [data_params, reference_values, sanitize_values] end end end diff --git a/spec/unit/helpers/global_helpers_spec.rb b/spec/unit/helpers/global_helpers_spec.rb index 1118a487c..b44b59712 100644 --- a/spec/unit/helpers/global_helpers_spec.rb +++ b/spec/unit/helpers/global_helpers_spec.rb @@ -162,22 +162,41 @@ 'x' => 'y', 'ads_password' => 'ads_123', 'my_password' => 'login_123', + 'private_key' => '-----TEST----- +abc +123 +-----END TEST-----', 'alias.user' => 'qa+test@gooddata.com', 'alias.segment' => 'UserTestSegmentK8s', 'gd_encoded_params' => '{"login_username": "${alias.user}", "login_password": "abc_${my_password}_123" , "SEGMENTS_FILTER": ["${alias.segment}"], + "connection": { + "username": "${alias.user}", + "db_private_key": "${private_key}" + }, "technical_user": ["${alias.user}"]}' } expected_result = { 'x' => 'y', 'ads_password' => 'ads_123', 'my_password' => 'login_123', + 'private_key' => '-----TEST----- +abc +123 +-----END TEST-----', 'alias.user' => 'qa+test@gooddata.com', 'alias.segment' => 'UserTestSegmentK8s', 'login_username' => 'qa+test@gooddata.com', 'login_password' => 'abc_login_123_123', 'SEGMENTS_FILTER' => ["UserTestSegmentK8s"], + 'connection' => { + 'username' => 'qa+test@gooddata.com', + 'db_private_key' => '-----TEST----- +abc +123 +-----END TEST-----' + }, 'technical_user' => ["qa+test@gooddata.com"] } result = GoodData::Helpers.decode_params(params, :resolve_reference_params => true) @@ -211,108 +230,5 @@ expect(result).to eq(expected_result) end - it 'should encode escape reference parameters in gd_encoded_params' do - params = { - 'x' => 'y', - 'ads_password' => 'ads_123', - 'my_password' => 'login_123', - 'gd_encoded_params' => '{"login_username": "login_user", "data01": "\\${abc}"}' - } - expected_result = { - 'x' => 'y', - 'ads_password' => 'ads_123', - 'my_password' => 'login_123', - 'login_username' => 'login_user', - 'data01' => '${abc}' - } - result = GoodData::Helpers.decode_params(params, :resolve_reference_params => true) - expect(result).to eq(expected_result) - end - - it 'should encode reference parameters in nested block in gd_encoded_params' do - params = { - 'x' => 'y', - 'ads_password' => 'ads_123', - 'my_password' => 'login_123', - 'gd_encoded_params' => '{"login_username": "login_user", "ads_client": {"username": "ads_user", "password": "${ads_password}"}}' - } - expected_result = { - 'x' => 'y', - 'ads_password' => 'ads_123', - 'my_password' => 'login_123', - 'login_username' => 'login_user', - 'ads_client' => { - 'username' => 'ads_user', - 'password' => 'ads_123' - } - } - result = GoodData::Helpers.decode_params(params, :resolve_reference_params => true) - expect(result).to eq(expected_result) - end - - it 'should convert all values into String' do - params = { - x: true, - y: ['hello', false], - z: { - z1: false, - z2: [true], - z3: [[[false]]] - } - } - expected_result = { - x: 'true', - y: %w(hello false), - z: { - z1: 'false', - z2: ['true'], - z3: [[['false']]] - } - } - result = GoodData::Helpers.stringify_values(params) - expect(result).to eq(expected_result) - end - end - - describe '.interpolate_error_message' do - let(:error_message) { { 'error' => { 'message' => 'foo %s', 'parameters' => ['bar'] } } } - - before do - @message = GoodData::Helpers.interpolate_error_message(error_message) - end - - it 'interpolates parameters' do - expect(@message).to eq('foo bar') - end - - context 'when error parameter is empty' do - let(:error_message) { {} } - it 'returns nil' do - expect(@message).to be_nil - end - end - - context 'when error key is empty' do - let(:error_message) { { 'error' => {} } } - it 'returns nil' do - expect(@message).to be_nil - end - end - end - - describe '.decode_params' do - it 'interpolates reference parameters in additional_hidden_params' do - params = { - 'gd_encoded_hidden_params' => '{ "additional_hidden_params": { "secret": "${my_password}" } }', - 'my_password' => "123" - } - expected_result = { - 'gd_encoded_hidden_params' => nil, - 'additional_hidden_params' => { 'secret' => '123' }, - 'my_password' => '123' - } - result = GoodData::Helpers.decode_params(params, :resolve_reference_params => true) - expect(result).to eq(expected_result) - end end end