virustotalx 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b93b0c39cdd1dbf4efdeffbe4f9ed6c30892f75a3a73172b1e5eb2db11678334
4
- data.tar.gz: 38be1389296d3bd50edbf0bdb8906b83a2639a681b0b91b7a9fc1df8539a35b4
3
+ metadata.gz: f014d99e8a184fa94a9f2d696209672867c2d437c83bf094b49346078887b077
4
+ data.tar.gz: 0ff81e8a4a61b7283a8d54fe329127d602b07847f8a62ca70f7aa4112b6a6187
5
5
  SHA512:
6
- metadata.gz: 86a227bded77dba22902a4531f09683cfc618c850ae178762f6ba5cd1438dbd546313bcd67f27041af3b562dcb0d1e047b570f160ad5a6db91a773b9e8aa6edc
7
- data.tar.gz: 1b73b35965ee06d99b02fc5674d30ea234f5a64909a2a8a4dfb12cac6c38df8b648ada8c0aaf981338ca3e61accd267a971ddb3883a8eee0fb25f1774b387d4e
6
+ metadata.gz: c957e719c7a2f9be34493128a95369f5a0bd0f0a534570f9466c70af1cec243daba9198b516cc21af576bd3f5d31b01a65dc017cd6a946663c6d9f3009906d04
7
+ data.tar.gz: a0497c176fc774a95193452590226f9887792aed9a42a1e144859b0db99684195c75d1e6ca8eb5de833a00a72b506b86f88bf347f621ea3f84b865c4960ef4e5
data/README.md CHANGED
@@ -39,12 +39,12 @@ api.ip_address.get("1.1.1.1")
39
39
 
40
40
  ## Supported API endpoints
41
41
 
