otx_ruby 0.7.1 → 0.8.0

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/circle.yml +1 -1
  3. data/lib/otx_ruby/activity.rb +90 -0
  4. data/lib/otx_ruby/base.rb +42 -2
  5. data/lib/otx_ruby/correlation_rule.rb +13 -0
  6. data/lib/otx_ruby/cve.rb +22 -0
  7. data/lib/otx_ruby/domain.rb +90 -0
  8. data/lib/otx_ruby/events.rb +28 -4
  9. data/lib/otx_ruby/export.rb +103 -0
  10. data/lib/otx_ruby/file.rb +23 -0
  11. data/lib/otx_ruby/hostname.rb +95 -0
  12. data/lib/otx_ruby/ip.rb +105 -0
  13. data/lib/otx_ruby/nids.rb +13 -0
  14. data/lib/otx_ruby/pulses.rb +150 -0
  15. data/lib/otx_ruby/subscribed.rb +19 -4
  16. data/lib/otx_ruby/types/author.rb +8 -0
  17. data/lib/otx_ruby/types/base_indicator.rb +8 -0
  18. data/lib/otx_ruby/types/correlation_rule.rb +21 -0
  19. data/lib/otx_ruby/types/cve.rb +36 -0
  20. data/lib/otx_ruby/types/file_analysis.rb +6 -0
  21. data/lib/otx_ruby/types/indicator_type.rb +6 -0
  22. data/lib/otx_ruby/types/indicator_type_counts.rb +8 -0
  23. data/lib/otx_ruby/types/ip/dns.rb +8 -0
  24. data/lib/otx_ruby/types/ip/general.rb +24 -0
  25. data/lib/otx_ruby/types/ip/geo.rb +8 -0
  26. data/lib/otx_ruby/types/ip/http_scan.rb +8 -0
  27. data/lib/otx_ruby/types/ip/malware.rb +21 -0
  28. data/lib/otx_ruby/types/{ip_reputation.rb → ip/reputation.rb} +0 -0
  29. data/lib/otx_ruby/types/ip/url.rb +8 -0
  30. data/lib/otx_ruby/types/ip/whois.rb +8 -0
  31. data/lib/otx_ruby/types/observation.rb +8 -0
  32. data/lib/otx_ruby/types/pulse.rb +14 -3
  33. data/lib/otx_ruby/types/pulse_info.rb +24 -0
  34. data/lib/otx_ruby/types/reference.rb +8 -0
  35. data/lib/otx_ruby/types/user.rb +21 -0
  36. data/lib/otx_ruby/url.rb +35 -0
  37. data/lib/otx_ruby/users.rb +97 -0
  38. data/lib/otx_ruby/version.rb +1 -1
  39. data/lib/otx_ruby.rb +32 -1
  40. metadata +33 -5
@@ -0,0 +1,13 @@
1
+ module OTX
2
+ class NIDS < OTX::Base
3
+ def get_general(nid)
4
+ uri = "/api/v1/indicators/nids/#{nid}/general"
5
+
6
+ json_data = get(uri)
7
+
8
+ general = OTX::Indicator::IP::General.new(json_data)
9
+
10
+ return general
11
+ end
12
+ end
13
+ end
@@ -3,6 +3,30 @@ module OTX
3
3
  # Retrieve and parse into the appropriate object a pulse from the OTX System
4
4
  #
5
5
  class Pulses < OTX::Base
6
+ #
7
+ # Create a Pulse
8
+ #
9
+ # @param params [Hash] Parameters to create a Pulse
10
+ #
11
+ def create(params)
12
+ uri = '/api/v1/pulses/create'
13
+
14
+ pulse = { body: params }
15
+
16
+ post(uri, pulse)
17
+ end
18
+
19
+ #
20
+ # Validate a Pulse indicator
21
+ #
22
+ # @param indicator [Hash] An indicator key value pair
23
+ #
24
+ def validate_indicator(indicator)
25
+ uri = '/api/v1/pulses/indicators/validate'
26
+
27
+ post(uri, indicator)
28
+ end
29
+
6
30
  #
7
31
  # Download an individually identified pulse and parse the output
8
32
  #
