opentpx 2.2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +15 -0
- data/README.md +44 -0
- data/bin/opentpx_tools +15 -0
- data/lib/tpx.rb +7 -0
- data/lib/tpx/2_2/attribute_accessors.rb +34 -0
- data/lib/tpx/2_2/classification_element.rb +11 -0
- data/lib/tpx/2_2/classification_element_list.rb +11 -0
- data/lib/tpx/2_2/collection.rb +21 -0
- data/lib/tpx/2_2/collection_element.rb +13 -0
- data/lib/tpx/2_2/data_model.rb +32 -0
- data/lib/tpx/2_2/element_observable.rb +41 -0
- data/lib/tpx/2_2/element_observable_list.rb +17 -0
- data/lib/tpx/2_2/exceptions.rb +13 -0
- data/lib/tpx/2_2/exchange.rb +220 -0
- data/lib/tpx/2_2/heterogeneous_list.rb +136 -0
- data/lib/tpx/2_2/homogeneous_list.rb +82 -0
- data/lib/tpx/2_2/mandatory_attributes.rb +69 -0
- data/lib/tpx/2_2/merging_heterogeneous_list.rb +36 -0
- data/lib/tpx/2_2/merging_homogeneous_list.rb +37 -0
- data/lib/tpx/2_2/network.rb +23 -0
- data/lib/tpx/2_2/network_list.rb +11 -0
- data/lib/tpx/2_2/observable.rb +13 -0
- data/lib/tpx/2_2/observable_attribute_map.rb +12 -0
- data/lib/tpx/2_2/observable_definition.rb +15 -0
- data/lib/tpx/2_2/observable_dictionary.rb +12 -0
- data/lib/tpx/2_2/schema/tpx.2.2.schema.json +632 -0
- data/lib/tpx/2_2/threat_observable.rb +14 -0
- data/lib/tpx/2_2/validator.rb +279 -0
- data/lib/tpx/tools.rb +81 -0
- data/lib/tpx/version.rb +3 -0
- data/lib/tpx_2_2.rb +14 -0
- metadata +218 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'tpx/2_2/data_model'
|
2
|
+
require 'tpx/2_2/observable'
|
3
|
+
|
4
|
+
|
5
|
+
module TPX_2_2
|
6
|
+
|
7
|
+
# The representation of the threat observable (the hash map keyed
|
8
|
+
# by the observable_id within the element observable).
|
9
|
+
class ThreatObservable < Observable
|
10
|
+
MANDATORY_ATTRIBUTES = Observable::MANDATORY_ATTRIBUTES + [
|
11
|
+
:occurred_at_t
|
12
|
+
]
|
13
|
+
end # class
|
14
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
require 'deep_merge'
|
2
|
+
# This uses the TPX JSON Schema to validate an input document.
|
3
|
+
module TPX_2_2
|
4
|
+
class Validator
|
5
|
+
|
6
|
+
class << self
|
7
|
+
TPX_KEYS = ['observable_dictionary_c_array', 'element_observable_c_array', 'collection_c_array', 'asn_c_array']
|
8
|
+
MANIFEST_KEYS = ['dictionary_file_manifest', 'observable_element_file_manifest', 'collection_file_manifest', 'network_file_manifest']
|
9
|
+
|
10
|
+
# validate_file! opens json file and validates it. Raises an error if validation fails.
|
11
|
+
#
|
12
|
+
# @param [String] filepath path to file which needs to be validated.
|
13
|
+
# @example
|
14
|
+
# TPX_2_2::Validator.validate_file!('folder_name/file_name.json')
|
15
|
+
def validate_file!(filepath)
|
16
|
+
unless File.exists? filepath
|
17
|
+
raise ValidationError , "No such file or directory '#{filepath}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
@@current_path = File.dirname(filepath)
|
21
|
+
|
22
|
+
begin
|
23
|
+
h = Oj.load_file(filepath)
|
24
|
+
rescue => e
|
25
|
+
raise ValidationError, "File '#{filepath}' is not a valid JSON file:\n#{e}"
|
26
|
+
end
|
27
|
+
|
28
|
+
if h.kind_of?(Hash) and tpx_manifest?(h)
|
29
|
+
DeepMerge::deep_merge!(load_manifest_files(h), h, {:merge_hash_arrays => true})
|
30
|
+
delete_manifest_keys!(h)
|
31
|
+
end
|
32
|
+
|
33
|
+
validate!(h)
|
34
|
+
end
|
35
|
+
|
36
|
+
# validate_json! validates json string. Raises an error if validation fails.
|
37
|
+
#
|
38
|
+
# @param [String] json_enc_str the json string which need to be validated.
|
39
|
+
# @example
|
40
|
+
# TPX_2_2::Validator.validate_json!("{\"provider_s\":\"provider\",\"schema_version_s\":\"2.1.6\",\"source_observable_s\":\"source_observable\",\"source_description_s\":\"source_description\",\"distribution_time_t\":1438862400,\"last_updated_t\":1438862400,\"list_name_s\":\"list_name\",\"element_observable_c_array\":[{\"subject_s\":\"192.168.0.1\",\"type_s\":\"ipv4\",\"score_i\":80,\"score_24hr_decay_i\":0,\"threat_observable_c_map\":{\"Conficker\":{\"occurred_at_t\":4355545,\"last_seen_t\":13123}}}],\"observable_dictionary_c_array\":[{\"observable_id_s\":\"Malicious Host\",\"description_s\":\"This network node is a malicious host.\",\"criticality_i\":20,\"classification_c_array\":[{\"classification_id_s\":\"Malicious Host\",\"criticality_i\":20}]}],\"collection_c_array\":[{\"name_id_s\":\"MarketSeg1\",\"occurred_at_t\":1212312323,\"last_updated_t\":1212312323,\"description_s\":\"This collection is related to MarketSeg1\",\"author_s\":\"Allan Thomson\",\"workspace_s\":\"lg-system\"}],\"asn_c_array\":[{\"asn_number_ui\":1,\"occurred_at_t\":1212312323,\"as_owner_s\":\"ABC Corp\"}]}")
|
41
|
+
def validate_json!(json_enc_str)
|
42
|
+
h = Oj.load(json_enc_str)
|
43
|
+
validate!(h)
|
44
|
+
end
|
45
|
+
|
46
|
+
# validate! validates hash. Raises an error if validation fails.
|
47
|
+
#
|
48
|
+
# @param [Hash] input_hash the hash which needs to be validated.
|
49
|
+
# @example
|
50
|
+
# TPX_2_2::Validator.validate!({
|
51
|
+
# 'provider_s': 'provider',
|
52
|
+
# 'schema_version_s': '2.1.6',
|
53
|
+
# 'source_observable_s': 'source_observable',
|
54
|
+
# 'source_description_s': 'source_description',
|
55
|
+
# 'distribution_time_t': 1438862400,
|
56
|
+
# 'last_updated_t': 1438862400,
|
57
|
+
# 'list_name_s': 'list_name',
|
58
|
+
# 'element_observable_c_array': [
|
59
|
+
# {
|
60
|
+
# 'subject_s': '192.168.0.1',
|
61
|
+
# 'type_s': 'ipv4',
|
62
|
+
# 'score_i': 80,
|
63
|
+
# 'score_24hr_decay_i': 0,
|
64
|
+
# 'threat_observable_c_map': {
|
65
|
+
# 'Conficker': {
|
66
|
+
# 'occurred_at_t': 4355545,
|
67
|
+
# 'last_seen_t': 13123
|
68
|
+
# }
|
69
|
+
# }
|
70
|
+
# }
|
71
|
+
# ],
|
72
|
+
# 'observable_dictionary_c_array': [
|
73
|
+
# {
|
74
|
+
# 'observable_id_s': 'Malicious Host',
|
75
|
+
# 'description_s': 'This network node is a malicious host.',
|
76
|
+
# 'criticality_i': 20,
|
77
|
+
# 'classification_c_array': [
|
78
|
+
# {
|
79
|
+
# 'classification_id_s': 'Malicious Host',
|
80
|
+
# 'criticality_i': 20
|
81
|
+
# }
|
82
|
+
# ]
|
83
|
+
# }
|
84
|
+
# ],
|
85
|
+
# 'collection_c_array': [
|
86
|
+
# {
|
87
|
+
# 'name_id_s': 'MarketSeg1',
|
88
|
+
# 'occurred_at_t': 1212312323,
|
89
|
+
# 'last_updated_t': 1212312323,
|
90
|
+
# 'description_s': 'This collection is related to MarketSeg1',
|
91
|
+
# 'author_s': 'Allan Thomson',
|
92
|
+
# 'workspace_s': 'lg-system'
|
93
|
+
# }
|
94
|
+
# ],
|
95
|
+
# 'asn_c_array': [
|
96
|
+
# {
|
97
|
+
# 'asn_number_ui': 1,
|
98
|
+
# 'occurred_at_t': 1212312323,
|
99
|
+
# 'as_owner_s': 'ABC Corp'
|
100
|
+
# }
|
101
|
+
# ]
|
102
|
+
# })
|
103
|
+
def validate!(input_hash)
|
104
|
+
@@undefined_observables = []
|
105
|
+
|
106
|
+
if input_hash.nil? || input_hash.empty?
|
107
|
+
raise ValidationError, " TPX has no content"
|
108
|
+
end
|
109
|
+
|
110
|
+
validate_schema!(input_hash)
|
111
|
+
|
112
|
+
if (TPX_KEYS & input_hash.keys).length > 0 && tpx_manifest?(input_hash)
|
113
|
+
raise TPX_2_2::ValidationError, "TPX file must either be in single-file or manifest format."
|
114
|
+
end
|
115
|
+
|
116
|
+
validate_element_observables!(input_hash['element_observable_c_array'])
|
117
|
+
validate_observable_dictionary!(input_hash['observable_dictionary_c_array'], input_hash['element_observable_c_array'])
|
118
|
+
validate_collections!(input_hash['collection_c_array'])
|
119
|
+
validate_networks!(input_hash['asn_c_array'])
|
120
|
+
if (input_hash['observable_dictionary_c_array'].nil? || input_hash['observable_dictionary_c_array'].empty?)
|
121
|
+
raise TPX_2_2::ValidationWarning, "observable dictionary is not defined"
|
122
|
+
end
|
123
|
+
unless @@undefined_observables.empty?
|
124
|
+
raise TPX_2_2::ValidationWarning, "observables #{@@undefined_observables.inspect} are not defined in the observable dictionary"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def validate_schema!(input_hash)
|
132
|
+
errors = JSON::Validator.fully_validate(TPX_2_2::SCHEMA, input_hash)
|
133
|
+
raise ValidationError, "#{errors.join(' ')}" unless errors.empty?
|
134
|
+
end
|
135
|
+
|
136
|
+
def validate_element_observables!(element_observable_list)
|
137
|
+
return if element_observable_list.nil? #nothing to validate, just return
|
138
|
+
|
139
|
+
schema = {
|
140
|
+
"type" => "object",
|
141
|
+
"required" => ["threat_observable_c_map"],
|
142
|
+
"properties" => {
|
143
|
+
"threat_observable_c_map" => {"type" => "hash"}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
element_observable_list.each do |element_observable|
|
147
|
+
errors = JSON::Validator.fully_validate(schema, element_observable)
|
148
|
+
raise ValidationError, "#{errors.join(' ')}" unless errors.empty?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def validate_observable_dictionary!(observable_dictionaries, element_observable_list)
|
153
|
+
return if observable_dictionaries.nil? #nothing to validate, just return
|
154
|
+
|
155
|
+
schema = {
|
156
|
+
"type" => "object",
|
157
|
+
"required" => [
|
158
|
+
"observable_id_s",
|
159
|
+
"description_s",
|
160
|
+
"classification_c_array"
|
161
|
+
],
|
162
|
+
"properties" => {
|
163
|
+
"observable_id_s" => {"type" => "string"},
|
164
|
+
"description_s" => {"type" => "string"},
|
165
|
+
"classification_c_array" => {"type" => "hash"}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
observables = []
|
170
|
+
|
171
|
+
observable_dictionaries.each do |observable_dictionary|
|
172
|
+
errors = JSON::Validator.fully_validate(schema, observable_dictionary)
|
173
|
+
raise TPX_2_2::ValidationError, "#{errors.join(' ')}" unless errors.empty?
|
174
|
+
observables << observable_dictionary['observable_id_s']
|
175
|
+
end
|
176
|
+
|
177
|
+
return if element_observable_list.nil?
|
178
|
+
element_observable_list.each do |element_observable|
|
179
|
+
element = element_observable['threat_observable_c_map'] || element_observable[:threat_observable_c_map]
|
180
|
+
element.each_key do |observable|
|
181
|
+
@@undefined_observables << """#{observable}""" unless observables.include? observable
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
def validate_collections!(collections)
|
188
|
+
return if collections.nil? #nothing to validate, just return
|
189
|
+
|
190
|
+
schema = {
|
191
|
+
"type" => "object",
|
192
|
+
"required" => ["name_id_s"],
|
193
|
+
"properties" => {
|
194
|
+
"name_id_s" => {"type" => "string"}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
collections.each do |collection|
|
199
|
+
errors = JSON::Validator.fully_validate(schema, collection)
|
200
|
+
raise ValidationError, "#{errors.join(' ')}" unless errors.empty?
|
201
|
+
collection.each do |key, value|
|
202
|
+
if (key == 'collection_c_array') && value.is_a?(Array)
|
203
|
+
validate_collections!(value)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def validate_networks!(networks)
|
210
|
+
return if networks.nil? #nothing to validate, just return
|
211
|
+
|
212
|
+
schema = {
|
213
|
+
"type" => "object",
|
214
|
+
"required" => ["asn_number_ui"],
|
215
|
+
"properties" => {
|
216
|
+
"asn_number_ui" => {"type" => "integer"}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
networks.each do |net|
|
221
|
+
errors = JSON::Validator.fully_validate(schema, net)
|
222
|
+
raise ValidationError, "#{errors.join(' ')}" unless errors.empty?
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# tpx_manifest? returns true if provided hash represents TPX manifest and contains TPX manifest entries
|
227
|
+
#
|
228
|
+
# @param [Hash] Hash with tpx content
|
229
|
+
# @example
|
230
|
+
# TPX_2_2::Validator.tpx_manifest?({ "schema_version_s"=> "2.2.0", "provider_s"=> "Lookingglass Cyber Solutions", "list_name_s"=> "Virus Tracker", "source_observable_s"=> "Virus Tracker", "source_file_s"=> "https://virustracker.net/", "source_description_s"=> "Virus Tracker provides real-time information about virus infections observed through custom sinkholes.", "distribution_time_t"=> 1443007504, "last_updated_t"=> 1443007504, "score_i"=> 90, "dictionary_file_manifest"=> [ "dictionary.json" ], "observable_element_file_manifest"=> [ "data8.json" ]})
|
231
|
+
def tpx_manifest?(input_hash)
|
232
|
+
(MANIFEST_KEYS & input_hash.keys).length > 0
|
233
|
+
end
|
234
|
+
|
235
|
+
# current_path returns the current path which can be one of: 1) current working directory 2) file directory path being validated
|
236
|
+
def current_path
|
237
|
+
@@current_path || Dir.pwd
|
238
|
+
end
|
239
|
+
|
240
|
+
# load_manifest_files loads files referenced in manifests and returns merged content
|
241
|
+
#
|
242
|
+
# @param [Hash] Hash with tpx content
|
243
|
+
def load_manifest_files(input_hash)
|
244
|
+
res = {}
|
245
|
+
MANIFEST_KEYS.each do |manifest_section|
|
246
|
+
files = input_hash[manifest_section]
|
247
|
+
unless files.blank?
|
248
|
+
files.each do |manifest_file|
|
249
|
+
DeepMerge::deep_merge!(load_manifest_file(manifest_file), res, {:merge_hash_arrays => true})
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
res
|
254
|
+
end
|
255
|
+
|
256
|
+
# delete_manifest_keys! deletes manifest keys from input_hash in order to be valid TPX
|
257
|
+
#
|
258
|
+
# @param [Hash] Hash with tpx content
|
259
|
+
def delete_manifest_keys!(input_hash)
|
260
|
+
MANIFEST_KEYS.each do |key|
|
261
|
+
input_hash.delete key
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# load_manifest_file loads TPX content from specified file, in case if file doesn't exists searches for it in current_path. In case if file not found ValidationError is raised
|
266
|
+
#
|
267
|
+
# @param [String] filename
|
268
|
+
def load_manifest_file(filename)
|
269
|
+
return Oj.load_file(filename) if File.exists? filename
|
270
|
+
|
271
|
+
filepath = File.join(current_path, File.basename(filename))
|
272
|
+
return Oj.load_file(filepath) if File.exists? filepath
|
273
|
+
|
274
|
+
raise ValidationError, "Could not find #{filename}"
|
275
|
+
end
|
276
|
+
|
277
|
+
end # class < self
|
278
|
+
end
|
279
|
+
end
|
data/lib/tpx/tools.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'gli'
|
2
|
+
require 'tpx'
|
3
|
+
|
4
|
+
module TPX
|
5
|
+
class Tools
|
6
|
+
extend ::GLI::App
|
7
|
+
|
8
|
+
TPX_VALID = "Validation succeeded"
|
9
|
+
TPX_INVALID = "The TPX file provided is invalid for the following reasons:"
|
10
|
+
TPX_VERSION_UNKNOWN = "Unknown TPX Version: "
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :quiet
|
14
|
+
|
15
|
+
def msg(message)
|
16
|
+
puts message unless quiet
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_tpx_version_const(tpx_version)
|
20
|
+
underscored_tpx_version = tpx_version.gsub('.', '_')
|
21
|
+
Object.const_get("TPX_#{underscored_tpx_version}")
|
22
|
+
rescue NameError => e
|
23
|
+
msg( e )
|
24
|
+
raise TPX_VERSION_UNKNOWN + "'#{tpx_version}'"
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate(tpx_version_const, filepath)
|
28
|
+
begin
|
29
|
+
tpx_version_const::Validator.validate_file! filepath
|
30
|
+
rescue tpx_version_const::ValidationWarning => w
|
31
|
+
msg( "Warning: #{w}" )
|
32
|
+
puts TPX_VALID + " against " + tpx_version_const.to_s
|
33
|
+
rescue => e
|
34
|
+
puts TPX_INVALID
|
35
|
+
puts e
|
36
|
+
else
|
37
|
+
puts TPX_VALID
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
program_desc 'OpenTPX Tools'
|
45
|
+
version TPX::VERSION
|
46
|
+
|
47
|
+
switch [:q, :quiet], default_value: false,
|
48
|
+
desc: 'quiet non-essential output and warnings.'
|
49
|
+
|
50
|
+
#--- COMMAND validate
|
51
|
+
desc "validates that a file is of a valid TPX file format"
|
52
|
+
long_desc "validates that a file is of a valid TPX file format\n\n" \
|
53
|
+
"TPX_FILE_PATH - The path to the TPX file. The file may be either a" \
|
54
|
+
" stand-alone TPX file or a tpx manifest file. For details on TPX" \
|
55
|
+
" manifest, please see https://github.com/Lookingglass/tpx"
|
56
|
+
|
57
|
+
arg 'TPX_FILE_PATH'
|
58
|
+
|
59
|
+
command :validate do |c|
|
60
|
+
c.flag [:v, :tpx_version], default_value: "2.2",
|
61
|
+
arg_name: 'VERSION',
|
62
|
+
type: String,
|
63
|
+
desc: "The version of tpx to validate the file against. Possible" \
|
64
|
+
" values: '2.2'"
|
65
|
+
|
66
|
+
c.action do |global_options, options, args|
|
67
|
+
self.quiet = global_options[:quiet]
|
68
|
+
tpx_version = options[:tpx_version]
|
69
|
+
tpx_file_path = args[0]
|
70
|
+
|
71
|
+
raise "Missing option TPX_VERSION" if tpx_version.nil?
|
72
|
+
raise "Missing arg TPX_FILE_PATH" if tpx_file_path.nil?
|
73
|
+
|
74
|
+
tpx_version = tpx_version.strip
|
75
|
+
msg( "Validating '#{tpx_file_path}' against TPX '#{tpx_version}' schema" )
|
76
|
+
tpx_version_const = get_tpx_version_const(tpx_version)
|
77
|
+
validate(tpx_version_const, tpx_file_path)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/tpx/version.rb
ADDED
data/lib/tpx_2_2.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module TPX_2_2
|
2
|
+
CURRENT_SCHEMA_VERSION = '2.2.0'
|
3
|
+
SCHEMA = File.join(File.dirname(File.expand_path(__FILE__)), 'tpx', '2_2', 'schema', 'tpx.2.2.schema.json')
|
4
|
+
|
5
|
+
require 'json-schema'
|
6
|
+
require 'active_support'
|
7
|
+
require 'active_support/core_ext/object/blank'
|
8
|
+
require 'active_support/core_ext/hash'
|
9
|
+
require 'oj'
|
10
|
+
|
11
|
+
require 'tpx/2_2/exceptions'
|
12
|
+
require 'tpx/2_2/validator'
|
13
|
+
require 'tpx/2_2/exchange'
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opentpx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.2.0.17
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- LookingGlass
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: timecop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: oj
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: json-schema
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.5.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 2.5.1
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: deep_merge
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: gli
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 2.13.2
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 2.13.2
|
153
|
+
description: An open-source format and tools for exchanging threat intelligence data. This
|
154
|
+
is a JSON-based format that allows sharing of data between partner organizations.
|
155
|
+
email:
|
156
|
+
- support@lgscout.com
|
157
|
+
executables:
|
158
|
+
- opentpx_tools
|
159
|
+
extensions: []
|
160
|
+
extra_rdoc_files: []
|
161
|
+
files:
|
162
|
+
- LICENSE.txt
|
163
|
+
- README.md
|
164
|
+
- bin/opentpx_tools
|
165
|
+
- lib/tpx.rb
|
166
|
+
- lib/tpx/2_2/attribute_accessors.rb
|
167
|
+
- lib/tpx/2_2/classification_element.rb
|
168
|
+
- lib/tpx/2_2/classification_element_list.rb
|
169
|
+
- lib/tpx/2_2/collection.rb
|
170
|
+
- lib/tpx/2_2/collection_element.rb
|
171
|
+
- lib/tpx/2_2/data_model.rb
|
172
|
+
- lib/tpx/2_2/element_observable.rb
|
173
|
+
- lib/tpx/2_2/element_observable_list.rb
|
174
|
+
- lib/tpx/2_2/exceptions.rb
|
175
|
+
- lib/tpx/2_2/exchange.rb
|
176
|
+
- lib/tpx/2_2/heterogeneous_list.rb
|
177
|
+
- lib/tpx/2_2/homogeneous_list.rb
|
178
|
+
- lib/tpx/2_2/mandatory_attributes.rb
|
179
|
+
- lib/tpx/2_2/merging_heterogeneous_list.rb
|
180
|
+
- lib/tpx/2_2/merging_homogeneous_list.rb
|
181
|
+
- lib/tpx/2_2/network.rb
|
182
|
+
- lib/tpx/2_2/network_list.rb
|
183
|
+
- lib/tpx/2_2/observable.rb
|
184
|
+
- lib/tpx/2_2/observable_attribute_map.rb
|
185
|
+
- lib/tpx/2_2/observable_definition.rb
|
186
|
+
- lib/tpx/2_2/observable_dictionary.rb
|
187
|
+
- lib/tpx/2_2/schema/tpx.2.2.schema.json
|
188
|
+
- lib/tpx/2_2/threat_observable.rb
|
189
|
+
- lib/tpx/2_2/validator.rb
|
190
|
+
- lib/tpx/tools.rb
|
191
|
+
- lib/tpx/version.rb
|
192
|
+
- lib/tpx_2_2.rb
|
193
|
+
homepage: http://www.opentpx.org
|
194
|
+
licenses:
|
195
|
+
- The Apache License, Version 2.0. See LICENSE.txt
|
196
|
+
metadata: {}
|
197
|
+
post_install_message:
|
198
|
+
rdoc_options: []
|
199
|
+
require_paths:
|
200
|
+
- lib
|
201
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
requirements: []
|
212
|
+
rubyforge_project:
|
213
|
+
rubygems_version: 2.4.3
|
214
|
+
signing_key:
|
215
|
+
specification_version: 4
|
216
|
+
summary: Open Threat Partner Exchange (OpenTPX)
|
217
|
+
test_files: []
|
218
|
+
has_rdoc:
|