opentpx 2.2.0.17

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.
@@ -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