42
- * [VirusTotal API reference](https://developers.virustotal.com/v3.0/reference#overview)
42
+ - [VirusTotal API reference](https://developers.virustotal.com/v3.0/reference#overview)
43
43
 
44
44
  ### Files
45
45
 
46
46
  | HTTP Method | URL | API method |
47
- |-------------|------------------------------------|------------------------------------------------------------|
47
+ | ----------- | ---------------------------------- | ---------------------------------------------------------- |
48
48
  | POST | /files | api.file.upload(filepath) |
49
49
  | GET | /files/upload_url | api.file.upload_url |
50
50
  | GET | /files/{id} | api.file.get(id) |
@@ -62,7 +62,7 @@ api.ip_address.get("1.1.1.1")
62
62
  ### URLs
63
63
 
64
64
  | HTTP Method | URL | API method |
65
- |-------------|-----------------------------|----------------------------------------------------------------|
65
+ | ----------- | --------------------------- | -------------------------------------------------------------- |
66
66
  | POST | /urls | N/A |
67
67
  | GET | /urls/{id} | api.url.get(id) |
68
68
  | POST | /urls/{id}/analyse | api.url.analyse(id) |
@@ -78,7 +78,7 @@ Note: you can use a URL as an id.
78
78
  ### Domains
79
79
 
80
80
  | HTTP Method | URL | API method |
81
- |-------------|----------------------------------|--------------------------------------------------------------|
81
+ | ----------- | -------------------------------- | ------------------------------------------------------------ |
82
82
  | GET | /domains/{domain} | api.domain.get(domain) |
83
83
  | GET | /domains/{domain}/comments | api.domain.comment(domain) |
84
84
  | POST | /domains/{domain}/comments | api.domain.add_comment(domain, text) |
@@ -87,7 +87,7 @@ Note: you can use a URL as an id.
87
87
  ### IP addresses
88
88
 
89
89
  | HTTP Method | URL | API method |
90
- |-------------|-----------------------------------|---------------------------------------------------------------------------------|
90
+ | ----------- | --------------------------------- | ------------------------------------------------------------------------------- |
91
91
  | GET | /ip_addresses/{ip} | api.ip_address.get(ip) |
92
92
  | GET | /ip_addresses/{ip}/comments | api.ip_address.comments(id) |
93
93
  | POST | /ip_addresses/{ip}/comments | api.ip_address.add_comment(id, text) |
@@ -96,12 +96,26 @@ Note: you can use a URL as an id.
96
96
  ### Analyses
97
97
 
98
98
  | HTTP Method | URL | API method |
99
- |-------------|----------------|----------------------|
99
+ | ----------- | -------------- | -------------------- |
100
100
  | GET | /analyses/{id} | api.analysis.get(ip) |
101
101
 
102
102
  ## Graphs
103
103
 
104
- N/A.
104
+ | HTTP Method | URL | API method |
105
+ | ----------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
106
+ | GET | graphs | api.graph.search(filter: nil, limit: nil, cursor: nil, order: nil, attributes: nil) |
107
+ | POST | graphs | api.graph.create(\*\*params) |
108
+ | GET | graphs/{id} | api.graph.get(id) |
109
+ | PATCH | graphs/{id} | api.graph.update(id, \*\*params) |
110
+ | GET | graphs/{id}/relationships/viewers | api.graph.viewers(id, limit: nil, cursor: nil) |
111
+ | POST | graphs/{id}/relationships/viewers | api.graph.add_viewer(id, \*\*params) |
112
+ | GET | graphs/{id}/relationships/viewers/{user_or_group_id} | api.graph.check_viewer(id, user_or_group_id) |
113
+ | DELETE | graphs/{id}/relationships/viewers/{user_or_group_id} | api.graph.delete_viewer(id, user_or_group_id) |
114
+ | GET | graphs/{id}/relationships/editors | api.graph.editors(id, limit: nil, cursor: nil) |
115
+ | POST | graphs/{id}/relationships/editors | api.graph.add_editor(id, \*\*params) |
116
+ | GET | graphs/{id}/relationships/editors/{user_or_group_id} | api.graph.check_editor(id, user_or_group_id) |
117
+ | DELETE | graphs/{id}/relationships/editors/{user_or_group_id} | api.graph.delete_editor(id, user_or_group_id) |
118
+ | GET | graphs/{id}/relationships/{relationship} | api.graph.`relationship`(id) |
105
119
 
106
120
  ## License
107
121
 
data/lib/virustotal.rb CHANGED
@@ -7,11 +7,16 @@ require "virustotal/errors"
7
7
  require "virustotal/api"
8
8
 
9
9
  require "virustotal/clients/base"
10
- require "virustotal/clients/object"
10
+
11
+ require "virustotal/clients/actions/comments"
12
+ require "virustotal/clients/actions/get"
13
+ require "virustotal/clients/actions/relationships"
14
+ require "virustotal/clients/actions/votes"
11
15
 
12
16
  require "virustotal/clients/analysis"
13
17
  require "virustotal/clients/domain"
14
18
  require "virustotal/clients/file"
19
+ require "virustotal/clients/graph"
15
20
  require "virustotal/clients/ip_address"
16
21
  require "virustotal/clients/url"
17
22
 
@@ -1,23 +1,73 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "clients/base"
4
-
5
3
  module VirusTotal
6
4
  class API
7
- attr_reader :analysis
8
- attr_reader :domain
9
- attr_reader :file
10
- attr_reader :ip_address
11
- attr_reader :url
5
+ # @return [String] VirusTotal API key
6
+ attr_reader :key
12
7
 
8
+ #
9
+ # @param [String] key VirusTotal API key
10
+ #
11
+ # @raise [ArgumentError] When given an empty key
12
+ #
13
13
  def initialize(key: ENV["VIRUSTOTAL_API_KEY"])
14
+ @key = key
15
+
14
16
  raise ArgumentError, "No API key has been found or provided! (setup your VIRUSTOTAL_API_KEY environment varialbe)" unless key
17
+ end
18
+
19
+ #
20
+ # Analyses API endpoint client
21
+ #
22
+ # @return [VirusTotal::Client::Analysis]
23
+ #
24
+ def analysis
25
+ @analysis ||= Client::Analysis.new(key: key)
26
+ end
27
+
28
+ #
29
+ # Domains API endpoint client
30
+ #
31
+ # @return [VirusTotal::Client::Domain]
32
+ #
33
+ def domain
34
+ @domain ||= Client::Domain.new(key: key)
35
+ end
36
+
37
+ #
38
+ # Files API endpoint client
39
+ #
40
+ # @return [VirusTotal::Client::File]
41
+ #
42
+ def file
43
+ @file ||= Client::File.new(key: key)
44
+ end
45
+
46
+ #
47
+ # IP addresses API endpoint client
48
+ #
49
+ # @return [VirusTotal::Client::IPAddress]
50
+ #
51
+ def ip_address
52
+ @ip_address ||= Client::IPAddress.new(key: key)
53
+ end
54
+
55
+ #
56
+ # URLs API endpoint client
57
+ #
58
+ # @return [VirusTotal::Client::URL]
59
+ #
60
+ def url
61
+ @url ||= Client::URL.new(key: key)
62
+ end
15
63
 
16
- @analysis = Client::Analysis.new(key: key)
17
- @domain = Client::Domain.new(key: key)
18
- @file = Client::File.new(key: key)
19
- @ip_address = Client::IPAddress.new(key: key)
20
- @url = Client::URL.new(key: key)
64
+ #
65
+ # Graphs API endpoint client
66
+ #
67
+ # @return [VirusTotal::Client::Graph]
68
+ #
69
+ def graph
70
+ @graph ||= Client::Graph.new(key: key)
21
71
  end
22
72
  end
23
73
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VirusTotal
4
+ module Client
5
+ module Action
6
+ module Comments
7
+ #
8
+ # Retrieve comments for an object
9
+ #
10
+ # @param [String] id Object identifier
11
+ #
12
+ # @return [Hash]
13
+ #
14
+ def comments(id)
15
+ id = to_id(id)
16
+ _get("/#{name}/#{id}/comments") { |json| json }
17
+ end
18
+
19
+ #
20
+ # Add a comment to an object
21
+ #
22
+ # @param [String] id Object identifier
23
+ # @param [String] text
24
+ #
25
+ # @return [Hash]
26
+ #
27
+ def add_comment(id, text)
28
+ id = to_id(id)
29
+ params = {
30
+ data: {
31
+ type: "comment",
32
+ attributes: {
33
+ text: text
34
+ }
35
+ }
36
+ }
37
+ _post("/#{name}/#{id}/comments", params) { |json| json }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VirusTotal
4
+ module Client
5
+ module Action
6
+ module Get
7
+ #
8
+ # Retrieve information about an object
9
+ #
10
+ # @param [String] id Object identifier
11
+ #
12
+ # @return [Hash]
13
+ #
14
+ def get(id)
15
+ id = to_id(id)
16
+ _get("/#{name}/#{id}") { |json| json }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VirusTotal
4
+ module Client
5
+ module Action
6
+ module Relationships
7
+ def relationships
8
+ []
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+ if relationships.include?(method)
13
+ id = to_id(args.first)
14
+ params = args.length == 2 ? args[1] : {}
15
+
16
+ _get("/#{name}/#{id}/#{method}", params) { |json| json }
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def respond_to_missing?(method_name, *)
23
+ relationships.include? method_name
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VirusTotal
4
+ module Client
5
+ module Action
6
+ module Votes
7
+ #
8
+ # Retrieve votes for an object
9
+ #
10
+ # @param [String] id Object identifier
11
+ #
12
+ # @return [Hash]
13
+ #
14
+ def votes(id)
15
+ id = to_id(id)
16
+ _get("/#{name}/#{id}/votes") { |json| json }
17
+ end
18
+
19
+ #
20
+ # Add a vote for an object
21
+ #
22
+ # @param [String] id Object identifier
23
+ # @param [String] verdict harmless or malicious
24
+ #
25
+ # @return [Hash]
26
+ #
27
+ def add_vote(id, verdict)
28
+ id = to_id(id)
29
+ params = {
30
+ data: {
31
+ type: "vote",
32
+ attributes: {
33
+ verdict: verdict
34
+ }
35
+ }
36
+ }
37
+ _post("/#{name}/#{id}/votes", params) { |json| json }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,9 +3,7 @@
3
3
  module VirusTotal
4
4
  module Client
5
5
  class Analysis < Base
6
- def get(id)
7
- _get("/analyses/#{id}") { |json| json }
8
- end
6
+ include Action::Get
9
7
  end
10
8
  end
11
9
  end
@@ -11,6 +11,15 @@ module VirusTotal
11
11
  VERSION = "v3"
12
12
  BASE_URL = "https://#{HOST}/api/#{VERSION}"
13
13
 
14
+ CONVERT_TABLE = {
15
+ analysis: "analyses",
16
+ domain: "domains",
17
+ file: "files",
18
+ graph: "graphs",
19
+ ipaddress: "ip_addresses",
20
+ url: "urls",
21
+ }.freeze
22
+
14
23
  attr_reader :key
15
24
 
16
25
  def initialize(key: ENV["VIRUSTOTAL_API_KEY"])
@@ -111,6 +120,32 @@ module VirusTotal
111
120
 
112
121
  request(post, &block)
113
122
  end
123
+
124
+ def _patch(path, params = {}, &block)
125
+ patch = Net::HTTP::Patch.new(url_for(path))
126
+ patch.body = JSON.generate(params) if params
127
+
128
+ request(patch, &block)
129
+ end
130
+
131
+ def _delete(path, params = {}, &block)
132
+ delete = Net::HTTP::Delete.new(url_for(path))
133
+ delete.body = JSON.generate(params) if params
134
+
135
+ request(delete, &block)
136
+ end
137
+
138
+ def to_id(id)
139
+ id
140
+ end
141
+
142
+ def klass
143
+ self.class.to_s.split("::").last.to_s.downcase.to_sym
144
+ end
145
+
146
+ def name
147
+ CONVERT_TABLE.fetch klass
148
+ end
114
149
  end
115
150
  end
116
151
  end
@@ -2,11 +2,15 @@
2
2
 
3
3
  module VirusTotal
4
4
  module Client
5
- class Domain < Object
5
+ class Domain < Base
6
+ include Action::Comments
7
+ include Action::Get
8
+ include Action::Relationships
9
+
6
10
  private
7
11
 
8
12
  def relationships
9
- %w(
13
+ @relationships ||= %w(
10
14
  communicating_files
11
15
  downloaded_files
12
16
  graphs
@@ -2,45 +2,86 @@
2
2
 
3
3
  module VirusTotal
4
4
  module Client
5
- class File < Object
5
+ class File < Base
6
+ include Action::Comments
7
+ include Action::Get
8
+ include Action::Relationships
9
+ include Action::Votes
10
+
11
+ #
12
+ # Upload and analyse a file
13
+ #
14
+ # @see https://developers.virustotal.com/v3.0/reference#files-scan
15
+ #
16
+ # @param [String] path File path to be scanned
17
+ #
18
+ # @return [Hash]
19
+ #
6
20
  def upload(path)
7
21
  name = ::File.basename(path)
8
22
  data = ::File.read(path)
9
23
  _post_with_file("/files", file: data, filename: name) { |json| json }
10
24
  end
11
25
 
26
+ #
27
+ # Get a URL for uploading files larger than 32MB
28
+ #
29
+ # @see https://developers.virustotal.com/v3.0/reference#files-upload-url
30
+ #
31
+ # @return [Hash]
32
+ #
12
33
  def upload_url
13
34
  _get("/files/upload_url") { |json| json }
14
35
  end
15
36
 
37
+ #
38
+ # Reanalyse a file already in VirusTotal
39
+ #
40
+ # @see https://developers.virustotal.com/v3.0/reference#files-analyse
41
+ #
42
+ # @param [String] hash SHA-256, SHA-1 or MD5 identifying the file
43
+ #
44
+ # @return [Hash]
45
+ #
16
46
  def analyse(hash)
17
47
  _post("/files/#{hash}/analyse") { |json| json }
18
48
  end
19
49
 
20
- def votes(hash)
21
- _get("/files/#{hash}/votes") { |json| json }
22
- end
23
-
24
- def add_vote(hash, verdict)
25
- params = {
26
- data: {
27
- type: "vote",
28
- attributes: {
29
- verdict: verdict
30
- }
31
- }
32
- }
33
- _post("/files/#{hash}/votes", params) { |json| json }
34
- end
35
-
50
+ #
51
+ # Get a download URL for a file
52
+ #
53
+ # @see https://developers.virustotal.com/v3.0/reference#files-download-url
54
+ #
55
+ # @param [String] hash SHA-256, SHA-1 or MD5 identifying the file
56
+ #
57
+ # @return [Hash]
58
+ #
36
59
  def download_url(hash)
37
60
  _get("/files/#{hash}/download_url") { |json| json }
38
61
  end
39
62
 
63
+ #
64
+ # Download a file
65
+ #
66
+ # @see https://developers.virustotal.com/v3.0/reference#files-download
67
+ #
68
+ # @param [String] SHA-256, SHA-1 or MD5 identifying the file
69
+ #
70
+ # @return [<Type>] <description>
71
+ #
40
72
  def download(hash)
41
73
  _get("/files/#{hash}/download") { |location| location }
42
74
  end
43
75
 
76
+ #
77
+ # Retrieve objects related to a file
78
+ #
79
+ # @see https://developers.virustotal.com/v3.0/reference#file_behaviours_pcap
80
+ #
81
+ # @param [String] id SHA-256, SHA-1 or MD5 identifying the file
82
+ #
83
+ # @return [Hash]
84
+ #
44
85
  def pcap(id)
45
86
  _get("/file_behaviours/#{id}/pcap") { |raw| raw }
46
87
  end
@@ -48,7 +89,7 @@ module VirusTotal
48
89
  private
49
90
 
50
91
  def relationships
51
- %w(
92
+ @relationships ||= %w(
52
93
  analyses
53
94
  behaviours
54
95
  bundled_files
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VirusTotal
4
+ module Client
5
+ class Graph < Base
6
+ include Action::Get
7
+
8
+ #
9
+ # Return graphs.
10
+ #
11
+ # @see https://developers.virustotal.com/v3.0/reference#graphs
12
+ #
13
+ # @param [String, nil] filter Return the graphs matching the given criteria only
14
+ # @param [Integer, nil] limit Maximum number graphs to retrieve
15
+ # @param [String, nil] cursor Continuation cursor
16
+ # @param [String, nil] order Sort order
17
+ # @param [String, nil] attributes Specific fields to retrieve
18
+ #
19
+ # @return [Hash]
20
+ #
21
+ def search(filter: nil, limit: nil, cursor: nil, order: nil, attributes: nil)
22
+ params = {
23
+ filter: filter,
24
+ limit: limit,
25
+ cursor: cursor,
26
+ order: order,
27
+ attributes: attributes
28
+ }.compact
29
+ _get("/graphs", params) { |json| json }
30
+ end
31
+
32
+ #
33
+ # Create a graph with the given nodes and links.
34
+ #
35
+ # @see https://developers.virustotal.com/v3.0/reference#create-graphs
36
+ #
37
+ # @param [Hash] **params
38
+ #
39
+ # @return [Hash]
40
+ #
41
+ def create(**params)
42
+ _post("/graphs", params) { |json| json }
43
+ end
44
+
45
+ #
46
+ # Update a graph.
47
+ #
48
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-update
49
+ #
50
+ # @param [String] id A 65 char length id which uniquely identify the graph.
51
+ # @param [Hash] **params
52
+ #
53
+ # @return [Hash]
54
+ #
55
+ def update(id, **params)
56
+ _patch("/graphs/#{id}", params) { |json| json }
57
+ end
58
+
59
+ #
60
+ # Retrieve graph viewers.
61
+ #
62
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-viewers
63
+ #
64
+ # @param [String] id A 65 char length id which uniquely identify the graph.
65
+ # @param [String, nil] limit Maximum number of related objects to retrieve
66
+ # @param [Integer, nil] cursor Continuation cursor
67
+ #
68
+ # @return [Hash]
69
+ #
70
+ def viewers(id, limit: nil, cursor: nil)
71
+ params = {
72
+ limit: limit,
73
+ cursor: cursor
74
+ }.compact
75
+ _get("/graphs/#{id}/relationships/viewers", params) { |json| json }
76
+ end
77
+
78
+ #
79
+ # Add a user or group as a graph viewer.
80
+ #
81
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-add-viewer
82
+ #
83
+ # @param [String] id A 65 char length id which uniquely identify the graph.
84
+ # @param [Hash] **params
85
+ #
86
+ # @return [Hash]
87
+ #
88
+ def add_viewer(id, **params)
89
+ _post("/graphs/#{id}/relationships/viewers", params) { |json| json }
90
+ end
91
+
92
+ #
93
+ # Check if a user or group is a graph viewer
94
+ #
95
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-check-viewer
96
+ #
97
+ # @param [String] id A 65 char length id which uniquely identify the graph.
98
+ # @param [String] user_or_group_id user or group ID
99
+ #
100
+ # @return [<Type>] <description>
101
+ #
102
+ def check_viewer(id, user_or_group_id)
103
+ _get("/graphs/#{id}/relationships/viewers/#{user_or_group_id}") { |json| json }
104
+ end
105
+
106
+ #
107
+ # Remove a user or group as viewer of a graph.
108
+ #
109
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-delete-viewer
110
+ #
111
+ # @param [String] id A 65 char length id which uniquely identify the graph.
112
+ # @param [String] user_or_group_id user or group ID
113
+ #
114
+ # @return [<Type>] <description>
115
+ #
116
+ def delete_viewer(id, user_or_group_id)
117
+ _delete("/graphs/#{id}/relationships/viewers/#{user_or_group_id}") { |json| json }
118
+ end
119
+
120
+ #
121
+ # Retrieve graph editors.
122
+ #
123
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-editors
124
+ #
125
+ # @param [String] id A 65 char length id which uniquely identify the graph.
126
+ # @param [String, nil] limit Maximum number of related objects to retrieve
127
+ # @param [Integer, nil] cursor Continuation cursor
128
+ #
129
+ # @return [Hash]
130
+ #
131
+ def editors(id, limit: nil, cursor: nil)
132
+ params = {
133
+ limit: limit,
134
+ cursor: cursor
135
+ }.compact
136
+ _get("/graphs/#{id}/relationships/editors", params) { |json| json }
137
+ end
138
+
139
+ #
140
+ # Add a user or group as a graph editor.
141
+ #
142
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-add-editor
143
+ #
144
+ # @param [String] id A 65 char length id which uniquely identify the graph.
145
+ # @param [Hash] **params
146
+ #
147
+ # @return [Hash]
148
+ #
149
+ def add_editor(id, **params)
150
+ _post("/graphs/#{id}/relationships/editors", params) { |json| json }
151
+ end
152
+
153
+ #
154
+ # Check if a user or group is a graph editor.
155
+ #
156
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-check-editor
157
+ #
158
+ # @param [String] id A 65 char length id which uniquely identify the graph.
159
+ # @param [String] user_or_group_id user or group ID
160
+ #
161
+ # @return [Hash]
162
+ #
163
+ def check_editor(id, user_or_group_id)
164
+ _get("/graphs/#{id}/relationships/editors/#{user_or_group_id}") { |json| json }
165
+ end
166
+
167
+ #
168
+ # Remove a user or group as editor of a graph.
169
+ #
170
+ # @see https://developers.virustotal.com/v3.0/reference#graphs-delete-editor
171
+ #
172
+ # @param [String] id A 65 char length id which uniquely identify the graph.
173
+ # @param [String] user_or_group_id user or group ID
174
+ #
175
+ # @return [Hash]
176
+ #
177
+ def delete_editor(id, user_or_group_id)
178
+ _delete("/graphs/#{id}/relationships/editors/#{user_or_group_id}") { |json| json }
179
+ end
180
+
181
+ private
182
+
183
+ def relationships
184
+ @relationships ||= %w(
185
+ comments
186
+ items
187
+ viewers
188
+ editors
189
+ owner
190
+ group
191
+ ).map(&:to_sym)
192
+ end
193
+ end
194
+ end
195
+ end
@@ -2,11 +2,15 @@
2
2
 
3
3
  module VirusTotal
4
4
  module Client
5
- class IPAddress < Object
5
+ class IPAddress < Base
6
+ include Action::Comments
7
+ include Action::Get
8
+ include Action::Relationships
9
+
6
10
  private
7
11
 
8
12
  def relationships
9
- %w(
13
+ @relationships ||= %w(
10
14
  communicating_files
11
15
  downloaded_files
12
16
  graphs
@@ -4,35 +4,40 @@ require "base64"
4
4
 
5
5
  module VirusTotal
6
6
  module Client
7
- class URL < Object
7
+ class URL < Base
8
+ include Action::Comments
9
+ include Action::Get
10
+ include Action::Relationships
11
+ include Action::Votes
12
+
13
+ #
14
+ # Analyse an URL.
15
+ #
16
+ # @see https://developers.virustotal.com/v3.0/reference#urls-analyse
17
+ #
18
+ # @param [String] url URL identifier
19
+ #
20
+ # @return [Hash]
21
+ #
8
22
  def analyse(url)
9
23
  id = to_id(url)
10
24
  _post("/urls/#{id}/analyse") { |json| json }
11
25
  end
12
26
 
13
- def votes(url)
14
- id = to_id(url)
15
- _get("/urls/#{id}/votes") { |json| json }
16
- end
17
-
27
+ #
28
+ # Domain or IP address for a URL.
29
+ #
30
+ # @see https://developers.virustotal.com/v3.0/reference#urlsidnetwork_location
31
+ #
32
+ # @param [String] url URL identifier
33
+ #
34
+ # @return [Hash]
35
+ #
18
36
  def network_location(url)
19
37
  id = to_id(url)
20
38
  _get("/urls/#{id}/network_location") { |json| json }
21
39
  end
22
40
 
23
- def add_vote(url, verdict)
24
- id = to_id(url)
25
- params = {
26
- data: {
27
- type: "vote",
28
- attributes: {
29
- verdict: verdict
30
- }
31
- }
32
- }
33
- _post("/urls/#{id}/votes", params) { |json| json }
34
- end
35
-
36
41
  private
37
42
 
38
43
  def to_id(url)
@@ -40,7 +45,7 @@ module VirusTotal
40
45
  end
41
46
 
42
47
  def relationships
43
- %w(
48
+ @relationships ||= %w(
44
49
  analyses
45
50
  downloaded_files
46
51
  graphs
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VirusTotal
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
data/virustotalx.gemspec CHANGED
@@ -26,8 +26,8 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.add_development_dependency "bundler", "~> 2.0"
28
28
  spec.add_development_dependency "coveralls", "~> 0.8"
29
- spec.add_development_dependency "rake", "~> 12.3"
30
- spec.add_development_dependency "rspec", "~> 3.8"
29
+ spec.add_development_dependency "rake", "~> 13.0"
30
+ spec.add_development_dependency "rspec", "~> 3.9"
31
31
  spec.add_development_dependency "vcr", "~> 5.0"
32
32
  spec.add_development_dependency "webmock", "~> 3.7"
33
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virustotalx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-26 00:00:00.000000000 Z
11
+ date: 2019-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '12.3'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '12.3'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.8'
61
+ version: '3.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.8'
68
+ version: '3.9'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: vcr
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -112,12 +112,16 @@ files:
112
112
  - bin/setup
113
113
  - lib/virustotal.rb
114
114
  - lib/virustotal/api.rb
115
+ - lib/virustotal/clients/actions/comments.rb
116
+ - lib/virustotal/clients/actions/get.rb
117
+ - lib/virustotal/clients/actions/relationships.rb
118
+ - lib/virustotal/clients/actions/votes.rb
115
119
  - lib/virustotal/clients/analysis.rb
116
120
  - lib/virustotal/clients/base.rb
117
121
  - lib/virustotal/clients/domain.rb
118
122
  - lib/virustotal/clients/file.rb
123
+ - lib/virustotal/clients/graph.rb
119
124
  - lib/virustotal/clients/ip_address.rb
120
- - lib/virustotal/clients/object.rb
121
125
  - lib/virustotal/clients/url.rb
122
126
  - lib/virustotal/errors.rb
123
127
  - lib/virustotal/version.rb
@@ -142,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
146
  - !ruby/object:Gem::Version
143
147
  version: '0'
144
148
  requirements: []
145
- rubygems_version: 3.0.4
149
+ rubygems_version: 3.0.3
146
150
  signing_key:
147
151
  specification_version: 4
148
152
  summary: Yet another VirusTotal API wrapper for Ruby
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module VirusTotal
4
- module Client
5
- class Object < Base
6
- CONVERT_TABLE = {
7
- ipaddress: "ip_addresses",
8
- domain: "domains",
9
- url: "urls",
10
- file: "file"
11
- }.freeze
12
-
13
- def get(id)
14
- id = to_id(id)
15
- _get("/#{name}/#{id}") { |json| json }
16
- end
17
-
18
- def comments(id)
19
- id = to_id(id)
20
- _get("/#{name}/#{id}/comments") { |json| json }
21
- end
22
-
23
- def add_comment(id, text)
24
- id = to_id(id)
25
- params = {
26
- data: {
27
- type: "comment",
28
- attributes: {
29
- text: text
30
- }
31
- }
32
- }
33
- _post("/#{name}/#{id}/comments", params) { |json| json }
34
- end
35
-
36
- def relationships
37
- []
38
- end
39
-
40
- def method_missing(method, *args)
41
- if relationships.include?(method)
42
- id = to_id(args.first)
43
- params = args.length == 2 ? args[1] : {}
44
-
45
- _get("/#{name}/#{id}/#{method}", params) { |json| json }
46
- else
47
- super
48
- end
49
- end
50
-
51
- def respond_to?(sym, *)
52
- return true if relationships.include? sym
53
-
54
- super
55
- end
56
-
57
- private
58
-
59
- def to_id(id)
60
- id
61
- end
62
-
63
- def klass
64
- self.class.to_s.split("::").last.to_s.downcase.to_sym
65
- end
66
-
67
- def name
68
- CONVERT_TABLE.fetch klass
69
- end
70
- end
71
- end
72
- end