metasploit-model 0.25.7 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. checksums.yaml +8 -8
  2. data/app/models/metasploit/model/search/operation/association.rb +57 -0
  3. data/app/models/metasploit/model/search/operator/association.rb +24 -14
  4. data/app/models/metasploit/model/search/operator/base.rb +19 -3
  5. data/app/models/metasploit/model/search/operator/single.rb +21 -1
  6. data/app/models/metasploit/model/search/query.rb +20 -1
  7. data/lib/metasploit/model/association/tree.rb +130 -0
  8. data/lib/metasploit/model/search.rb +61 -27
  9. data/lib/metasploit/model/search/association.rb +152 -8
  10. data/lib/metasploit/model/search/attribute.rb +112 -22
  11. data/lib/metasploit/model/search/operator.rb +53 -1
  12. data/lib/metasploit/model/search/operator/help.rb +39 -1
  13. data/lib/metasploit/model/search/with.rb +44 -1
  14. data/lib/metasploit/model/version.rb +2 -2
  15. data/spec/app/models/metasploit/model/search/operation/association_spec.rb +67 -0
  16. data/spec/app/models/metasploit/model/search/operator/association_spec.rb +76 -76
  17. data/spec/app/models/metasploit/model/search/operator/deprecated/author_spec.rb +54 -18
  18. data/spec/app/models/metasploit/model/search/operator/deprecated/authority_spec.rb +20 -8
  19. data/spec/app/models/metasploit/model/search/operator/deprecated/platform_spec.rb +20 -8
  20. data/spec/app/models/metasploit/model/search/operator/deprecated/ref_spec.rb +86 -26
  21. data/spec/app/models/metasploit/model/search/operator/deprecated/text_spec.rb +63 -21
  22. data/spec/lib/metasploit/model/search/association/tree_spec.rb +385 -0
  23. data/spec/lib/metasploit/model/search/association_spec.rb +99 -10
  24. data/spec/lib/metasploit/model/search_spec.rb +48 -107
  25. data/spec/support/shared/examples/search/query/metasploit/model/search/operator/deprecated/authority.rb +19 -7
  26. metadata +7 -1
@@ -1,29 +1,173 @@
1
1
  module Metasploit
2
2
  module Model
3
3
  module Search
4
- # Registers associations that can be searched.
4
+ # Use search operators registered on an associated class using
5
+ # {Metasploit::Model::Search::Attribute::ClassMethods#search_attribute},
6
+ # {Metasploit::Model::Search::With::ClassMethods#search_with}.
7
+ #
8
+ # Searchable associations are declared explicitly so that associations cycles can be avoided and the search
9
+ # interface can be tuned for clarity and complexity.
10
+ #
11
+ # # Testing
12
+ #
13
+ # {ClassMethods#search_association} calls can be tested with the 'search_association' shared example. First,
14
+ # ensure the shared examples from `metasploit-model` are required in your `spec_helper.rb`:
15
+ #
16
+ # # spec/spec_helper.rb
17
+ # support_glob = Metasploit::Model::Engine.root.join('spec', 'support', '**', '*.rb')
18
+ #
19
+ # Dir.glob(support_glob) do |path|
20
+ # require path
21
+ # end
22
+ #
23
+ # In the spec for the `Class` that called `search_association`, use the 'search_association' shared example:
24
+ #
25
+ # # spec/app/models/my_class_spec.rb
26
+ # require 'spec_helper'
27
+ #
28
+ # describe MyClass do
29
+ # context 'search' do
30
+ # context 'associations' do
31
+ # it_should_be_like 'search_association', :association_name
32
+ # end
33
+ # end
34
+ # end
35
+ #
36
+ # @example Search near and far associations
37
+ # class Root
38
+ # include Metasploit::Model::Association
39
+ # include Metasploit::Model::Search
40
+ #
41
+ # #
42
+ # # Associations
43
+ # #
44
+ #
45
+ # association :children,
46
+ # class_name: 'Child'
47
+ #
48
+ # #
49
+ # # Search
50
+ # #
51
+ #
52
+ # search_association children: :grandchildren
53
+ # end
54
+ #
55
+ # class Child
56
+ # include Metasploit::Model::Association
57
+ # include Metasploit::Model::Search
58
+ #
59
+ # #
60
+ # # Associations
61
+ # #
62
+ #
63
+ # association :grandchildren,
64
+ # class_name: 'Grandchild'
65
+ #
66
+ # #
67
+ # # Search
68
+ # #
69
+ #
70
+ # search_attribute :name,
71
+ # type: :string
72
+ # end
73
+ #
74
+ # class Grandchild
75
+ # include Metasploit::Model::Search
76
+ #
77
+ # search_attribute :age,
78
+ # type: :integer
79
+ # end
80
+ #
81
+ # Root.search_operator_by_name.each_value
82
+ # # :'children.name'
83
+ # # :'children.grandchildren.age'
84
+ #
85
+ # Child.search_operator_by_name.each_value
86
+ # # :name
87
+ # # @note ``:'grandchildren.age'`` is not in `Child`'s operators because it didn't declare
88
+ # # `search_association :grandchildren`, only `Root` did.
89
+ #
90
+ # Grandchild.search_operator_name
91
+ # # :age
92
+ #
5
93
  module Association
