ruby_stix 0.0.2-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/lib/cybox_bindings.jar +0 -0
- data/lib/ruby_stix/api/api_helper.rb +307 -0
- data/lib/ruby_stix/api/base_object_property_type.rb +3 -0
- data/lib/ruby_stix/api/indicator.rb +28 -0
- data/lib/ruby_stix/api/object.rb +26 -0
- data/lib/ruby_stix/api/observable.rb +26 -0
- data/lib/ruby_stix/api/observables_type.rb +8 -0
- data/lib/ruby_stix/api/stix_type.rb +56 -0
- data/lib/ruby_stix/api.rb +11 -0
- data/lib/ruby_stix/marshall.rb +169 -0
- data/lib/ruby_stix/method_translations.rb +0 -0
- data/lib/ruby_stix/version.rb +3 -0
- data/lib/ruby_stix.rb +191 -0
- data/lib/stix_bindings.jar +0 -0
- data/ruby_stix.gemspec +23 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/test_data/fireeye-pivy-report.xml +4936 -0
- data/spec/units/campaign_spec.rb +15 -0
- data/spec/units/constructor_spec.rb +61 -0
- data/spec/units/id_helper_spec.rb +18 -0
- data/spec/units/indicator_spec.rb +44 -0
- data/spec/units/list_helper_spec.rb +16 -0
- data/spec/units/method_name_fixer_spec.rb +7 -0
- data/spec/units/namespace_cleaner_spec.rb +34 -0
- data/spec/units/object_spec.rb +37 -0
- data/spec/units/observable_spec.rb +38 -0
- data/spec/units/setter_spec.rb +52 -0
- data/spec/units/stix_type_spec.rb +66 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 112ae61c03f537dfd3b01d0dffaeedd15ad82300
|
4
|
+
data.tar.gz: 695c4969f7eca8b727d458c77ae76597a8335782
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c1ad8b82de21c3ddc359aaf98d7b0ead9f06dbe34b795efd2934c4730b4d741d4c72cf7d7e4279503aa9594b2b21d4d4af1ba6a807c27bffb3d3fc0bfd31777a
|
7
|
+
data.tar.gz: 6a7731bf85bdd57817956d43c1c7e667643114fa245d39a6d6eb20e76670568ba7046d43fde478fa3875889d6e2e98c1c7f860931129167468ddb0689b1de1c2
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby-1.7.9
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 John Wunder
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# StixRuby
|
2
|
+
|
3
|
+
Bindings for generating and parsing STIX documents in JRuby. It relies on java-stix.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'ruby_stix', :git => "http://github.com/johnwunder/ruby-stix.git"
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Or, clone this repository, build the gem, and install it manually as:
|
16
|
+
|
17
|
+
$ rake build
|
18
|
+
$ gem install pkg/ruby_stix.gem
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
TODO
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
|
26
|
+
1. Fork it
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
Binary file
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
java_import 'javax.xml.datatype.DatatypeFactory'
|
5
|
+
|
6
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
7
|
+
inflect.acronym 'TTP'
|
8
|
+
inflect.acronym 'TTPs'
|
9
|
+
end
|
10
|
+
|
11
|
+
class Java::OrgMitre::ApiHelper
|
12
|
+
|
13
|
+
BLACKLIST = ["getClass", "hashCode", "equals", "toString", "notify", "notifyAll", "wait"]
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
# Every time we create an object, we try to annotate that object's class. If the class has been annotated already,
|
17
|
+
# this does nothing.
|
18
|
+
annotate_class!
|
19
|
+
|
20
|
+
# Call the super constructor to create the java object backing
|
21
|
+
super()
|
22
|
+
|
23
|
+
# We add several options for creating new objects. This method figures out what the particular object we're creating
|
24
|
+
# supports and then processes the arguments. It will throw an error if invalid arguments are passed.
|
25
|
+
process_constructor_args(*args)
|
26
|
+
|
27
|
+
# (TODO: This may not be the right place to put this?)
|
28
|
+
# Generate an ID if the object supports it and we didn't set something manually
|
29
|
+
self.generate_id! if should_create_id?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns whether or not a new object should have an auto-generated ID. The criteria are:
|
33
|
+
# 1. It responds to "id" and "idref" (i.e. is a STIX-idable object)
|
34
|
+
# 2. It doesn't have "suppress_id" set
|
35
|
+
# 3. There's no id or idref set already
|
36
|
+
def should_create_id?
|
37
|
+
self.respond_to?(:id) && self.respond_to?(:idref) && !self.class.suppress_id? && self.idref.nil? && self.id.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Process arguments that are passed to the constructor
|
41
|
+
# There are a couple options here:
|
42
|
+
|
43
|
+
# 1. A hash is passed, which will call appropriate setter methods to set each value to the key
|
44
|
+
# 2. A string is passed, which will set the string value of the element
|
45
|
+
# 3. A string and hash are passed, which will do both
|
46
|
+
# 4. Nothing is passed, which will just create the object
|
47
|
+
def process_constructor_args(*args)
|
48
|
+
# If two arguments are passed, option #3 is the winner. The first argument will set the value and the second argument is the kv hash
|
49
|
+
if args.length == 2 && self.respond_to?("value=")
|
50
|
+
self.value = args[0]
|
51
|
+
args = args[1]
|
52
|
+
# If one argument is passed and it's not a hash, try to set it as the value (likely it's a string) and use an empty hash as the kv hash
|
53
|
+
elsif args.length == 1 && !args[0].kind_of?(Hash) && self.respond_to?("value=")
|
54
|
+
self.value = args[0]
|
55
|
+
args = {}
|
56
|
+
# If one argument is passed and it's a hash, use that as the kv hash
|
57
|
+
elsif args.length == 1 && args[0].kind_of?(Hash)
|
58
|
+
args = args[0]
|
59
|
+
# If nothing was passed, use an empty hash as the kv hash
|
60
|
+
elsif args.length == 0
|
61
|
+
args = {}
|
62
|
+
elsif args.first.kind_of?(Array)
|
63
|
+
handle_array_argument(self, args.first)
|
64
|
+
args = {}
|
65
|
+
# Finally, throw an error if the arguments are anything else
|
66
|
+
else
|
67
|
+
raise "Invalid arguments to construct #{self.class.to_s}: #{args.inspect}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# If key/value pairs were passed, use them
|
71
|
+
process_args(args).each do |key, value|
|
72
|
+
process_single_argument(key, value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def process_single_argument(k, v)
|
77
|
+
# If we respond to the setter, call it. This effectively allows Java-style keyword argument names to be used
|
78
|
+
if self.respond_to?("set#{k}")
|
79
|
+
self.send("set#{k}", v)
|
80
|
+
# If we respond to the Ruby setter, call it. This allows Ruby-style keyword argument names to be used
|
81
|
+
elsif self.respond_to?("#{k}=")
|
82
|
+
self.send("#{k}=", v)
|
83
|
+
# If the value is an array, we can handle it a little differently
|
84
|
+
# Note that some array arguments might get caught by the setter
|
85
|
+
elsif v.kind_of?(Array)
|
86
|
+
# Find the Java method name even if we used a Ruby-style name. This is imperfect so may throw errors.
|
87
|
+
java_method_name = java_method_name_for_key(k)
|
88
|
+
|
89
|
+
expected_type = nil
|
90
|
+
|
91
|
+
# Add each value individually to the list
|
92
|
+
v.each do |value|
|
93
|
+
argument_type = find_generic_argument_for(java_method_name)
|
94
|
+
|
95
|
+
value = auto_create_object(argument_type, value)
|
96
|
+
|
97
|
+
# Finally, set the value
|
98
|
+
self.send(java_method_name).add(value)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
raise ArgumentError.new("Invalid argument to construct #{self.class.to_s}: `#{k}`")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def java_method_name_for_key(k)
|
106
|
+
if self.respond_to?("get#{k}")
|
107
|
+
"get#{k}"
|
108
|
+
elsif self.respond_to?("get#{to_java_name(k)}")
|
109
|
+
"get#{to_java_name(k)}"
|
110
|
+
else
|
111
|
+
raise "Unable to find corresponding java method for #{k}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Finds the expected class for a list by parsing it out of the Java signature. This kind of blows but the way Java
|
116
|
+
# implements generics (type erasure) means the JRuby code does not have access to the generic type.
|
117
|
+
def find_generic_argument_for(k)
|
118
|
+
return eval(self.java_class.java_method(k).to_generic_string.match(/<(.+)>/)[1])
|
119
|
+
end
|
120
|
+
|
121
|
+
# Convert a Ruby-style method name (lower snake) to a Java-style method name (camel)
|
122
|
+
# This is imperfect, really I would like to re-use the JRuby logic but don't know how.
|
123
|
+
def to_java_name(string)
|
124
|
+
string.to_s.camelize
|
125
|
+
end
|
126
|
+
|
127
|
+
# Generate a random ID. Uses the ID namespace if it's been set.
|
128
|
+
def generate_id!
|
129
|
+
self.id = StixRuby.generate_id(self.class.to_s.split('::').last.gsub('Type', '').downcase)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Theoretically method_missing might be used for more, but currently it just tries to catch "add_"
|
133
|
+
# calls and direct them to the appropriate child.
|
134
|
+
# TODO: Should we just define these methods manually by iterating over all methods and finding lists?
|
135
|
+
def method_missing(method_name, *args)
|
136
|
+
# Catch us trying to "add_observable" to "ObservablesType" and correctly handle it
|
137
|
+
if matches = method_name.to_s.match(/^add_(.+)$/)
|
138
|
+
if matches[1] && self.respond_to?(matches[1].pluralize)
|
139
|
+
java_method_name = java_method_name_for_key(matches[1].pluralize)
|
140
|
+
if respond_to?(java_method_name)
|
141
|
+
# If the method is a list, try to add the object
|
142
|
+
if send(java_method_name).class == Java::JavaUtil::ArrayList # Need to do an equality check on the class because sometimes other classes masquerade as lists
|
143
|
+
argument_type = find_generic_argument_for(java_method_name)
|
144
|
+
self.send(java_method_name).add(auto_create_object(argument_type, args.first))
|
145
|
+
elsif send(java_method_name).nil?
|
146
|
+
# Use the setter...
|
147
|
+
send(java_method_name.gsub(/^get/, "set"), args)
|
148
|
+
else
|
149
|
+
# We already have an item in the list, so just add the new one
|
150
|
+
intermediate = send(java_method_name)
|
151
|
+
argument_type = intermediate.find_generic_argument_for(java_method_name)
|
152
|
+
intermediate.send(java_method_name).add(auto_create_object(argument_type, args.first))
|
153
|
+
end
|
154
|
+
else
|
155
|
+
super
|
156
|
+
end
|
157
|
+
else
|
158
|
+
super
|
159
|
+
end
|
160
|
+
else
|
161
|
+
super
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# This is a callback that children can override to add fancy helpers to constructor arguments
|
166
|
+
# Here though it's a pass-through
|
167
|
+
def process_args(args)
|
168
|
+
args
|
169
|
+
end
|
170
|
+
|
171
|
+
# Some behavior to determine whether to generate an ID
|
172
|
+
def self.suppress_id
|
173
|
+
@suppress_id = true
|
174
|
+
end
|
175
|
+
|
176
|
+
# TODO: This would be better without the multiple checks...
|
177
|
+
def self.suppress_id?
|
178
|
+
@suppress_id == true || (superclass.respond_to?(:suppress_id) && superclass.suppress_id?)
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.annotate!
|
182
|
+
# Mark us as annotated
|
183
|
+
@annotated = true
|
184
|
+
|
185
|
+
# Annotate superclass if it's ok with that
|
186
|
+
self.superclass.annotate! if self.superclass.respond_to?(:annotate!)
|
187
|
+
|
188
|
+
# JRuby->Ruby name translation is not perfect and, for example, screws up "TTP"
|
189
|
+
# This will go through all methods and correct the ruby methods
|
190
|
+
StixRuby::IRREGULARS.each do |irregular_pattern, correct_pattern|
|
191
|
+
self.instance_methods.select {|m| m.to_s =~ irregular_pattern}.each do |irregular|
|
192
|
+
alias_method irregular.to_s.gsub(irregular_pattern, correct_pattern), irregular
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Hooks into both Ruby and Java-style setters and makes them a little more intelligent by trying
|
197
|
+
# to handle arrays appropriately and call constructors automatically when necessary
|
198
|
+
self.setter_methods.each do |method_name, java_method|
|
199
|
+
# Find the type of the argument and the name of the method
|
200
|
+
argument_type = java_method.argument_types.first.ruby_class
|
201
|
+
|
202
|
+
# Do not annotate this method if it's already annotated or has a basic value constructor
|
203
|
+
next if argument_type == Java::JavaLang::Object || self.annotated_method?(method_name)
|
204
|
+
|
205
|
+
# Mark this method as annotated
|
206
|
+
self.annotated_method(method_name)
|
207
|
+
|
208
|
+
# Alias the raw version
|
209
|
+
alias_method method_name + "Raw", method_name
|
210
|
+
|
211
|
+
# Re-define the method
|
212
|
+
define_method method_name, ->(*args) do
|
213
|
+
# Must have at least one argument
|
214
|
+
raise ArgumentError.new("Wrong number of arguments (0 for 1)") if args.nil? || args.length == 0
|
215
|
+
|
216
|
+
# Pass the argument to the raw setter if it's already of the correct type
|
217
|
+
if args.first.kind_of?(argument_type)
|
218
|
+
send(method_name + "Raw", *args)
|
219
|
+
# This handles cases where we have essentially a wrapper element around an array
|
220
|
+
# and allows us to just set the array
|
221
|
+
elsif args.first.kind_of?(Array)
|
222
|
+
new_obj = argument_type.new
|
223
|
+
handle_array_argument(new_obj, args.first)
|
224
|
+
send(method_name + "Raw", new_obj)
|
225
|
+
else
|
226
|
+
# Try to auto-create the object (magic happens here)
|
227
|
+
object = auto_create_object(argument_type, args.first)
|
228
|
+
|
229
|
+
send(method_name + "Raw", object)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# Returns the Ruby or Java setter method name and the corresponding java setter method reference
|
236
|
+
def self.setter_methods
|
237
|
+
self.java_class.java_instance_methods.select {|method| method.name =~ /^set/ && !(method.name =~ /Raw$/)}.map { |method|
|
238
|
+
# If the method accepts more than one argument, ignore it
|
239
|
+
if method.argument_types.length == 1
|
240
|
+
methods = [[method.name, method]]
|
241
|
+
methods << [ruby_name(method.name), method] if self.instance_methods.find {|m| m.to_s == ruby_name(method.name)}
|
242
|
+
ruby_setter = ruby_name(method.name.gsub("set", "") + "=")
|
243
|
+
methods << [ruby_setter, method] if self.instance_methods.find {|m| m.to_s == ruby_setter}
|
244
|
+
methods
|
245
|
+
else
|
246
|
+
nil
|
247
|
+
end
|
248
|
+
}.compact.flatten(1)
|
249
|
+
end
|
250
|
+
|
251
|
+
def handle_array_argument(assign_to, argument)
|
252
|
+
# Create the array destination
|
253
|
+
# Try to find the appropriate getter method for the array
|
254
|
+
getter = assign_to.java_class.java_instance_methods.reject {|m| BLACKLIST.include?(m.name) || m.return_type != java.util.List.java_class }
|
255
|
+
raise "Unable to automatically determine array container, please explicitly specify it" if getter.length != 1
|
256
|
+
getter = getter.first.name
|
257
|
+
array = assign_to.send(getter)
|
258
|
+
getter_reference = assign_to.java_class.java_method(getter).to_generic_string.match(/<(.+)>/)[1]
|
259
|
+
expected_type = eval(getter_reference)
|
260
|
+
argument.each {|item|
|
261
|
+
array.add(auto_create_object(expected_type, item))
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
def auto_create_object(argument_type, arg)
|
266
|
+
if arg.kind_of?(argument_type)
|
267
|
+
arg
|
268
|
+
elsif argument_type.respond_to?(:from_value)
|
269
|
+
argument_type.from_value(arg)
|
270
|
+
# Handle an array argument
|
271
|
+
# JAXB dates are really F'd up, so autoconvert them
|
272
|
+
elsif argument_type == javax.xml.datatype.XMLGregorianCalendar
|
273
|
+
calendar = java.util.GregorianCalendar.new
|
274
|
+
calendar.setTime(arg.to_java)
|
275
|
+
DatatypeFactory.newInstance.newXMLGregorianCalendar(calendar)
|
276
|
+
else
|
277
|
+
argument_type.new(arg)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.ruby_name(method)
|
282
|
+
method.underscore
|
283
|
+
end
|
284
|
+
|
285
|
+
# A bunch of crap for detecting when things have already been annotated
|
286
|
+
def self.annotated?
|
287
|
+
@annotated == true
|
288
|
+
end
|
289
|
+
|
290
|
+
def annotated?
|
291
|
+
self.class.annotated?
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.annotated_method?(name)
|
295
|
+
@annotated_methods ||= Set.new
|
296
|
+
@annotated_methods.include?(name) || (self.superclass.respond_to?(:annotated_method?) && self.superclass.annotated_method?(name))
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.annotated_method(method)
|
300
|
+
@annotated_methods ||= Set.new
|
301
|
+
@annotated_methods.add(method)
|
302
|
+
end
|
303
|
+
|
304
|
+
def annotate_class!
|
305
|
+
self.class.annotate! unless annotated?
|
306
|
+
end
|
307
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Java::OrgMitreStixIndicator::IndicatorType
|
2
|
+
def item=(val)
|
3
|
+
if val.kind_of?(org.mitre.cybox.core.ObservableType)
|
4
|
+
self.observable = val
|
5
|
+
elsif val.kind_of?(org.mitre.cybox.core.ObjectType)
|
6
|
+
self.observable = org.mitre.cybox.core.ObservableType.new(:object => val)
|
7
|
+
elsif val.kind_of?(org.mitre.cybox.core.EventType)
|
8
|
+
self.observable = org.mitre.cybox.core.ObservableType.new(:event => val)
|
9
|
+
elsif val.kind_of?(org.mitre.cybox.common.ObjectPropertiesType)
|
10
|
+
self.observable = org.mitre.cybox.core.ObservableType.new(:object => org.mitre.cybox.core.ObjectType.new(:properties => val))
|
11
|
+
elsif val.kind_of?(Hash) && val[:operator]
|
12
|
+
self.composite_indicator_expression = process_composition(val)
|
13
|
+
else
|
14
|
+
raise "Unknown item type: #{val.class}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_composition(composition_hash)
|
19
|
+
operator = org.mitre.stix.indicator.OperatorTypeEnum.from_value(composition_hash[:operator].to_s.upcase)
|
20
|
+
composition = org.mitre.stix.indicator.CompositeIndicatorExpressionType.new(:operator => operator)
|
21
|
+
composition_hash[:items].each do |item|
|
22
|
+
indicator = item.kind_of?(org.mitre.stix.common.IndicatorBaseType) ? item : self.class.new(:item => item)
|
23
|
+
composition.add_indicator(indicator)
|
24
|
+
end
|
25
|
+
|
26
|
+
return composition
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Java::OrgMitreCyboxCore::ObjectType
|
2
|
+
def add_related_object(object, relationship = nil)
|
3
|
+
self.related_objects ||= org.mitre.cybox.core.RelatedObjectsType.new
|
4
|
+
|
5
|
+
if object.kind_of?(org.mitre.cybox.core.RelatedObjectType)
|
6
|
+
self.related_objects.add_related_object(object)
|
7
|
+
else
|
8
|
+
related_object = org.mitre.cybox.core.RelatedObjectType.new(:idref => object.id)
|
9
|
+
if relationship
|
10
|
+
if relationship.kind_of?(String)
|
11
|
+
# Ugh, why does Java throw an exception here?
|
12
|
+
begin
|
13
|
+
enum = org.mitre.cybox.vocabularies.ObjectRelationshipEnum10.from_value(relationship)
|
14
|
+
related_object.relationship = org.mitre.cybox.vocabularies.ObjectRelationshipVocab10.new(:value => enum.value)
|
15
|
+
rescue
|
16
|
+
related_object.relationship = org.mitre.cybox.common.ControlledVocabularyStringType.new(:value => relationship)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
related_object.relationship = relationship
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
self.related_objects.add_related_object(related_object)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Java::OrgMitreCyboxCore::ObservableType
|
2
|
+
def item=(val)
|
3
|
+
if val.kind_of?(org.mitre.cybox.core.ObjectType)
|
4
|
+
self.object = val
|
5
|
+
elsif val.kind_of?(org.mitre.cybox.core.EventType)
|
6
|
+
self.event = val
|
7
|
+
elsif val.kind_of?(org.mitre.cybox.common.ObjectPropertiesType)
|
8
|
+
self.object = Java::OrgMitreCyboxCore::ObjectType.new(:properties => val)
|
9
|
+
elsif val.kind_of?(Hash) && val[:operator]
|
10
|
+
self.observable_composition = process_composition(val)
|
11
|
+
else
|
12
|
+
raise "Unknown item type: #{val.class}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_composition(composition_hash)
|
17
|
+
operator = org.mitre.cybox.core.OperatorTypeEnum.from_value(composition_hash[:operator].to_s.upcase)
|
18
|
+
composition = Java::OrgMitreCyboxCore::ObservableCompositionType.new(:operator => operator)
|
19
|
+
composition_hash[:items].each do |item|
|
20
|
+
observable = item.kind_of?(org.mitre.cybox.core.ObservableType) ? item : self.class.new(:item => item)
|
21
|
+
composition.add_observable(observable)
|
22
|
+
end
|
23
|
+
|
24
|
+
return composition
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Java::OrgMitreStixCore::STIXType
|
2
|
+
include StixRuby::Marshall
|
3
|
+
|
4
|
+
def add_observable(observable)
|
5
|
+
self.observables ||= org.mitre.cybox.core.ObservablesType.new(:cybox_major_version => '2', :cybox_minor_version => '1')
|
6
|
+
self.observables.add_observable(observable)
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_campaign(campaign)
|
10
|
+
self.campaigns ||= org.mitre.stix.core.CampaignsType.new
|
11
|
+
self.campaigns.add_campaign(campaign)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_course_of_action(coa)
|
15
|
+
self.courses_of_action ||= org.mitre.stix.core.CoursesOfActionType.new
|
16
|
+
self.courses_of_action.course_of_actions.add(coa)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_exploit_target(et)
|
20
|
+
self.exploit_targets ||= org.mitre.stix.common.ExploitTargetsType.new
|
21
|
+
self.exploit_targets.add_exploit_target(et)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_incident(incident)
|
25
|
+
self.incidents ||= org.mitre.stix.core.IncidentsType.new
|
26
|
+
self.incidents.add_incident(incident)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_indicator(indicator)
|
30
|
+
self.indicators ||= org.mitre.stix.core.IndicatorsType.new
|
31
|
+
self.indicators.add_indicator(indicator)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_threat_actor(ta)
|
35
|
+
self.threat_actors ||= org.mitre.stix.core.ThreatActorsType.new
|
36
|
+
self.threat_actors.add_threat_actor(ta)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ttps
|
40
|
+
self.getTTPs
|
41
|
+
end
|
42
|
+
|
43
|
+
def ttps=(val)
|
44
|
+
self.setTTPs(val)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_ttp(ttp)
|
48
|
+
self.ttps ||= org.mitre.stix.core.TTPsType.new
|
49
|
+
self.ttps.getTTPS.add(ttp)
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_args(args)
|
53
|
+
args[:version] ||= "1.0.1"
|
54
|
+
args
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'ruby_stix'
|
2
|
+
|
3
|
+
require 'ruby_stix/marshall'
|
4
|
+
|
5
|
+
require 'ruby_stix/api/api_helper'
|
6
|
+
require 'ruby_stix/api/indicator'
|
7
|
+
require 'ruby_stix/api/observable'
|
8
|
+
require 'ruby_stix/api/object'
|
9
|
+
require 'ruby_stix/api/observables_type'
|
10
|
+
require 'ruby_stix/api/stix_type'
|
11
|
+
require 'ruby_stix/api/base_object_property_type'
|