@@ -18,5 +42,131 @@ module OTX
18
42
 
19
43
  return pulse
20
44
  end
45
+
46
+ #
47
+ # Search for Pulses including the query in their datafields
48
+ #
49
+ # @param query [String] Query to search
50
+ # @param limit [Integer] Limit results per page to this number
51
+ # @param page [Integer] Return results for this page
52
+ # @param sort [Symbol] Sort results by modified, created or subscriber_count
53
+ # @return [Array<OTX::Pulse>] Parsed Pulses
54
+ #
55
+ def search(query, limit = 10, page = 1, sort = :created)
56
+ uri = '/api/v1/search/users'
57
+
58
+ if sort == :modified || sort == :subscriber_count
59
+ sort_by = sort.to_s
60
+ else
61
+ sort_by = 'created'
62
+ end
63
+
64
+ params = { q: query, limit: limit, page: page, sort: sort_by }
65
+ results = []
66
+
67
+ json_data = get(uri, params)
68
+
69
+ json_data['results'].each do |pulse|
70
+ results << OTX::Pulse.new(pulse)
71
+ end
72
+
73
+ return results
74
+ end
75
+
76
+ #
77
+ # Edit a Pulses information
78
+ #
79
+ # @param id [String] The ID of the Pulse
80
+ # @param param [Hash] Parameters to edit
81
+ #
82
+ def edit(id, params)
83
+ uri = "/api/v1/pulses/#{id}"
84
+
85
+ patch(uri, params)
86
+ end
87
+
88
+ #
89
+ # GET Pulses from a user
90
+ #
91
+ # @param username [String] Name of the User to retrieve pulses from
92
+ # @param limit [Integer] Limit results per page to this number
93
+ # @param page [Integer] Return results for this page
94
+ # @return [Array<OTX::Pulse>] Parsed Pulses
95
+ #
96
+ def get_user_pulses(username, limit = 10, page = 1)
97
+ uri = "/api/v1/pulses/user/#{username}"
98
+ params = { limit: limit, page: page }
99
+ results = []
100
+
101
+ json_data = get(uri, params)
102
+
103
+ json_data['results'].each do |pulse|
104
+ results << OTX::Pulse.new(pulse)
105
+ end
106
+
107
+ return results
108
+ end
109
+
110
+ #
111
+ # GET Pulses that share indicators with a Pulse
112
+ #
113
+ # @param id [String] ID of the Pulse to retrieve related Pulses from
114
+ # @param limit [Integer] Limit results per page to this number
115
+ # @param page [Integer] Return results for this page
116
+ # @return [Array<OTX::Pulse>] Parsed Pulses
117
+ #
118
+ def get_related(id, limit = 10, page = 1)
119
+ uri = "/api/v1/pulses/#{id}/related"
120
+ params = { limit: limit, page: page }
121
+ results = []
122
+
123
+ json_data = get(uri, params)
124
+
125
+ json_data['results'].each do |pulse|
126
+ results << OTX::Pulse.new(pulse)
127
+ end
128
+
129
+ return results
130
+ end
131
+
132
+ #
133
+ # GET a Pulses Indicators
134
+ #
135
+ # @param id [String] ID of the Pulse to retrieve Indicators from
136
+ # @param limit [Integer] Limit results per page to this number
137
+ # @param page [Integer] Return results for this page
138
+ # @return [Array<OTX::Pulse>] Parsed Indicators
139
+ #
140
+ def get_indicators(id, limit = 10, page = 1)
141
+ uri = "/api/v1/pulses/#{id}/indicators"
142
+ params = { limit: limit, page: page }
143
+ results = []
144
+
145
+ json_data = get(uri, params)
146
+
147
+ json_data['results'].each do |indicator|
148
+ results << OTX::Indicators.new(indicator)
149
+ end
150
+
151
+ return results
152
+ end
153
+
154
+ #
155
+ # GET list of Pulse Indicator Types
156
+ #
157
+ # @return [Array<OTX::Indicator::IndicatorType>]
158
+ #
159
+ def get_indicator_types
160
+ uri = '/api/v1/pulses/indicators/types'
161
+ types = []
162
+
163
+ json_data = get(uri)
164
+
165
+ json_data['detail'].each do |type|
166
+ types << OTX::Indicator::IndicatorType.new(type)
167
+ end
168
+
169
+ return types
170
+ end
21
171
  end
