otx_ruby 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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