6
94
  extend ActiveSupport::Concern
7
95
 
8
96
  # Adds {#search_association} DSL to make {Metasploit::Model::Search::Operator::Association association search
9
97
  # operators}.
10
98
  module ClassMethods
99
+ # @note Use {#search_associations} to declare multiple associations or a tree of far associations as
100
+ # searchable.
101
+ #
11
102
  # Registers association for search.
12
103
  #
104
+ # @example a single searchable association
105
+ # search_association :children
106
+ #
13
107
  # @param association [#to_sym] name of association to search.
14
108
  # @return [void]
109
+ # @see #search_associations
15
110
  def search_association(association)
16
- search_association_set.add(association.to_sym)
111
+ search_association_tree[association.to_sym] ||= nil
17
112
  end
18
113
 
19
- # Set of all associations that are searchable.
114
+ # Registers a tree of near and far associations for search. When a tree is used, all intermediate association
115
+ # on the paths are used, so `search_association children: :grandchildren` makes both `children.granchildren`
116
+ # *and* `children` as search operator prefixes.
117
+ #
118
+ # @example a single search association
119
+ # search_associations :children
120
+ #
121
+ # @example multiple near associations
122
+ # search_associations :first,
123
+ # :second
124
+ #
125
+ # @example far association
126
+ # search_associations near: :far
127
+ #
128
+ # @example multiple far associations
129
+ # search_associations near: [
130
+ # :first_far,
131
+ # :second_far
132
+ # ]
133
+ #
134
+ # @example mix of near and far associations
135
+ # # Keep associations in order by near association names by mixing Symbols and Hash{Symbol => Object}
136
+ # search_associations :apple,
137
+ # {
138
+ # banana: :peel
139
+ # },
140
+ # :cucumber
141
+ #
20
142
  #
21
- # @example Adding association to search
22
- # search_association :things
143
+ # @param associations [Array<Array, Hash, Symbol>, Hash, Symbol]
144
+ # @return [void]
145
+ # @see search_association
146
+ def search_associations(*associations)
147
+ expanded_associations = Metasploit::Model::Association::Tree.expand(associations)
148
+
149
+ @search_association_tree = Metasploit::Model::Association::Tree.merge(
150
+ search_association_tree,
151
+ expanded_associations
152
+ )
153
+ end
154
+
155
+ # The association operators for the searchable associations declared with {#search_association} and
156
+ # {#search_associations}.
157
+ #
158
+ # @return (see Metasploit::Model::Association::Tree.operators)
159
+ def search_association_operators
160
+ @search_association_operators ||= Metasploit::Model::Association::Tree.operators(
161
+ search_association_tree,
162
+ class: self
163
+ )
164
+ end
165
+
166
+ # Tree of associations that are searchable.
23
167
  #
