diff --git a/app/models/metasploit_data_models/search/visitor/where.rb b/app/models/metasploit_data_models/search/visitor/where.rb index 86ae265e..1825a028 100644 --- a/app/models/metasploit_data_models/search/visitor/where.rb +++ b/app/models/metasploit_data_models/search/visitor/where.rb @@ -49,6 +49,25 @@ class MetasploitDataModels::Search::Visitor::Where attribute.matches(match_value) end + visit 'Metasploit::Model::Search::Operation::Jsonb' do |operation| + attribute = attribute_visitor.visit operation.operator + + begin + operation_hash = JSON.parse(operation.value) + left = Arel::Nodes::InfixOperation.new( + '->>', + Arel::Nodes.build_quoted(attribute), + Arel::Nodes.build_quoted(operation_hash.keys[0]) + ) + right ="%#{operation_hash.values[0]}%" + rescue JSON::ParserError + left = Arel::Nodes::NamedFunction.new("cast", [attribute.as('text')]) + right ="%#{operation.value}%" + end + + left.matches(right) + end + visit 'MetasploitDataModels::IPAddress::CIDR' do |cidr| cast_to_inet "#{cidr.address}/#{cidr.prefix_length}" end diff --git a/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb b/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb index 39fcf0bc..e86416b5 100644 --- a/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb +++ b/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb @@ -183,5 +183,49 @@ end end end + + context 'with MetasploitDataModels::Search::Operation::Jsonb' do + let(:klass) do + klass = Class.new(ApplicationRecord) + Object.const_set('Jsonb', klass) + klass + end + + let(:node) do + Metasploit::Model::Search::Operation::Jsonb.new( + :operator => operator, + :value => value + ) + end + + let(:operator) do + Metasploit::Model::Search::Operator::Attribute.new( + :klass => klass, + :attribute => :metadata + ) + end + + let(:value) do + 'adcs_ca:myCA' + end + + it 'should visit operation.operator with attribute_visitor' do + expect(visitor.attribute_visitor).to receive(:visit).with(operator).and_call_original + + visit + end + + it 'should return the expected Arel::Nodes::Matches' do + attribute = Arel::Attributes::Attribute.new( + Arel::Table.new(:metasploit_credential_privates), + 'metadata' + ) + allow(visitor.attribute_visitor).to receive(:visit).with(operator).and_return(attribute) + + results = visit + expect(results).to be_a(Arel::Nodes::Matches) + expect(results.to_sql).to eq("\"metasploit_credential_privates\".\"metadata\" ->> 'adcs_ca' ILIKE '%myCA%'") + end + end end end