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 +4 -4
- data/README.md +21 -7
- data/lib/virustotal.rb +6 -1
- data/lib/virustotal/api.rb +62 -12
- data/lib/virustotal/clients/actions/comments.rb +42 -0
- data/lib/virustotal/clients/actions/get.rb +21 -0
- data/lib/virustotal/clients/actions/relationships.rb +28 -0
- data/lib/virustotal/clients/actions/votes.rb +42 -0
- data/lib/virustotal/clients/analysis.rb +1 -3
- data/lib/virustotal/clients/base.rb +35 -0
- data/lib/virustotal/clients/domain.rb +6 -2
- data/lib/virustotal/clients/file.rb +59 -18
- data/lib/virustotal/clients/graph.rb +195 -0
- data/lib/virustotal/clients/ip_address.rb +6 -2
- data/lib/virustotal/clients/url.rb +25 -20
- data/lib/virustotal/version.rb +1 -1
- data/virustotalx.gemspec +2 -2
- metadata +12 -8
- data/lib/virustotal/clients/object.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f014d99e8a184fa94a9f2d696209672867c2d437c83bf094b49346078887b077
|
4
|
+
data.tar.gz: 0ff81e8a4a61b7283a8d54fe329127d602b07847f8a62ca70f7aa4112b6a6187
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|
data/lib/virustotal/api.rb
CHANGED
@@ -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
|
-
|
8
|
-
attr_reader :
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
@@ -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 <
|
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 <
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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 <
|
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 <
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
data/lib/virustotal/version.rb
CHANGED
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", "~>
|
30
|
-
spec.add_development_dependency "rspec", "~> 3.
|
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.
|
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-
|
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: '
|
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: '
|
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.
|
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.
|
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.
|
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
|