24
- # @return [Set<Symbol>]
25
- def search_association_set
26
- @search_association_set ||= Set.new
168
+ # @return [Hash{Symbol => Hash,nil}]
169
+ def search_association_tree
170
+ @search_association_tree ||= {}
27
171
  end
28
172
  end
29
173
  end
@@ -1,7 +1,117 @@
1
1
  module Metasploit
2
2
  module Model
3
3
  module Search
4
- # Registers attributes that can be searched.
4
+ # Registers attributes that can be searched. Attributes must be declared to be searchable as a type from
5
+ # {Metasploit::Model::Search::Operator::Attribute::TYPES}. The type of the attribute is used to select a
6
+ # type-specific {Metasploit::Model::Search::Operation}, which will validate the
7
+ # {Metasploit::Model::Search::Operation::Base#value} is of the valid type.
8
+ #
9
+ # # Set attributes
10
+ #
11
+ # Search attributes declared as having an integer set or string set type integer or string set require a
12
+ # `<attribute>_set` method to be defined on the `Class`, which returns the set of allowed values for the search
13
+ # attribute's operation. This method will be called, indirectly by
14
+ # {Metasploit::Model::Search::Operation::Set::Integer}'s and {Metasploit::Model::Search::Operation::Set::String}'s
15
+ # validations.
16
+ #
17
+ # # Help
18
+ #
19
+ # The help for each operator is uses the `I18n` system, so the help for an attribute operator on a given class can
20
+ # added to `config/locales/<lang>.yml`. The scope of the lookup, under the language key is the `Class`'s
21
+ # `i18n_scope`, which is `metasploit.model` if the `Class` includes {Metasploit::Model::Translation} or
22
+ # `active_record` for `ActiveRecord::Base` subclasses. Under the `i18n_scope`, any `Module#ancestor`'s
23
+ # `model_name.i18n_key` can be used to look up the help for an attribute's operator. This allows for super
24
+ # classes or mixins to define the search operator help for subclasses.
25
+ #
26
+ # # config/locales/<lang>.yml
27
+ # <lang>:
28
+ # <Class#i18n_scope>:
29
+ # ancestors:
30
+ # <ancestor.model_name.i18n_key>:
31
+ # search:
32
+ # operator:
33
+ # names:
34
+ # <attribute>:
35
+ # help: "The attribute on the class"
36
+ #
37
+ # # Testing
38
+ #
39
+ # {ClassMethods#search_attribute} calls can be tested with the 'search_attribute' shared example. First, ensure
40
+ # the shared examples from `metasploit-model` are required in your `spec_helper.rb`:
41
+ #
42
+ # # spec/spec_helper.rb
43
+ # support_glob = Metasploit::Model::Engine.root.join('spec', 'support', '**', '*.rb')
44
+ #
45
+ # Dir.glob(support_glob) do |path|
46
+ # require path
47
+ # end
48
+ #
49
+ # In the spec for the `Class` that called `search_attribute`, use the 'search_attribute' shared example by
50
+ # passing that arguments passed to {ClassMethods#search_attribute}.
51
+ #
52
+ # # spec/app/models/my_class_spec.rb
53
+ # require 'spec_helper'
54
+ #
55
+ # describe MyClass do
56
+ # context 'search' do
57
+ # context 'attributes' do
58
+ # it_should_behave_like 'search_attribute',
59
+ # type: {
60
+ # set: :string
61
+ # }
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ # @example search an attribute for `true` or `false`
67
+ # search_attribute :flag,
68
+ # type: :boolean
69
+ #
70
+ # @example search an attribute for an integer
71
+ # search_attribute :age,
72
+ # type: :integer
73
+ #
74
+ # @example search an attribute for a restricted set of integers
75
+ # #
76
+ # # Search
77
+ # #
78
+ #
79
+ # search_attribute :bits,
80
+ # set: :integer
81
+ #
82
+ # #
83
+ # # Class Methods
84
+ # #
85
+ #
86
+ # # Return set of allowed values for {#bits} search.
87
+ # #
88
+ # # @return [Set<Integer>]
89
+ # def self.bits_set
90
+ # @bits_set ||= Set.new([32, 64])
91
+ # end
92
+ #
93
+ # @example search an attribute for a restricted set of strings
94
+ # #
95
+ # # Search
96
+ # #
97
+ #
98
+ # search_attribute :endianness,
99
+ # set: :string
100
+ #
101
+ # #
102
+ # # Class Methods
103
+ # #
104
+ #
105
+ # # Return set of allowed values for {#endianness} search.
106
+ # #
107
+ # # @return [Set<String>]
108
+ # def self.endianness_set
109
+ # @endianness_set ||= Set.new(['big', 'litte'])
110
+ # end
111
+ #
112
+ # @example search an attribute by substring (case-insensitve LIKE)
113
+ # search_attribute :description,
114
+ # type: :string
5
115
  module Attribute