22
172
  end
@@ -5,13 +5,28 @@ module OTX
5
5
  # associated pulses
6
6
  #
7
7
  class Subscribed < OTX::Base
8
+ def get_subscribed(limit = 10, page = 1, params = {})
9
+ uri = '/api/v1/pulses/subscribed'
10
+ params['limit'] = limit
11
+ params['page'] = page
12
+ results = []
13
+
14
+ json_data = get(uri, params)
15
+
16
+ json_data['results'].each do |pulse|
17
+ results << OTX::Pulse.new(pulse)
18
+ end
19
+
20
+ return results
21
+ end
22
+
8
23
  #
9
24
  # Get all subscribed pulses from the API, get all events in chunks defined by limit
10
25
  #
11
26
  # @param limit [Integer] Size of chunk of data to be Returned (default = 20)
12
27
  # @return [Array] Array of OTX::Pulse records
13
28
  #
14
- def get_all(limit=20)
29
+ def get_all(limit = 20)
15
30
  uri = '/api/v1/pulses/subscribed'
16
31
  params = {limit: limit}
17
32
  pulses = []
@@ -22,7 +37,7 @@ module OTX
22
37
  params = URI::decode_www_form(URI(page).query).to_h unless page.nil?
23
38
 
24
39
  pulses += json_data['results']
25
- end while !page.nil?
40
+ end while page && !json_data['results'].empty?
26
41
 
27
42
  results = []
28
43
  pulses.each do |pulse|
@@ -40,7 +55,7 @@ module OTX
40
55
  # @param limit [Integer] Size of chunk of data to be Returned (default = 20)
41
56
  # @return [Array] Array of OTX::Pulse records
42
57
  #
43
- def get_since(timestamp, limit=20)
58
+ def get_since(timestamp, limit = 20)
44
59
  uri = '/api/v1/pulses/subscribed'
45
60
  params = {limit: limit, modified_since: timestamp}
46
61
  pulses = []
@@ -51,7 +66,7 @@ module OTX
51
66
  params = URI::decode_www_form(URI(page).query).to_h unless page.nil?
52
67
 
53
68
  pulses += json_data['results']
54
- end while !page.nil?
69
+ end while page && !json_data['results'].empty?
55
70
 
56
71
  results = []
