vt_api 0.1.2.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/.scrutinizer.yml +16 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +44 -1
- data/README.md +1 -1
- data/Rakefile +25 -10
- data/lib/vt_api.rb +3 -21
- data/lib/vt_api/api.rb +2 -0
- data/lib/vt_api/api/config.rb +4 -1
- data/lib/vt_api/api/v2.rb +6 -8
- data/lib/vt_api/api/v2/comments.rb +9 -5
- data/lib/vt_api/api/v2/essentials.rb +13 -0
- data/lib/vt_api/api/v2/file.rb +14 -16
- data/lib/vt_api/api/v2/url.rb +16 -8
- data/lib/vt_api/errors.rb +23 -0
- data/lib/vt_api/internal.rb +3 -1
- data/lib/vt_api/internal/api_provider.rb +27 -18
- data/lib/vt_api/internal/api_version.rb +13 -12
- data/lib/vt_api/internal/endpoint.rb +5 -8
- data/lib/vt_api/internal/versions.rb +3 -1
- data/lib/vt_api/internal/versions/api_v2.rb +43 -58
- data/lib/vt_api/internal/versions/default.rb +3 -2
- data/lib/vt_api/version.rb +3 -1
- data/vt_api.gemspec +6 -4
- metadata +47 -4
- data/.yardopts +0 -1
- data/bin/console +0 -13
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d38c571162ab68a4e9546da48dca0278826a563176aba99a4a6b08bb9fa07f5b
|
4
|
+
data.tar.gz: b96cc897788cbf83b84e37b5ad5822c2ada1dc5d3c6b3e820a4747345822c126
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43e6919c0215b9d988889365d9812e86964613aacd21b056d89cb2351aa6d10881ec15cdebab89b2ab45a0dd8da861e923f4737418ae6b422f655a1fcda9b19a
|
7
|
+
data.tar.gz: 5ac6d587584b22e2a408986aecf9400950fd44112b7d3162d217718069c216fb5d6b27768c62b3fc4b76f8356e5850255b02ae628398978ece63f046d4591553
|
data/.rubocop.yml
ADDED
data/.scrutinizer.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,28 +1,71 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
vt_api (0.1.
|
4
|
+
vt_api (0.1.3)
|
5
5
|
faraday (~> 0.15)
|
6
6
|
mimemagic (~> 0.3)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
+
addressable (2.6.0)
|
12
|
+
public_suffix (>= 2.0.2, < 4.0)
|
13
|
+
crack (0.4.3)
|
14
|
+
safe_yaml (~> 1.0.0)
|
15
|
+
diff-lcs (1.3)
|
11
16
|
faraday (0.15.4)
|
12
17
|
multipart-post (>= 1.2, < 3)
|
18
|
+
hashdiff (0.3.8)
|
13
19
|
mimemagic (0.3.3)
|
14
20
|
multipart-post (2.0.0)
|
21
|
+
mustermann (1.0.3)
|
22
|
+
public_suffix (3.0.3)
|
23
|
+
rack (2.0.6)
|
24
|
+
rack-protection (2.0.5)
|
25
|
+
rack
|
15
26
|
rake (10.5.0)
|
27
|
+
rspec (3.8.0)
|
28
|
+
rspec-core (~> 3.8.0)
|
29
|
+
rspec-expectations (~> 3.8.0)
|
30
|
+
rspec-mocks (~> 3.8.0)
|
31
|
+
rspec-core (3.8.0)
|
32
|
+
rspec-support (~> 3.8.0)
|
33
|
+
rspec-expectations (3.8.2)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.8.0)
|
36
|
+
rspec-mocks (3.8.0)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.8.0)
|
39
|
+
rspec-support (3.8.0)
|
40
|
+
safe_yaml (1.0.5)
|
41
|
+
sinatra (2.0.5)
|
42
|
+
mustermann (~> 1.0)
|
43
|
+
rack (~> 2.0)
|
44
|
+
rack-protection (= 2.0.5)
|
45
|
+
tilt (~> 2.0)
|
46
|
+
tilt (2.0.9)
|
47
|
+
webmock (3.5.1)
|
48
|
+
addressable (>= 2.3.6)
|
49
|
+
crack (>= 0.3.2)
|
50
|
+
hashdiff
|
16
51
|
yard (0.9.18)
|
17
52
|
|
18
53
|
PLATFORMS
|
54
|
+
ruby
|
55
|
+
unknown
|
19
56
|
x64-mingw32
|
20
57
|
|
21
58
|
DEPENDENCIES
|
22
59
|
bundler (~> 2.0)
|
23
60
|
rake (~> 10.0)
|
61
|
+
rspec (~> 3.8)
|
62
|
+
sinatra (~> 2.0)
|
24
63
|
vt_api!
|
64
|
+
webmock (~> 3.5)
|
25
65
|
yard (~> 0.9)
|
26
66
|
|
67
|
+
RUBY VERSION
|
68
|
+
ruby 2.5.1p57
|
69
|
+
|
27
70
|
BUNDLED WITH
|
28
71
|
2.0.1
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ scans = file.scans # => [#<VtApi::ApiV2::File::AvResult ...>, ...]
|
|
42
42
|
|
43
43
|
scan_id = VtApi::ApiV2::File.schedule_scan file: 'foobar.txt' # => "92605f5aa57e20475a893cd63d998ffdafca8b1c6142fca225ea5638a2437fe6-2139190"
|
44
44
|
|
45
|
-
url = VtApi::ApiV2::URL.report resource: 'https://bitbucket.org/
|
45
|
+
url = VtApi::ApiV2::URL.report resource: 'https://bitbucket.org/thedeadferryman/vt_api' # => #<VtApi::ApiV2::URL ...>
|
46
46
|
|
47
47
|
comments = VtApi::ApiV2::Comments.get resource: 'fca0b14b72c426a67f06a771c9e2d67e6883972e' # => [#<VtApi::ApiV2::Comments::Comment ...>, ...]
|
48
48
|
comments = VtApi::ApiV2::Comments.put resource: 'fca0b14b72c426a67f06a771c9e2d67e6883972e', text: 'Lorem ipsum dolor sit amet...' # => true
|
data/Rakefile
CHANGED
@@ -1,10 +1,25 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
YARD_SOURCES = Dir['lib/**/*.rb']
|
6
|
+
YARD_EXTRAS = Dir['*.md']
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new
|
11
|
+
rescue LoadError
|
12
|
+
STDERR.puts 'RSpec not found, skipping testing tasks'
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'yard'
|
17
|
+
YARD::Rake::YardocTask.new do |opts|
|
18
|
+
opts.files = YARD_SOURCES + %w[-] + YARD_EXTRAS
|
19
|
+
opts.options = %w[--verbose --no-private]
|
20
|
+
end
|
21
|
+
rescue LoadError
|
22
|
+
STDERR.puts 'YARDoc not found, skipping doc tasks'
|
23
|
+
end
|
24
|
+
|
25
|
+
task default: %i[spec build]
|
data/lib/vt_api.rb
CHANGED
@@ -1,28 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'vt_api/version'
|
4
|
+
require_relative 'vt_api/errors'
|
2
5
|
require_relative 'vt_api/internal'
|
3
6
|
require_relative 'vt_api/api'
|
4
7
|
|
5
8
|
module VtApi
|
6
9
|
|
7
|
-
# Error is thrown when some of required request params are missing
|
8
|
-
#
|
9
|
-
# @see Endpoint#params_valid
|
10
|
-
# @see ApiProvider#request
|
11
|
-
class MissingParametersError < ArgumentError
|
12
|
-
end
|
13
|
-
|
14
|
-
# Error is thrown when requested method could not be found in interface.
|
15
|
-
#
|
16
|
-
# @see ApiVersion#endpoint?
|
17
|
-
# @see ApiProvider#request
|
18
|
-
class UndefinedMethodError < NoMethodError
|
19
|
-
end
|
20
|
-
|
21
|
-
# Error is thrown when API returns HTTP code marked by interface as error.
|
22
|
-
#
|
23
|
-
# @see ApiVersion#error?
|
24
|
-
# @see ApiVersion#error
|
25
|
-
# @see ApiProvider#request
|
26
|
-
class ApiError < RuntimeError
|
27
|
-
end
|
28
10
|
end
|
data/lib/vt_api/api.rb
CHANGED
data/lib/vt_api/api/config.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ostruct'
|
2
4
|
|
5
|
+
# @author Karl F. Meinkopf
|
3
6
|
module VtApi
|
4
7
|
# Default options for VT API, common for all versions
|
5
8
|
DEFAULT_OPTIONS = OpenStruct.new(
|
@@ -30,4 +33,4 @@ module VtApi
|
|
30
33
|
def self.token=(token)
|
31
34
|
options[:token] = token
|
32
35
|
end
|
33
|
-
end
|
36
|
+
end
|
data/lib/vt_api/api/v2.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'config'
|
4
|
+
|
5
|
+
require_relative 'v2/essentials'
|
2
6
|
require_relative 'v2/file'
|
3
7
|
require_relative 'v2/url'
|
4
8
|
require_relative 'v2/comments'
|
5
9
|
|
6
10
|
module VtApi
|
11
|
+
# VT Public 2.0 API bindings
|
7
12
|
module ApiV2
|
8
|
-
|
9
|
-
# Get ApiProvider singleton configured for VT Public API 2.0.
|
10
|
-
#
|
11
|
-
# @return [ApiProvider]
|
12
|
-
def self.provider
|
13
|
-
@provider ||= ApiProvider.new Versions::API_V2, VtApi.options.adapter
|
14
|
-
end
|
15
13
|
end
|
16
|
-
end
|
14
|
+
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
require_relative 'essentials'
|
5
|
+
|
1
6
|
module VtApi
|
2
7
|
module ApiV2
|
3
8
|
# VT API 2.0 for comments
|
@@ -45,15 +50,14 @@ module VtApi
|
|
45
50
|
resp.response_code == 1
|
46
51
|
end
|
47
52
|
|
48
|
-
private
|
49
|
-
|
50
53
|
def self.parse_comments(api_resp)
|
51
|
-
|
54
|
+
# noinspection RubyResolve
|
55
|
+
if api_resp.response_code.nil? || (api_resp.response_code != 1)
|
52
56
|
[]
|
53
57
|
else
|
54
|
-
api_resp.comments.map {|comment| Comment.new comment.date, comment.text}
|
58
|
+
api_resp.comments.map { |comment| Comment.new comment.date, comment.text }
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
59
|
-
end
|
63
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VtApi
|
4
|
+
# VT Public 2.0 API bindings
|
5
|
+
module ApiV2
|
6
|
+
# Get ApiProvider singleton configured for VT Public API 2.0.
|
7
|
+
#
|
8
|
+
# @return [ApiProvider]
|
9
|
+
def self.provider
|
10
|
+
@provider ||= ApiProvider.new Versions::API_V2, VtApi.options.adapter
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/vt_api/api/v2/file.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'pathname'
|
3
5
|
|
@@ -5,14 +7,12 @@ require 'faraday/upload_io'
|
|
5
7
|
require 'mimemagic'
|
6
8
|
|
7
9
|
require_relative '../config'
|
8
|
-
require_relative '
|
9
|
-
require_relative '../v2'
|
10
|
+
require_relative 'essentials'
|
10
11
|
|
11
12
|
module VtApi
|
12
13
|
module ApiV2
|
13
14
|
# Class that represents VT Public API 2.0 for files.
|
14
15
|
class File
|
15
|
-
|
16
16
|
# Representation of particular AV result on file.
|
17
17
|
class AvResult
|
18
18
|
attr_reader :av_name, :triggered, :version, :threat_name, :update
|
@@ -29,7 +29,7 @@ module VtApi
|
|
29
29
|
|
30
30
|
# Existing ID types
|
31
31
|
# @see #id
|
32
|
-
ID_TYPES = %w
|
32
|
+
ID_TYPES = %w[scan_id resource_id md5 sha1 sha256].freeze
|
33
33
|
|
34
34
|
class << self
|
35
35
|
# @see https://developers.virustotal.com/v2.0/reference#file-report
|
@@ -55,9 +55,7 @@ module VtApi
|
|
55
55
|
# @param [String|Pathname|UploadIO] file
|
56
56
|
# @return [String] Scan ID.
|
57
57
|
def schedule_scan(file:)
|
58
|
-
if file.
|
59
|
-
file = file_to_io file
|
60
|
-
end
|
58
|
+
file = file_to_io file if file.is_a?(String) || file.is_a?(Pathname)
|
61
59
|
|
62
60
|
resp = ApiV2.provider.request 'file.scan', apikey: VtApi.options.token, file: file
|
63
61
|
resp.scan_id
|
@@ -79,10 +77,11 @@ module VtApi
|
|
79
77
|
#
|
80
78
|
# @see #initialize
|
81
79
|
def self.from_response(api_resp)
|
82
|
-
|
80
|
+
# noinspection RubyResolve
|
81
|
+
if api_resp.response_code.nil? || (api_resp.response_code < 1)
|
83
82
|
nil
|
84
83
|
else
|
85
|
-
report =
|
84
|
+
report = new api_resp
|
86
85
|
|
87
86
|
report
|
88
87
|
end
|
@@ -91,7 +90,8 @@ module VtApi
|
|
91
90
|
attr_reader :scan_date, :permalink, :scans, :scan_count, :trigger_count
|
92
91
|
|
93
92
|
# Initializes new object from VT API response.
|
94
|
-
# @note Direct creation of object cas cause errors since it doesn't contain any validity checks.
|
93
|
+
# @note Direct creation of object cas cause errors since it doesn't contain any validity checks.
|
94
|
+
# Use predefined API method bindings instead.
|
95
95
|
#
|
96
96
|
# @see .report
|
97
97
|
# @see .schedule_scan
|
@@ -117,9 +117,7 @@ module VtApi
|
|
117
117
|
# @param [Symbol|String] type
|
118
118
|
# @return [String] ID string of specified type.
|
119
119
|
def id(type = :id)
|
120
|
-
unless ID_TYPES.include? type.to_sym
|
121
|
-
raise ArgumentError, "There is no such id type (#{type}) in VT API 2.0"
|
122
|
-
end
|
120
|
+
raise ArgumentError, "There is no such id type (#{type}) in VT API 2.0" unless ID_TYPES.include? type.to_sym
|
123
121
|
|
124
122
|
@ids[type.to_sym]
|
125
123
|
end
|
@@ -128,13 +126,13 @@ module VtApi
|
|
128
126
|
|
129
127
|
# noinspection RubyResolve
|
130
128
|
def load_ids!(api_resp)
|
131
|
-
@ids = OpenStruct.new
|
129
|
+
@ids = OpenStruct.new(
|
132
130
|
scan_id: api_resp.scan_id,
|
133
131
|
md5: api_resp.md5,
|
134
132
|
sha1: api_resp.sha1,
|
135
133
|
sha256: api_resp.sha256,
|
136
134
|
resource_id: api_resp.resource
|
137
|
-
|
135
|
+
)
|
138
136
|
end
|
139
137
|
|
140
138
|
def load_meta!(api_resp)
|
@@ -153,4 +151,4 @@ module VtApi
|
|
153
151
|
end
|
154
152
|
end
|
155
153
|
end
|
156
|
-
end
|
154
|
+
end
|
data/lib/vt_api/api/v2/url.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../config'
|
4
|
+
require_relative 'essentials'
|
5
|
+
|
1
6
|
module VtApi
|
2
7
|
module ApiV2
|
3
8
|
# Class that represents URL scan report.
|
4
9
|
class URL
|
5
10
|
class << self
|
6
|
-
|
7
11
|
# @see https://developers.virustotal.com/v2.0/reference#url-report
|
8
12
|
#
|
9
13
|
# @param [String] resource
|
10
|
-
# @param [Boolean] scan
|
14
|
+
# @param [Boolean] scan Schedule URL scan if it is not present in system.
|
11
15
|
# @return [URL] URL report object is present, <code>nil</code> otherwise.
|
12
16
|
def report(resource:, scan: false)
|
13
|
-
resp = ApiV2.provider.request 'url.report',
|
17
|
+
resp = ApiV2.provider.request 'url.report',
|
18
|
+
apikey: VtApi.options.token,
|
19
|
+
resource: resource,
|
20
|
+
schedule_scan: (scan ? 1 : 0)
|
14
21
|
pp resp
|
15
22
|
from_response resp
|
16
23
|
end
|
@@ -23,17 +30,17 @@ module VtApi
|
|
23
30
|
resp = ApiV2.provider.request 'url.report', apikey: VtApi.options.token, url: url
|
24
31
|
resp.scan_id
|
25
32
|
end
|
26
|
-
|
27
33
|
end
|
28
34
|
|
29
35
|
# Shorthand for #initialize.
|
30
36
|
#
|
31
37
|
# @see #initialize
|
32
38
|
def self.from_response(api_resp)
|
33
|
-
|
39
|
+
# noinspection RubyResolve
|
40
|
+
if api_resp.response_code.nil? || (api_resp.response_code < 1)
|
34
41
|
nil
|
35
42
|
else
|
36
|
-
report =
|
43
|
+
report = new api_resp
|
37
44
|
report
|
38
45
|
end
|
39
46
|
end
|
@@ -41,7 +48,8 @@ module VtApi
|
|
41
48
|
attr_reader :id, :url, :scan_date, :permalink, :filescan_id
|
42
49
|
|
43
50
|
# Initializes new object from VT API response.
|
44
|
-
# @note Direct creation of object cas cause errors since it doesn't contain any validity checks.
|
51
|
+
# @note Direct creation of object cas cause errors since it doesn't contain any validity checks.
|
52
|
+
# Use predefined API method bindings instead.
|
45
53
|
#
|
46
54
|
# @see .report
|
47
55
|
# @see .schedule_scan
|
@@ -75,4 +83,4 @@ module VtApi
|
|
75
83
|
end
|
76
84
|
end
|
77
85
|
end
|
78
|
-
end
|
86
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VtApi
|
2
|
+
# Error is thrown when some of required request params are missing
|
3
|
+
#
|
4
|
+
# @see Endpoint#params_valid
|
5
|
+
# @see ApiProvider#request
|
6
|
+
class MissingParametersError < ArgumentError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Error is thrown when requested method could not be found in interface.
|
10
|
+
#
|
11
|
+
# @see ApiVersion#endpoint?
|
12
|
+
# @see ApiProvider#request
|
13
|
+
class UndefinedMethodError < NoMethodError
|
14
|
+
end
|
15
|
+
|
16
|
+
# Error is thrown when API returns HTTP code marked by interface as error.
|
17
|
+
#
|
18
|
+
# @see ApiVersion#error?
|
19
|
+
# @see ApiVersion#error
|
20
|
+
# @see ApiProvider#request
|
21
|
+
class ApiError < RuntimeError
|
22
|
+
end
|
23
|
+
end
|
data/lib/vt_api/internal.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
5
|
require 'json'
|
4
6
|
require 'ostruct'
|
5
7
|
|
6
8
|
require_relative 'versions/default'
|
7
|
-
require_relative '
|
9
|
+
require_relative '../errors'
|
8
10
|
|
9
11
|
module VtApi
|
10
|
-
# API
|
12
|
+
# API interaction class.
|
11
13
|
#
|
12
14
|
# Uses [Faraday] for HTTP interaction.
|
13
15
|
class ApiProvider
|
14
|
-
|
15
16
|
# Create new ApiProvider.
|
16
17
|
#
|
17
18
|
# @param [ApiVersion] api_version API interface to use.
|
18
19
|
# @param [Object] adapter Faraday HTTP adapter.
|
19
20
|
# @return [Object]
|
20
21
|
def initialize(api_version = Versions::DEFAULT, adapter = :net_http)
|
21
|
-
unless api_version.
|
22
|
-
raise ArgumentError,
|
22
|
+
unless api_version.is_a? ApiVersion
|
23
|
+
raise ArgumentError,
|
24
|
+
"Invalid API interface supplied! Must be subclass of 'ApiVersion', got #{api_version.class} instead"
|
23
25
|
end
|
24
26
|
|
25
27
|
@api = api_version
|
@@ -42,24 +44,31 @@ module VtApi
|
|
42
44
|
# @param [Hash] params
|
43
45
|
# @return [OpenStruct] Method result object.
|
44
46
|
def request(method_name, params = {})
|
45
|
-
|
46
|
-
raise UndefinedMethodError, "Endpoint '#{method_name}' not found in '#{@api.version}' API interface."
|
47
|
-
end
|
48
|
-
|
49
|
-
endpoint = @api.endpoint method_name
|
50
|
-
|
51
|
-
unless endpoint.params_valid? (params)
|
52
|
-
raise MissingParametersError, "Missed parameters #{endpoint.missing_params(params).to_s} required by endpoint '#{method_name}'."
|
53
|
-
end
|
47
|
+
endpoint = endpoint(method_name, params)
|
54
48
|
|
55
49
|
result = @connection.public_send(endpoint.method, endpoint.uri, params, {})
|
56
50
|
|
57
|
-
if @api.error? result.status
|
58
|
-
raise ApiError, "#{@api.version} error: #{@api.error(result.status)}"
|
59
|
-
end
|
51
|
+
raise ApiError, "#{@api.version} error: #{@api.error(result.status)}" if @api.error? result.status
|
60
52
|
|
61
53
|
# noinspection RubyResolve
|
62
54
|
JSON.parse result.body, object_class: OpenStruct
|
63
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def endpoint(method_name, params)
|
60
|
+
unless @api.endpoint? method_name
|
61
|
+
raise UndefinedMethodError,
|
62
|
+
"Endpoint '#{method_name}' not found in '#{@api.version}' API interface."
|
63
|
+
end
|
64
|
+
|
65
|
+
endpoint = @api.endpoint method_name
|
66
|
+
|
67
|
+
unless endpoint.params_valid? params
|
68
|
+
raise MissingParametersError,
|
69
|
+
"Missed parameters #{endpoint.missing_params(params)} required by endpoint '#{method_name}'."
|
70
|
+
end
|
71
|
+
endpoint
|
72
|
+
end
|
64
73
|
end
|
65
|
-
end
|
74
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module VtApi
|
3
4
|
# @abstract Base class for API interfaces.
|
4
5
|
class ApiVersion
|
5
6
|
# Get API base URL.
|
@@ -10,42 +11,42 @@ module VtApi
|
|
10
11
|
end
|
11
12
|
|
12
13
|
# API interface name/version.
|
13
|
-
#
|
14
|
+
#
|
14
15
|
# @return [String]
|
15
16
|
def version
|
16
17
|
nil
|
17
18
|
end
|
18
19
|
|
19
20
|
# Get API HTTP-code description.
|
20
|
-
#
|
21
|
-
# @param [Integer]
|
21
|
+
#
|
22
|
+
# @param [Integer] _http_code
|
22
23
|
# @return [String] Error description.
|
23
|
-
def error(
|
24
|
+
def error(_http_code)
|
24
25
|
nil
|
25
26
|
end
|
26
27
|
|
27
28
|
# Check whether API HTTP-code means error.
|
28
29
|
#
|
29
|
-
# @param [Integer]
|
30
|
+
# @param [Integer] _http_code
|
30
31
|
# @return [Boolean] Error description.
|
31
|
-
def error?(
|
32
|
+
def error?(_http_code)
|
32
33
|
false
|
33
34
|
end
|
34
35
|
|
35
36
|
# Get API method endpoint interface.
|
36
37
|
#
|
37
|
-
# @param [String]
|
38
|
+
# @param [String] _method API method name to be called.
|
38
39
|
# @return [VtApi::Endpoint]
|
39
|
-
def endpoint(
|
40
|
+
def endpoint(_method)
|
40
41
|
nil
|
41
42
|
end
|
42
43
|
|
43
44
|
# Check whether given method is defined in interface.
|
44
45
|
#
|
45
|
-
# @param [String]
|
46
|
+
# @param [String] _method Method name.
|
46
47
|
# @return [Boolean]
|
47
|
-
def endpoint?(
|
48
|
+
def endpoint?(_method)
|
48
49
|
false
|
49
50
|
end
|
50
51
|
end
|
51
|
-
end
|
52
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday/connection'
|
2
4
|
|
3
5
|
module VtApi
|
@@ -23,16 +25,13 @@ module VtApi
|
|
23
25
|
@params = params
|
24
26
|
end
|
25
27
|
|
26
|
-
|
27
28
|
# Check whether given parameters match endpoint interface.
|
28
29
|
#
|
29
30
|
# @param [Hash] passed_params
|
30
31
|
# @return [Boolean]
|
31
32
|
def params_valid?(passed_params)
|
32
33
|
@params.each do |param, required|
|
33
|
-
if required
|
34
|
-
return false
|
35
|
-
end
|
34
|
+
return false if required && passed_params[param].nil?
|
36
35
|
end
|
37
36
|
|
38
37
|
true
|
@@ -46,9 +45,7 @@ module VtApi
|
|
46
45
|
missing = []
|
47
46
|
|
48
47
|
@params.each do |param, required|
|
49
|
-
if required
|
50
|
-
missing << param
|
51
|
-
end
|
48
|
+
missing << param if required && passed_params[param].nil?
|
52
49
|
end
|
53
50
|
|
54
51
|
missing
|
@@ -66,4 +63,4 @@ module VtApi
|
|
66
63
|
uri.gsub %r{([^:])[\/]+}, '\1/'
|
67
64
|
end
|
68
65
|
end
|
69
|
-
end
|
66
|
+
end
|
@@ -1,73 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../api_version'
|
2
4
|
require_relative '../endpoint'
|
3
5
|
|
4
6
|
module VtApi
|
5
7
|
module Versions
|
6
|
-
|
7
8
|
# VirusTotal Public API 2.0 singleton interface.
|
8
9
|
# Describes all available API methods (endpoints).
|
9
10
|
class ApiV2 < ApiVersion
|
10
|
-
|
11
11
|
# Root URI for all endpoints.
|
12
12
|
BASE_URI = 'https://virustotal.com/vtapi/v2/'
|
13
13
|
|
14
14
|
# VirusTotal Public API v2.0 interface description.
|
15
15
|
ENDPOINTS = {
|
16
|
-
'file.report': Endpoint.new('file/report', :get,
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
resource: true,
|
48
|
-
before: false
|
49
|
-
}),
|
50
|
-
'comments.put': Endpoint.new('comments/put', :post, {
|
51
|
-
apikey: true,
|
52
|
-
resource: true,
|
53
|
-
comment: true
|
54
|
-
}),
|
55
|
-
}
|
16
|
+
'file.report': Endpoint.new('file/report', :get,
|
17
|
+
apikey: true,
|
18
|
+
resource: true),
|
19
|
+
'file.scan': Endpoint.new('file/scan', :post,
|
20
|
+
apikey: true,
|
21
|
+
file: true),
|
22
|
+
'file.rescan': Endpoint.new('file/rescan', :post,
|
23
|
+
apikey: true,
|
24
|
+
resource: true),
|
25
|
+
'url.report': Endpoint.new('url/report', :get,
|
26
|
+
apikey: true,
|
27
|
+
resource: true,
|
28
|
+
schedule_scan: false),
|
29
|
+
'url.scan': Endpoint.new('url/scan', :post,
|
30
|
+
apikey: true,
|
31
|
+
url: true),
|
32
|
+
'domain.report': Endpoint.new('domain/report', :get,
|
33
|
+
apikey: true,
|
34
|
+
domain: true),
|
35
|
+
'ip-address.report': Endpoint.new('ip-address/report', :get,
|
36
|
+
apikey: true,
|
37
|
+
domain: true),
|
38
|
+
'comments.get': Endpoint.new('comments/get', :get,
|
39
|
+
apikey: true,
|
40
|
+
resource: true,
|
41
|
+
before: false),
|
42
|
+
'comments.put': Endpoint.new('comments/put', :post,
|
43
|
+
apikey: true,
|
44
|
+
resource: true,
|
45
|
+
comment: true)
|
46
|
+
}.freeze
|
56
47
|
|
57
48
|
# List of possible HTTP error codes with descriptions
|
58
49
|
ERRORS = {
|
59
|
-
204 =>
|
60
|
-
400 =>
|
61
|
-
403 =>
|
62
|
-
404 =>
|
63
|
-
}
|
50
|
+
204 => 'Request rate limit exceeded.',
|
51
|
+
400 => 'Invalid arguments.',
|
52
|
+
403 => 'Access denied.',
|
53
|
+
404 => 'Endpoint not found.'
|
54
|
+
}.freeze
|
64
55
|
|
65
56
|
class << self
|
66
57
|
# Get interface instance.
|
67
58
|
#
|
68
59
|
# @return [VtApi::Versions::ApiV2]
|
69
60
|
def instance
|
70
|
-
@instance ||=
|
61
|
+
@instance ||= new
|
71
62
|
end
|
72
63
|
end
|
73
64
|
|
@@ -84,7 +75,7 @@ module VtApi
|
|
84
75
|
# @param [String] method Method name.
|
85
76
|
# @return [Boolean]
|
86
77
|
def endpoint?(method)
|
87
|
-
|
78
|
+
!endpoint(method).nil?
|
88
79
|
end
|
89
80
|
|
90
81
|
# Get API HTTP-code description.
|
@@ -100,10 +91,10 @@ module VtApi
|
|
100
91
|
# @param [Integer] http_code
|
101
92
|
# @return [Boolean] Error description.
|
102
93
|
def error?(http_code)
|
103
|
-
|
94
|
+
!error(http_code).nil?
|
104
95
|
end
|
105
96
|
|
106
|
-
#
|
97
|
+
# API base URL.
|
107
98
|
#
|
108
99
|
# @return [String]
|
109
100
|
def base_url
|
@@ -116,15 +107,9 @@ module VtApi
|
|
116
107
|
def version
|
117
108
|
'VTAPI-2.0'
|
118
109
|
end
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
# Locked constructor.
|
123
|
-
def initialize
|
124
|
-
end
|
125
110
|
end
|
126
111
|
|
127
112
|
# Shorthand for <code>ApiV2.instance</code>
|
128
113
|
API_V2 = ApiV2.instance
|
129
114
|
end
|
130
|
-
end
|
115
|
+
end
|
data/lib/vt_api/version.rb
CHANGED
data/vt_api.gemspec
CHANGED
@@ -26,20 +26,22 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.files = []
|
27
27
|
|
28
28
|
Dir.chdir(File.expand_path('..', __FILE__)) do
|
29
|
-
spec.files += `git ls-files -z`.split(0.chr).reject {|f| f.match(%r{^(test|spec|features)/})}
|
29
|
+
spec.files += `git ls-files -z`.split(0.chr).reject { |f| f.match(%r{^(test|spec|features)/}) }
|
30
30
|
end
|
31
31
|
|
32
32
|
|
33
33
|
spec.bindir = 'exe'
|
34
|
-
spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f)}
|
34
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
35
35
|
spec.require_paths = ['lib']
|
36
36
|
|
37
37
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
38
38
|
spec.add_development_dependency 'rake', '~> 10.0'
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.8'
|
40
|
+
spec.add_development_dependency 'sinatra', '~> 2.0'
|
41
|
+
spec.add_development_dependency 'webmock', '~> 3.5'
|
39
42
|
spec.add_development_dependency 'yard', '~> 0.9'
|
40
|
-
# spec.add_development_dependency 'rspec', '~> 3.8'
|
41
43
|
# spec.add_development_dependency 'pry', '~> 0.12'
|
42
|
-
|
44
|
+
|
43
45
|
spec.add_dependency 'faraday', '~> 0.15'
|
44
46
|
spec.add_dependency 'mimemagic', '~> 0.3'
|
45
47
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vt_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl 'Charon' Meinkopf
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sinatra
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.5'
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: yard
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,22 +130,23 @@ extensions: []
|
|
88
130
|
extra_rdoc_files: []
|
89
131
|
files:
|
90
132
|
- ".gitignore"
|
133
|
+
- ".rubocop.yml"
|
134
|
+
- ".scrutinizer.yml"
|
91
135
|
- ".travis.yml"
|
92
|
-
- ".yardopts"
|
93
136
|
- Gemfile
|
94
137
|
- Gemfile.lock
|
95
138
|
- LICENSE.md
|
96
139
|
- README.md
|
97
140
|
- Rakefile
|
98
|
-
- bin/console
|
99
|
-
- bin/setup
|
100
141
|
- lib/vt_api.rb
|
101
142
|
- lib/vt_api/api.rb
|
102
143
|
- lib/vt_api/api/config.rb
|
103
144
|
- lib/vt_api/api/v2.rb
|
104
145
|
- lib/vt_api/api/v2/comments.rb
|
146
|
+
- lib/vt_api/api/v2/essentials.rb
|
105
147
|
- lib/vt_api/api/v2/file.rb
|
106
148
|
- lib/vt_api/api/v2/url.rb
|
149
|
+
- lib/vt_api/errors.rb
|
107
150
|
- lib/vt_api/internal.rb
|
108
151
|
- lib/vt_api/internal/api_provider.rb
|
109
152
|
- lib/vt_api/internal/api_version.rb
|
data/.yardopts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--verbose --no-private lib/**/*.rb - README.md LICENSE.md
|
data/bin/console
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "vt_api"
|
5
|
-
|
6
|
-
VtApi.token = 'fe2b8030e62c7d2e3a2ce7450159612fd3bf0419e0ffbdeea3e06e80d51a01af'
|
7
|
-
|
8
|
-
include VtApi
|
9
|
-
|
10
|
-
ApiV2::File.report resource: '13166fc9de263ee2c676430ae88e65040e10761c90e79347a2684476bc60e622'
|
11
|
-
|
12
|
-
# require "pry"
|
13
|
-
# Pry.start
|