6
116
  extend ActiveSupport::Concern
7
117
 
@@ -10,27 +120,7 @@ module Metasploit
10
120
  # Adds {#search_attribute} DSL to make {Metasploit::Model::Search::Operator::Attribute attribute search
11
121
  # operators}.
12
122
  module ClassMethods
13
- # Registers attribute for search. Help for the operator supports i18n.
14
- #
15
- # @example defining help
16
- # # lib/metasploit/model/module/instance.rb
17
- # module Metasploit::Model::Module::Instance
18
- # include Metasploit::Model::Search
19
- #
20
- # included do
21
- # search_attribute :description, :type => :string
22
- # end
23
- # end
24
- #
25
- # # config/locales/en.yml
26
- # en:
27
- # metasploit:
28
- # model:
29
- # module:
30
- # instance:
31
- # search_attribute:
32
- # description:
33
- # help: "A long, paragraph description of what the module does."
123
+ # {include:Metasploit::Model::Search::Attribute}
34
124
  #
35
125
  # @param attribute [#to_sym] name of attribute to search.
36
126
  # @param options [Hash{Symbol => String}]
@@ -1,7 +1,59 @@
1
1
  module Metasploit
2
2
  module Model
3
3
  module Search
4
- # Namespace for search operators
4
+ # # Declaring operator classes
5
+ #
6
+ # ## Interface
7
+ #
8
+ # Operators do not need to subclass any specific superclass, but they are expected to define certain methods.
9
+ #
10
+ # class MyOperator
11
+ # #
12
+ # # Instance Methods
13
+ # #
14
+ #
15
+ # # @param klass [Class] The klass on which `search_with` was called.
16
+ # def initialize(attributes={})
17
+ # # ...
18
+ # end
19
+ #
20
+ # # Description of what this operator searches for.
21
+ # #
22
+ # # @return [String]
23
+ # def help
24
+ # # ...
25
+ # end
26
+ #
27
+ # # Name of this operator. The name of the operator is matched to the string before the ':' in a formatted
28
+ # # operation.
29
+ # #
30
+ # # @return [Symbol]
31
+ # def name
32
+ # # ...
33
+ # end
34
+ #
35
+ # # Creates a one or more operations based on `formatted_value`.
36
+ # #
37
+ # # @return [#operator, Array<#operator>] Operation with this operator as the operation's `operator`.
38
+ # def operate_on(formatted_value)
39
+ # # ...
40
+ # end
41
+ # end
42
+ #
43
+ # ## Help
44
+ #
45
+ # Instead of having define your own `#help` method for your operator `Class`, you can `include`
46
+ # {Metasploit::Model::Search::Operator::Help}.
47
+ #
48
+ # {include:Metasploit::Model::Search::Operator::Help}
49
+ #
50
+ # ## {Metasploit::Model::Search::Operator::Base}
51
+ #
52
+ # {include:Metasploit::Model::Search::Operator::Base}
53
+ #
54
+ # ## {Metasploit::Model::Search::Operator::Single}
55
+ #
56
+ # {include:Metasploit::Model::Search::Operator::Single}
5
57
  module Operator