57
72
  pulses.each do |pulse|
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module Pulse
4
+ class Author < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module CVE
4
+ class BaseIndicator < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module OTX
2
+ module Indicator
3
+ class CorrelationRule < OTX::Type::Base
4
+ def initialize(attributes={})
5
+ attributes.each do |key, value|
6
+ unless self.respond_to?(key)
7
+ self.class.send(:attr_accessor, key)
8
+ end
9
+
10
+ if key == 'pulse_info'
11
+ send("#{key.downcase}=", OTX::Indicator::CVE::PulseInfo.new(value))
12
+ elsif key == 'base_indicator'
13
+ send("#{key.downcase}=", OTX::Indicator::CVE::BaseIndicator.new(value))
14
+ else
15
+ send("#{key.downcase}=", value)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,36 @@
1
+ module OTX
2
+ module Indicator
3
+ module CVE
4
+ class General < OTX::Type::Base
5
+ #
6
+ # Needs details for attributes
7
+ #
8
+ attr_accessor :indicator, :date_modified, :pulse_info, :references, :base_indicator
9
+
10
+ def initialize(attributes={})
11
+ attributes.each do |key, value|
12
+ _key = key.gsub('-', '_')
13
+
14
+ unless self.respond_to?(key)
15
+ self.class.send(:attr_accessor, key)
16
+ end
17
+
18
+ if _key == 'pulse_info'
19
+ @pulse_info = OTX::Indicator::CVE::PulseInfo.new(value)
20
+ elsif _key == 'base_indicator'
21
+ @base_indicator = OTX::Indicator::CVE::BaseIndicator.new(value)
22
+ elsif _key == 'references'
23
+ @references = []
24
+ value.each do |reference|
25
+ @references << OTX::Indicator::CVE::Reference.new(reference)
26
+ end
27
+ else
28
+ send("#{_key.downcase}=", value)
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ module OTX
2
+ module Indicator
3
+ class FileAnalysis < OTX::Type::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module OTX
2
+ module Indicator
3
+ class IndicatorType < OTX::Type::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module Pulse
4
+ class IndicatorTypeCounts < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class DNS < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class General < OTX::Type::Base
5
+ def initialize(attributes={})
6
+ attributes.each do |key, value|
7
+
8
+ unless self.respond_to?(key)
9
+ self.class.send(:attr_accessor, key)
10
+ end
11
+
12
+ if key == 'pulse_info'
13
+ send("#{key.downcase}=", OTX::Indicator::CVE::PulseInfo.new(value))
14
+ elsif key == 'base_indicator'
15
+ send("#{key.downcase}=", OTX::Indicator::CVE::BaseIndicator.new(value))
16
+ else
17
+ send("#{key.downcase}=", value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class Geo < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class HTTPScan < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class Malware < OTX::Type::Base
5
+ def initialize(attributes={})
6
+ attributes.each do |key, value|
7
+ if key == 'hash'
8
+ self.class.send(:attr_accessor, 'malware_hash')
9
+ send('malware_hash=', value)
10
+ else
11
+ unless self.respond_to?(key)
12
+ self.class.send(:attr_accessor, key)
13
+ end
14
+ send("#{key.downcase}=", value)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class URL < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module IP
4
+ class Whois < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module Pulse
4
+ class Observation < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -29,13 +29,24 @@ module OTX
29
29
 
30
30
  def initialize(attributes={})
31
31
  attributes.each do |key, value|
32
- if key != 'indicators'
33
- send("#{key.downcase}=", value)
34
- else
32
+ # Dynamically Add any missing attributes
33
+ unless self.respond_to?(key)
34
+ self.class.send(:attr_accessor, key)
35
+ end
36
+
37
+ if key == 'indicators'
35
38
  @indicators = []
36
39
  value.each do |indicator|
37
40
  @indicators << OTX::Indicators.new(indicator)
38
41
  end
42
+ elsif key == 'observation'
43
+ @observation = OTX::Indicator::Pulse::Observation.new(value)
44
+ elsif key == 'indicator_type_counts'
45
+ @indicator_type_counts = OTX::Indicator::Pulse::IndicatorTypeCounts.new(value)
46
+ elsif key == 'author'
47
+ @author = OTX::Indicator::Pulse::Author.new(value)
48
+ else
49
+ send("#{key.downcase}=", value)
39
50
  end
40
51
  end
41
52
  end
@@ -0,0 +1,24 @@
1
+ module OTX
2
+ module Indicator
3
+ module CVE
4
+ class PulseInfo < OTX::Type::Base
5
+ def initialize(attributes={})
6
+ attributes.each do |key, value|
7
+ unless self.respond_to?(key)
8
+ self.class.send(:attr_accessor, key)
9
+ end
10
+
11
+ if key != 'pulses'
12
+ send("#{key.downcase}=", value)
13
+ else
14
+ @pulses = []
15
+ value.each do |pulse|
16
+ @pulses << OTX::Pulse.new(pulse)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module OTX
2
+ module Indicator
3
+ module CVE
4
+ class Reference < OTX::Type::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module OTX
2
+ #
3
+ # AlienVault OTX User Record
4
+ #
5
+ # @attr user_id [String] User ID
6
+ # @attr username [String] User name
7
+ # @attr member_since [String] Number of days since User created their account
8
+ # @attr avatar_url [String] URL for Users avatar image
9
+ # @attr pulse_count [Integer] Number of Pulses created
10
+ # @attr accepted_edits_count [Integer] Number of Users edits that have been accepted
11
+ # @attr subscriber_count [Integer] Number of other Users subscribed to this User
12
+ # @attr follower_count [Integer] Number of other Users following this User
13
+ # @attr award_count [Integer] Number of awards this User has received
14
+ # @attr awards [Array<String>] Array of awards this User has received
15
+ #
16
+ class User < OTX::Type::Base
17
+ attr_accessor :user_id, :username, :member_since, :avatar_url, :pulse_count,
18
+ :accepted_edits_count, :subscriber_count, :follower_count, :award_count,
19
+ :awards
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module OTX
2
+ class URL < OTX::Base
3
+ def get_general(url)
4
+ uri = "/api/v1/indicators/url/#{url}/general"
5
+
6
+ json_data = get(uri)
7
+
8
+ general = OTX::Indicator::IP::General.new(json_data)
9
+
10
+ return general
11
+ end
12
+
13
+ def get_url_list(url)
14
+ uri = "/api/v1/indicators/url/#{url}/url_list"
15
+
16
+ page = 0
17
+ url_list = []
18
+ begin
19
+ page += 1
20
+ params = {limit: 20, page: page}
21
+ json_data = get(uri, params)
22
+ has_next = json_data['has_next']
23
+
24
+ url_list += json_data['url_list']
25
+ end while has_next
26
+
27
+ results = []
28
+ url_list.each do |url|
29
+ results << OTX::Indicator::IP::URL.new(url)
30
+ end
31
+
32
+ return results
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,97 @@
1
+ module OTX
2
+ #
3
+ # Search for, subscribe to, unsubscribe from, follow and unfollow users
4
+ #
5
+ class Users < OTX::Base
6
+ #
7
+ # Validate your API Key configuration. If valid, some basic information about the user account corresponding to the API Key supplied will be returned.
8
+ #
9
+ # @return [OTX::User] Parsed User
10
+ #
11
+ def me
12
+ uri = "/api/v1/users/me"
13
+
14
+ json_data = get(uri)
15
+
16
+ user = OTX::User.new(json_data)
17
+
18
+ return user
19
+ end
20
+
21
+ #
22
+ # Search for Users by username
23
+ #
24
+ # @param query [String] Full or partial username to search
25
+ # @param limit [Integer] Limit results per page to this number
26
+ # @param page [Integer] Return results for this page
27
+ # @param sort [Symbol] Sort results by username or pulse_count
28
+ # @return [Array<OTX::User>] Parsed Users
29
+ #
30
+ def search(query, limit = 10, page = 1, sort = :username)
31
+ uri = '/api/v1/search/users'
32
+ params = {
33
+ q: query,
34
+ limit: limit,
35
+ page: page,
36
+ sort: sort == :pulse_count ? 'pulse_count' : 'username'
37
+ }
38
+ results = []
39
+
40
+ json_data = get(uri, params)
41
+
42
+ json_data['results'].each do |user|
43
+ results << OTX::User.new(user)
44
+ end
45
+
46
+ return results
47
+ end
48
+
49
+ #
50
+ # Subscribe to a User
51
+ #
52
+ # @param useranme [String] Username of the User you wish to subscribe to
53
+ #
54
+ def subscribe_to(username)
55
+ action(username, 'subscribe')
56
+ end
57
+
58
+ #
59
+ # Unsubscribe from a User
60
+ #
61
+ # @param useranme [String] Username of the User you wish to unsubscribe from
62
+ #
63
+ def unsubscribe_from(username)
64
+ action(username, 'unsubscribe')
65
+ end
66
+
67
+ #
68
+ # Follow a User
69
+ #
70
+ # @param useranme [String] Username of the User you wish to follow
71
+ #
72
+ def follow(username)
73
+ action(username, 'follow')
74
+ end
75
+
76
+ #
77
+ # Unfollow a User
78
+ #
79
+ # @param useranme [String] Username of the User you wish to unfollow
80
+ #
81
+ def unfollow(username)
82
+ action(username, 'unfollow')
83
+ end
84
+
85
+ #
86
+ # Perform an action on a User
87
+ #
88
+ # @param useranme [String] Username of the User you wish to perform an action on
89
+ # @param action [String] Action you wish to perform on the User
90
+ #
91
+ def action(username, action)
92
+ uri = "/api/v1/users/#{username}/#{action}"
93
+
94
+ post(uri)
95
+ end
96
+ end
97
+ end
@@ -1,4 +1,4 @@
1
1
  module OTX
2
2
  # Library Version Number
3
- VERSION = "0.7.1"
3
+ VERSION = "0.8.0"
4
4
  end