opentpx 2.2.0.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ require 'tpx/2_2/exceptions'
2
+
3
+ module TPX_2_2
4
+ # A list (Array) whose elements are not all the same type or do not have the same id attribute.
5
+ # The HeterogenousList defines an array of [ChildClass, child_id_attribute_name] as the accepted :child_types.
6
+ class HeterogeneousList < Array
7
+ include Enumerable
8
+
9
+ class << self
10
+ # The types of objects and their id attribute names accepted by the HeterogeneousList.
11
+ # An Array of Arrays like [[ChildClass, child_id_attribute], [AnotherChildClass, another_child_id_attribute]].
12
+ attr_accessor :child_types
13
+
14
+ # Defines the child class types that the list accepts. Another accessor for `child_types`.
15
+ #
16
+ # @param [Array] child_class_id_array The list of [Class, id_atttribute_name] to accept as list members.
17
+ def children_of_class_and_id(child_class_id_array)
18
+ self.child_types = child_class_id_array
19
+ end
20
+ end
21
+
22
+ # Hash lookup accessor to list members.
23
+ # Hash of hashes like child_id_of[ChildClass][child_id_val] = child
24
+ attr_accessor :child_id_of
25
+
26
+ # Initialize a new HeterogeneousList from an Array.
27
+ #
28
+ # @param [Array] input_array The Array of HeterogeneousList.child_types included classes (or Hash to be initialized as HeterogeneousList.child_type classes) to create the HeterogeneousList object from.
29
+ def initialize(input_array)
30
+ unless input_array.is_a? Array
31
+ raise ValidationError, "Supplied parameter (#{input_array.inspect}) to #{self.class}#initialize should be of type Array!"
32
+ end
33
+
34
+ @child_id_of = {}
35
+ validated_array = []
36
+
37
+ input_array.each_with_index do |child, i|
38
+ validate_expected_child_type(child, i)
39
+ new_initialized_child = nil
40
+ new_initialized_child_type = nil
41
+
42
+ self.class.child_types.each do |child_type|
43
+ if child.class == child_type[0] && child.has_key?(child_type[1])
44
+ new_initialized_child = child
45
+ new_initialized_child_type = child_type
46
+ break
47
+ elsif child.has_key?(child_type[1])
48
+ new_initialized_child = child_type[0].new(child)
49
+ new_initialized_child_type = child_type
50
+ break
51
+ end
52
+ end
53
+
54
+ if new_initialized_child
55
+ validate_unique(new_initialized_child, new_initialized_child_type)
56
+ child_id_of[new_initialized_child_type[0]] ||= {}
57
+ child_id_of[new_initialized_child_type[0]][new_initialized_child[new_initialized_child_type[1]]] = new_initialized_child
58
+ validated_array << new_initialized_child
59
+ end
60
+ end
61
+
62
+ super validated_array
63
+ end
64
+
65
+ # Add a new child to the HeterogeneousList (push).
66
+ #
67
+ # @param [Hash or HeterogeneousList.type] child The object to add to the HeterogeneousList.
68
+ def <<(child)
69
+ child_type = validate_expected_child_type(child)
70
+ validate_unique(child, child_type)
71
+ child_id_of[child_type[0]] ||= {}
72
+ child_id_of[child_type[0]][child[child_type[1]]] = child
73
+ super child
74
+ end
75
+
76
+ # Validate that a child is of the proper type to add to the HeterogeneousList.
77
+ #
78
+ # @param [Hash or one of HeterogeneousList.child_types] child The object to verify is one of HeterogeneousList.child_types.
79
+ # @param [Integer] i The position, if any, in the list of the object to verify is one of HeterogeneousList.child_types.
80
+ def validate_expected_child_type(child, i=nil)
81
+ if child.class == Hash || child.class == HashWithIndifferentAccess
82
+ validate_expected_child_type_from_hash(child, i)
83
+ else
84
+ validate_expected_child_type_from_initialized_object(child, i)
85
+ end
86
+ end
87
+
88
+ # Validate that a child is of the proper type to add to the HeterogeneousList.
89
+ #
90
+ # @param [Hash] child The object to verify is one of HeterogeneousList.child_types.
91
+ # @param [Integer] i The position, if any, in the list of the object to verify is one of HeterogeneousList.child_types.
92
+ def validate_expected_child_type_from_hash(child, i=nil)
93
+ child_type_key_count = 0
94
+ child_type_found = nil
95
+ self.class.child_types.each do |child_type|
96
+ if child.has_key?(child_type[1])
97
+ child_type_key_count += 1
98
+ child_type_found = child_type
99
+ end
100
+ end
101
+ if child_type_key_count > 1
102
+ raise ValidationError, "Supplied input object #{child.inspect}#{pos_msg} has multiple subject types in #{self.class}!"
103
+ elsif child_type_key_count == 0
104
+ raise ValidationError, "Supplied input object #{child.inspect}#{pos_msg(i)} not one of required types #{self.class.child_types} in #{self.class}!"
105
+ end
106
+ return child_type_found
107
+ end
108
+
109
+ # Validate that a child is of the proper type to add to the HeterogeneousList.
110
+ #
111
+ # @param [one of HeterogeneousList.child_types] child The object to verify is one of HeterogeneousList.child_types.
112
+ # @param [Integer] i The position, if any, in the list of the object to verify is one of HeterogeneousList.child_types.
113
+ def validate_expected_child_type_from_initialized_object(child, i=nil)
114
+ self.class.child_types.each do |child_type|
115
+ if child.class == child_type[0] && child.has_key?(child_type[1])
116
+ return child_type
117
+ end
118
+ end
119
+ raise ValidationError, "Supplied input object #{child.inspect}#{pos_msg(i)} not one of required types #{self.class.child_types} in #{self.class}!"
120
+ end
121
+
122
+ def pos_msg(i)
123
+ pos_msg = i.nil? ? '' : " at position #{i}"
124
+ end
125
+
126
+ # Validate that a child is not contained in the list prior to adding to the HeterogeneousList.
127
+ #
128
+ # @param [Hash or HeterogeneousList.type] child The object to verify is not already contained in HeterogeneousList.
129
+ def validate_unique(child, child_type)
130
+ if child_id_of.has_key?(child_type[0]) and child_id_of[child_type[0]].has_key?(child[child_type[1]])
131
+ raise TPX_2_2::DuplicateElementInsertError, "Duplicate input object id #{child[child_type[1]]} provided to #{self.class}!"
132
+ end
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,82 @@
1
+ require 'tpx/2_2/exceptions'
2
+
3
+ module TPX_2_2
4
+ # A list (Array) whose elements are all the same type and have the same id attribute (HomogeneousList.child_id).
5
+ class HomogeneousList < Array
6
+ include Enumerable
7
+
8
+ class << self
9
+ # The child class type accepted.
10
+ attr_accessor :type
11
+ # The id attribute name of the children objects.
12
+ attr_accessor :child_id
13
+
14
+ # Defines the child class that the list accepts.
15
+ #
16
+ # @param [Class] klass The Class to accept as list members.
17
+ def homogeneous_list_of(klass)
18
+ self.type = klass
19
+ end
20
+
21
+ # Defines the child class id attribute name.
22
+ #
23
+ # @param [Symbol] child_id The id field of list members.
24
+ def children_keyed_by(child_id)
25
+ self.child_id = child_id
26
+ end
27
+ end
28
+
29
+ # Hash lookup accessor to list members.
30
+ # Hash of hashes like child_id_of[ChildClass][child_id_val] = child
31
+ attr_accessor :child_id_of
32
+
33
+ # Initialize a new HomogeneousList from an Array.
34
+ #
35
+ # @param [Array] input_array The Array of HomogeneousList.type classes (or Hash to be initialized as HomogeneousList.type classes) to create the HomogeneousList object from.
36
+ def initialize(input_array)
37
+ unless input_array.is_a? Array
38
+ raise ValidationError, "Supplied parameter (#{input_array.inspect}) to #{self.class}#initialize should be of type Array!"
39
+ end
40
+ @child_id_of = {}
41
+ input_array.each_with_index do |child, i|
42
+ if child.class == Hash || child.class == HashWithIndifferentAccess
43
+ child = self.class.type.new(child)
44
+ end
45
+ validate_homogeneous_type_of(child, i)
46
+ validate_unique(child)
47
+ @child_id_of[child[self.class.child_id]] = child
48
+ end
49
+ super input_array
50
+ end
51
+
52
+ # Add a new child to the HomogeneousList (push).
53
+ #
54
+ # @param [Hash or HomogeneousList.type] child The object to add to the HomogeneousList.
55
+ def <<(child)
56
+ validate_homogeneous_type_of(child)
57
+ validate_unique(child)
58
+ @child_id_of[child[self.class.child_id]] = child
59
+ super child
60
+ end
61
+
62
+ # Validate that a child is of the proper type to add to the HomogeneousList.
63
+ #
64
+ # @param [Hash or HomogeneousList.type] child The object to verify is one of HomogeneousList.type.
65
+ # @param [Integer] i The position, if any, in the list of the object to verify is one of HomogeneousList.type.
66
+ def validate_homogeneous_type_of(child, i=nil)
67
+ unless child.is_a? self.class.type
68
+ pos_msg = i.nil? ? '' : " at position #{i}"
69
+ raise ValidationError, "Supplied input object #{child.inspect}#{pos_msg} not of required type #{self.class.type} in #{self.class}!"
70
+ end
71
+ end
72
+
73
+ # Validate that a child is not contained in the list prior to adding to the HomogeneousList.
74
+ #
75
+ # @param [Hash or HomogeneousList.type] child The object to verify is not already contained in HomogeneousList.
76
+ def validate_unique(child)
77
+ if @child_id_of.has_key?(child[self.class.child_id])
78
+ raise TPX_2_2::DuplicateElementInsertError, "Duplicate input object id #{child[self.class.child_id]} provided to #{self.class}!"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,69 @@
1
+ module TPX_2_2
2
+ module MandatoryAttributes
3
+ MANDATORY_ATTRIBUTES = [] # override in consumer
4
+ MUST_HAVE_ONE_OF_ATTRIBUTES = []
5
+ MUST_HAVE_ONE_AND_ONLY_ONE_OF_ATTRIBUTES = []
6
+
7
+ # Perform all validations.
8
+ def validate!
9
+ validate_mandatory_attributes!
10
+
11
+ validate_must_have_one_of_attributes!
12
+
13
+ validate_must_have_one_and_only_one_of_attributes!
14
+ end # def validate!
15
+
16
+ # Perform validation of all mandatory attributes.
17
+ def validate_mandatory_attributes!
18
+ self.class::MANDATORY_ATTRIBUTES.each do |attrib|
19
+ if self[attrib].nil?
20
+ raise ValidationError, "The mandatory attribute `#{attrib}` is missing from the supplied input_hash paramater to #{self.class}."
21
+ end
22
+ end
23
+ end
24
+
25
+ # Perform validation of all sets of attributes of which at least one are required.
26
+ def validate_must_have_one_of_attributes!
27
+ self.class::MUST_HAVE_ONE_OF_ATTRIBUTES.each do |attrib_set|
28
+ unless attrib_set.is_a? Array
29
+ raise AttributeDefinitionError, "Elements of #{self.class}::MUST_HAVE_ONE_OF_ATTRIBUTES must be of type Array."
30
+ end
31
+
32
+ has_one_of_mandatory_set = false
33
+ attrib_set.each do |attrib|
34
+ if self.has_key?(attrib) && !self[attrib].nil?
35
+ has_one_of_mandatory_set = true
36
+ break
37
+ end
38
+ end
39
+
40
+ unless has_one_of_mandatory_set
41
+ raise ValidationError, "A member of the mandatory attribute set `#{attrib_set}` is missing from the supplied input_hash paramater to #{self.class}."
42
+ end
43
+ end
44
+ end
45
+
46
+ # Perform validation of all sets of attributes of which only one is required.
47
+ def validate_must_have_one_and_only_one_of_attributes!
48
+ self.class::MUST_HAVE_ONE_AND_ONLY_ONE_OF_ATTRIBUTES.each do |attrib_set|
49
+ unless attrib_set.is_a? Array
50
+ raise AttributeDefinitionError, "Elements of #{self.class}::MUST_HAVE_ONE_AND_ONLY_ONE_OF_ATTRIBUTES must be of type Array."
51
+ end
52
+
53
+ count_of_mandatory_set = 0
54
+ attrib_set.each do |attrib|
55
+ if self.has_key?(attrib)
56
+ count_of_mandatory_set += 1
57
+ end
58
+ end
59
+
60
+ if count_of_mandatory_set == 0
61
+ raise ValidationError, "A member of the mandatory attribute set `#{attrib_set}` is missing from the supplied input_hash paramater to #{self.class}."
62
+ elsif count_of_mandatory_set > 1
63
+ raise ValidationError, "More than one member of the exclusive and mandatory attribute set `#{attrib_set}` was provided to #{self.class}."
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ require 'tpx/2_2/heterogeneous_list'
2
+
3
+ module TPX_2_2
4
+ # A list (Array) whose elements are not all the same type or do not have the same id attribute
5
+ # and who merges certain attributes on duplicate object insert.
6
+ # The MergingHeterogenousList defines an array of [ChildClass, child_id_attribute_name] as the accepted :child_types.
7
+ class MergingHeterogeneousList < HeterogeneousList
8
+
9
+ class << self
10
+ # This list of attributes to merge on duplicate object id insert.
11
+ attr_accessor :attributes_to_merge
12
+
13
+ def on_duplicate_addition_merge_attributes(attributes)
14
+ self.attributes_to_merge = attributes
15
+ end
16
+ end
17
+
18
+ # Add a new child to the MergingHeterogenousList (push). Merge `attributes_to_merge` on a duplicate child id insert.
19
+ #
20
+ # @param [Hash or MergingHeterogenousList.type] child The object to add to the MergingHeterogenousList.
21
+ def <<(child)
22
+ child_type = validate_expected_child_type(child)
23
+ if child_id_of.has_key?(child_type[0]) && child_id_of[child_type[0]].has_key?(child[child_type[1]])
24
+ self.class.attributes_to_merge.each do |attribute|
25
+ child_id_of[child_type[0]][child[child_type[1]]][attribute].merge!(child[attribute])
26
+ end
27
+ else
28
+ child_id_of[child_type[0]] ||= {}
29
+ child_id_of[child_type[0]][child[child_type[1]]] = child
30
+ meth = Array.instance_method(:<<)
31
+ meth.bind(self).call(child)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ module TPX_2_2
2
+ # A list (Array) whose elements are all the same type and have the same id attribute
3
+ # (MergingHomogeneousList.child_id) and who merges certain attributes on duplicate object insert.
4
+ class MergingHomogeneousList < HomogeneousList
5
+
6
+ class << self
7
+ # This list of attributes to merge on duplicate object id insert.
8
+ attr_accessor :attributes_to_merge
9
+
10
+ # Defines the child attribute names that the list will merge when an object of the same id as an existing list member is inserted.
11
+ # Another accessor for `attributes_to_merge`.
12
+ #
13
+ # @param [Array] attributes The list of attribute names to merge.
14
+ def on_duplicate_addition_merge_attributes(attributes)
15
+ self.attributes_to_merge = attributes
16
+ end
17
+ end
18
+
19
+ # Add a new child to the MergingHomogeneousList (push). Merge `attributes_to_merge` on a duplicate child id insert.
20
+ #
21
+ # @param [Hash or MergingHomogeneousList.type] child The object to add to the MergingHomogeneousList.
22
+ def <<(child)
23
+ unless child.is_a?(self.class.type) && child.has_key?(self.class.child_id)
24
+ raise TPX_2_2::ValidationError, "Element provided to #{self.class}#<< must be #{self.class.type} with key `#{self.class.child_id}`."
25
+ end
26
+ element = self.find {|e| e[self.class.child_id] == child[self.class.child_id] }
27
+ if element.nil?
28
+ super
29
+ else
30
+ self.class.attributes_to_merge.each do |attribute|
31
+ element[attribute].merge!(child[attribute])
32
+ end
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require 'tpx/2_2/data_model'
2
+
3
+ module TPX_2_2
4
+
5
+ # A set of defined network membership, routing topology, ownership, and network announcements.
6
+ class Network < DataModel
7
+ MANDATORY_ATTRIBUTES = [
8
+ :occurred_at_t,
9
+ :asn_number_ui # TODO: Add to specification document
10
+ ]
11
+
12
+ # Overrides the default initialize to add a default occurred_at_t.
13
+ #
14
+ # @param [Hash] input_hash The input hash.
15
+ #
16
+ # @return [DataModel] The returned object.
17
+ def initialize(input_hash)
18
+ input_hash[:occurred_at_t] ||= Time.now.getutc.to_i # TODO: Should we do this here? Should we do this everywhere except ThreatObservable?
19
+ super input_hash
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ require 'tpx/2_2/homogeneous_list'
2
+ require 'tpx/2_2/network'
3
+
4
+ module TPX_2_2
5
+
6
+ # A list of network objects.
7
+ class NetworkList < HomogeneousList
8
+ homogeneous_list_of Network
9
+ children_keyed_by :asn_number_ui
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'tpx/2_2/data_model'
2
+
3
+ module TPX_2_2
4
+
5
+ # A name associated with a measurement of risk including a
6
+ # description of the risk and one or more classifications
7
+ # associated with one or more network elements
8
+ class Observable < DataModel
9
+ MANDATORY_ATTRIBUTES = [
10
+ :observable_id_s
11
+ ]
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'tpx/2_2/data_model'
2
+
3
+ module TPX_2_2
4
+
5
+ # An map of attributes associated with the observable
6
+ # that are common across all subjects
7
+ class ObservableAttributeMap < DataModel
8
+ MANDATORY_ATTRIBUTES = [
9
+ :occurred_at_t
10
+ ]
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require 'tpx/2_2/data_model'
2
+ require 'tpx/2_2/observable_attribute_map'
3
+ require 'tpx/2_2/classification_element_list'
4
+
5
+ module TPX_2_2
6
+
7
+ # The definition of an observable.
8
+ class ObservableDefinition < DataModel
9
+ MANDATORY_ATTRIBUTES = [
10
+ :observable_id_s, # TODO: Clarify handling of file hash in specification document
11
+ :description_s,
12
+ :classification_c_array,
13
+ ]
14
+ end
15
+ end