6
58
 
7
59
  end
@@ -2,7 +2,45 @@ module Metasploit
2
2
  module Model
3
3
  module Search
4
4
  module Operator
5
- # Methods to lookup help text for an operator with a given `#name` registered to a given `#klass`.
5
+ # This allows the help to be looked up using `I18n`, and for the
6
+ # help to be customized based on the following criteria:
7
+ #
8
+ # `klass` on which the operator is declared, including any `Module#ancestors` and the operator `name`
9
+ #
10
+ # # config/locales/<lang>.yml
11
+ # <lang>:
12
+ # <klass.i18n_scope>:
13
+ # ancestors:
14
+ # <klass_ancestor.model_name.i18n_key>:
15
+ # search:
16
+ # operator:
17
+ # names:
18
+ # <name>:
19
+ # help: "Help for searching <name> on <klass>"
20
+ #
21
+ # `class` of the operator, including any `Module#ancestors` and the operator `name`
22
+ #
23
+ # # config/locales/<lang>.yml
24
+ # <lang>:
25
+ # <operator.class.i18n_scope>:
26
+ # search:
27
+ # operator:
28
+ # ancestors:
29
+ # <operator_class_ancestor.model_name.i18n_key>:
30
+ # <name>:
31
+ # help: "Help for searching <name> using <operator.class>"
32
+ #
33
+ # `class` of the operator, including any `Module#ancestors` without the operator `name`
34
+ #
35
+ # # config/locales/<lang>.yml
36
+ # <lang>:
37
+ # <operator.class.i18n_scope>:
38
+ # search:
39
+ # operator:
40
+ # ancestors:
41
+ # <operator_class_ancestor.model_name.i18n_key>:
42
+ # help: "Help for searching using <operator.class>"
43
+ #
6
44
  module Help
7
45
  # @note This uses I18n.translate along with {Metasploit::Model::Translation#search_i18n_scope},
8
46
  # the value is not cached to support changing the I18n.locale and getting the correct help message for that
@@ -1,7 +1,50 @@
1
1
  module Metasploit
2
2
  module Model
3
3
  module Search
4
- # Generalizes operators from attributes to anything directly registered as an operator on a class.
4
+ # Generalizes {Metasploit::Model::Search::Attribute operators from attributes} to anything directly registered as
5
+ # an operator on a class.
6
+ #
7
+ # {include:Metasploit::Model::Search::Operator}
8
+ #
9
+ # # Testing
10
+ #
11
+ # {ClassMethods#search_with} calls can be tested with the 'search_with' shared example. First, ensure
12
+ # the shared examples from `metasploit-model` are required in your `spec_helper.rb`:
13
+ #
14
+ # # spec/spec_helper.rb
15
+ # support_glob = Metasploit::Model::Engine.root.join('spec', 'support', '**', '*.rb')
16
+ #
17
+ # Dir.glob(support_glob) do |path|
18
+ # require path
19
+ # end
20
+ #
21
+ # In the spec fo the `Class` that called `search_with`, use the 'search_with' shared example by passing the
22
+ # arguments passed to {ClassMethods#search_attribute}.
23
+ #
24
+ # # app/models/my_class.rb
25
+ # class MyClass
26
+ # include Metasploit::Model::Search
27
+ #
28
+ # #
29
+ # # Search
30
+ # #
31
+ #
32
+ # search_with MyOperatorClass,
33
+ # foo: :bar
34
+ # end
35
+ #
36
+ # # spec/app/models/my_class_spec.rb
37
+ # require 'spec_helper'
38
+ #
39
+ # describe MyClass do
40
+ # context 'search' do
41
+ # context 'attributes' do
42
+ # it_should_behave_like 'search_with',
43
+ # MyOperatorClass,
44
+ # foo: :bar
45
+ # end
46
+ # end
47
+ # end
5
48
  module With
6
49
  extend ActiveSupport::Concern
7
50