virustotal_api 0.4.1 → 0.5.4
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/.github/workflows/ruby.yml +26 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +12 -5
- data/CHANGELOG.md +27 -2
- data/README.md +94 -56
- data/lib/virustotal_api.rb +7 -7
- data/lib/virustotal_api/analysis.rb +16 -0
- data/lib/virustotal_api/base.rb +41 -10
- data/lib/virustotal_api/domain.rb +18 -0
- data/lib/virustotal_api/exceptions.rb +3 -0
- data/lib/virustotal_api/file.rb +48 -0
- data/lib/virustotal_api/group.rb +18 -0
- data/lib/virustotal_api/ip.rb +18 -0
- data/lib/virustotal_api/uri.rb +2 -1
- data/lib/virustotal_api/url.rb +38 -0
- data/lib/virustotal_api/user.rb +18 -0
- data/lib/virustotal_api/version.rb +2 -1
- data/test/analysis_test.rb +26 -0
- data/test/base_test.rb +18 -23
- data/test/domain_test.rb +27 -0
- data/test/exceptions_test.rb +22 -0
- data/test/file_test.rb +63 -0
- data/test/fixtures/analysis.yml +544 -0
- data/test/fixtures/domain.yml +830 -0
- data/test/fixtures/domain_bad_request.yml +52 -0
- data/test/fixtures/file_analyse.yml +52 -0
- data/test/fixtures/file_find.yml +853 -0
- data/test/fixtures/file_not_found.yml +52 -0
- data/test/fixtures/file_rate_limit.yml +52 -0
- data/test/fixtures/file_unauthorized.yml +51 -0
- data/test/fixtures/file_upload.yml +54 -0
- data/test/fixtures/group_find.yml +216 -0
- data/test/fixtures/ip.yml +716 -0
- data/test/fixtures/unscanned_url_find.yml +44 -0
- data/test/fixtures/url_analyse.yml +52 -0
- data/test/fixtures/url_find.yml +599 -0
- data/test/fixtures/user_find.yml +213 -0
- data/test/group_test.rb +27 -0
- data/test/{ip_report_test.rb → ip_test.rb} +6 -4
- data/test/uri_test.rb +1 -1
- data/test/url_test.rb +47 -0
- data/test/user_test.rb +26 -0
- data/test/version_test.rb +1 -1
- data/virustotal_api.gemspec +10 -8
- metadata +102 -71
- data/.circleci/config.yml +0 -23
- data/.github/workflows/gem_publish.yml +0 -38
- data/lib/virustotal_api/domain_report.rb +0 -36
- data/lib/virustotal_api/file_report.rb +0 -37
- data/lib/virustotal_api/file_rescan.rb +0 -36
- data/lib/virustotal_api/file_scan.rb +0 -38
- data/lib/virustotal_api/ip_report.rb +0 -36
- data/lib/virustotal_api/url_report.rb +0 -41
- data/lib/virustotal_api/url_scan.rb +0 -36
- data/test/domain_report_test.rb +0 -32
- data/test/file_report_test.rb +0 -36
- data/test/file_rescan_test.rb +0 -32
- data/test/file_scan_test.rb +0 -30
- data/test/fixtures/domain_report.yml +0 -311
- data/test/fixtures/ip_report.yml +0 -1323
- data/test/fixtures/queue_unscanned_url_report.yml +0 -46
- data/test/fixtures/report.yml +0 -110
- data/test/fixtures/report_not_found.yml +0 -42
- data/test/fixtures/request_forbidden.yml +0 -38
- data/test/fixtures/rescan.yml +0 -47
- data/test/fixtures/scan.yml +0 -49
- data/test/fixtures/unscanned_url_report.yml +0 -43
- data/test/fixtures/url_report.yml +0 -95
- data/test/fixtures/url_scan.yml +0 -48
- data/test/url_report_test.rb +0 -57
- data/test/url_scan_test.rb +0 -30
data/.circleci/config.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
version: 2
|
2
|
-
jobs:
|
3
|
-
test:
|
4
|
-
docker:
|
5
|
-
- image: circleci/ruby:2.5.3-stretch
|
6
|
-
steps:
|
7
|
-
- checkout
|
8
|
-
- run:
|
9
|
-
name: Setup
|
10
|
-
command: |
|
11
|
-
gem update bundler
|
12
|
-
bundle install
|
13
|
-
- run:
|
14
|
-
name: Rubocop
|
15
|
-
command: bundle exec rake rubocop
|
16
|
-
- run:
|
17
|
-
name: Run Tests
|
18
|
-
command: bundle exec rake test
|
19
|
-
workflows:
|
20
|
-
version: 2
|
21
|
-
test:
|
22
|
-
jobs:
|
23
|
-
- test
|
@@ -1,38 +0,0 @@
|
|
1
|
-
name: Ruby Gem
|
2
|
-
|
3
|
-
on: release
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
name: Build + Publish
|
8
|
-
runs-on: ubuntu-latest
|
9
|
-
|
10
|
-
steps:
|
11
|
-
- uses: actions/checkout@master
|
12
|
-
- name: Set up Ruby 2.6
|
13
|
-
uses: actions/setup-ruby@v1
|
14
|
-
with:
|
15
|
-
version: 2.6.x
|
16
|
-
|
17
|
-
- name: Publish to GPR
|
18
|
-
run: |
|
19
|
-
mkdir -p $HOME/.gem
|
20
|
-
touch $HOME/.gem/credentials
|
21
|
-
chmod 0600 $HOME/.gem/credentials
|
22
|
-
printf -- "---\n:github: Bearer ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
23
|
-
gem build *.gemspec
|
24
|
-
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
25
|
-
env:
|
26
|
-
GEM_HOST_API_KEY: ${{secrets.GITHUB_TOKEN}}
|
27
|
-
OWNER: username
|
28
|
-
|
29
|
-
- name: Publish to RubyGems
|
30
|
-
run: |
|
31
|
-
mkdir -p $HOME/.gem
|
32
|
-
touch $HOME/.gem/credentials
|
33
|
-
chmod 0600 $HOME/.gem/credentials
|
34
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
35
|
-
gem build *.gemspec
|
36
|
-
gem push *.gem
|
37
|
-
env:
|
38
|
-
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class DomainReport < Base
|
7
|
-
attr_reader :report
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
end
|
12
|
-
|
13
|
-
# @param [String] domain
|
14
|
-
# @param [String] api_key for virustotal
|
15
|
-
# @return [VirustotalAPI::IPReport] Report Search Result
|
16
|
-
def self.find(domain, api_key)
|
17
|
-
response = RestClient.get(
|
18
|
-
api_uri + '/domain/report',
|
19
|
-
{ params: params(domain, api_key) }
|
20
|
-
)
|
21
|
-
report = parse(response)
|
22
|
-
|
23
|
-
new(report)
|
24
|
-
end
|
25
|
-
|
26
|
-
# @param [String] domain
|
27
|
-
# @param [String] api_key virustotal
|
28
|
-
# @return [Hash] params for GET Request
|
29
|
-
def self.params(domain, api_key)
|
30
|
-
{
|
31
|
-
domain: domain,
|
32
|
-
apikey: api_key
|
33
|
-
}
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class FileReport < Base
|
7
|
-
attr_reader :report, :report_url
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
@report_url = report.fetch('permalink') { nil }
|
12
|
-
end
|
13
|
-
|
14
|
-
# @param [String] resource file as a md5/sha1/sha256 hash
|
15
|
-
# @param [String] api_key for virustotal
|
16
|
-
# @return [VirustotalAPI::FileReport] Report Search Result
|
17
|
-
def self.find(resource, api_key)
|
18
|
-
response = RestClient.post(
|
19
|
-
api_uri + '/file/report',
|
20
|
-
params(resource, api_key)
|
21
|
-
)
|
22
|
-
report = parse(response)
|
23
|
-
|
24
|
-
new(report)
|
25
|
-
end
|
26
|
-
|
27
|
-
# @param [String] resource file as a md5/sha1/sha256 hash
|
28
|
-
# @param [String] api_key for virustotal
|
29
|
-
# @return [Hash] params for POST Request
|
30
|
-
def self.params(resource, api_key)
|
31
|
-
{
|
32
|
-
resource: resource,
|
33
|
-
apikey: api_key
|
34
|
-
}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class FileRescan < Base
|
7
|
-
attr_reader :report, :rescan_id
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
@rescan_id = @report.fetch('scan_id') { nil }
|
12
|
-
end
|
13
|
-
|
14
|
-
# @param [String] resource file as a md5/sha1/sha256 hash
|
15
|
-
# @param [String] api_key for virustotal
|
16
|
-
# @return [VirustotalAPI::FileRescan] Report
|
17
|
-
def self.rescan(resource, api_key)
|
18
|
-
response = RestClient.post(
|
19
|
-
api_uri + '/file/rescan',
|
20
|
-
apikey: api_key,
|
21
|
-
resource: resource
|
22
|
-
)
|
23
|
-
report = parse(response)
|
24
|
-
|
25
|
-
new(report)
|
26
|
-
end
|
27
|
-
|
28
|
-
# @return [Boolean] if file was queued
|
29
|
-
# 0 => not_present, 1 => exists, -2 => queued_for_analysis
|
30
|
-
def queued_for_analysis?
|
31
|
-
response_code = @report.fetch('response_code') { nil }
|
32
|
-
|
33
|
-
response_code == -2
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class FileScan < Base
|
7
|
-
attr_reader :report, :scan_id
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
@scan_id = @report.fetch('scan_id') { nil }
|
12
|
-
end
|
13
|
-
|
14
|
-
# @param [String] file_path for file to be sent for scan
|
15
|
-
# @param [String] api_key for virustotal
|
16
|
-
# @param [Hash] opts hash for additional options
|
17
|
-
# @return [VirusotalAPI::FileScan] Report
|
18
|
-
def self.scan(file_path, api_key, opts = {})
|
19
|
-
response = RestClient.post(
|
20
|
-
api_uri + '/file/scan',
|
21
|
-
apikey: api_key,
|
22
|
-
filename: opts.fetch('filename') { File.basename(file_path) },
|
23
|
-
file: File.open(file_path, 'r')
|
24
|
-
)
|
25
|
-
report = parse(response)
|
26
|
-
|
27
|
-
new(report)
|
28
|
-
end
|
29
|
-
|
30
|
-
# @return [Boolean] if file was queued
|
31
|
-
# 0 => not_present, 1 => exists, -2 => queued_for_analysis
|
32
|
-
def queued_for_analysis?
|
33
|
-
response_code = @report.fetch('response_code') { nil }
|
34
|
-
|
35
|
-
response_code == -2
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class IPReport < Base
|
7
|
-
attr_reader :report
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
end
|
12
|
-
|
13
|
-
# @param [String] ip address IPv4 format
|
14
|
-
# @param [String] api_key for virustotal
|
15
|
-
# @return [VirustotalAPI::IPReport] Report Search Result
|
16
|
-
def self.find(ip, api_key)
|
17
|
-
response = RestClient.get(
|
18
|
-
api_uri + '/ip-address/report',
|
19
|
-
{ params: params(ip, api_key) }
|
20
|
-
)
|
21
|
-
report = parse(response)
|
22
|
-
|
23
|
-
new(report)
|
24
|
-
end
|
25
|
-
|
26
|
-
# @param [String] ip address IPv4 format
|
27
|
-
# @param [String] api_key for virustotal
|
28
|
-
# @return [Hash] params for GET Request
|
29
|
-
def self.params(ip, api_key)
|
30
|
-
{
|
31
|
-
ip: ip,
|
32
|
-
apikey: api_key
|
33
|
-
}
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class URLReport < Base
|
7
|
-
attr_reader :report, :report_url, :scan_id
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
@report_url = report.fetch('permalink') { nil }
|
12
|
-
@scan_id = report.fetch('scan_id') { nil }
|
13
|
-
end
|
14
|
-
|
15
|
-
# @param [String] resource as an ip/domain/url
|
16
|
-
# @param [String] api_key for virustotal
|
17
|
-
# @param [Integer] optional param to start scan if not found. 1 for true
|
18
|
-
# @return [VirustotalAPI::URLReport] Report Search Result
|
19
|
-
def self.find(resource, api_key, scan = 0)
|
20
|
-
response = RestClient.post(
|
21
|
-
api_uri + '/url/report',
|
22
|
-
params(resource, api_key, scan)
|
23
|
-
)
|
24
|
-
report = parse(response)
|
25
|
-
|
26
|
-
new(report)
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param [String] resource as an ip/domain/url
|
30
|
-
# @param [String] api_key for virustotal
|
31
|
-
# @param [Integer] optional param to start scan if not found. 1 for true
|
32
|
-
# @return [Hash] params for POST Request
|
33
|
-
def self.params(resource, api_key, scan = 0)
|
34
|
-
{
|
35
|
-
resource: resource,
|
36
|
-
apikey: api_key,
|
37
|
-
scan: scan.to_s
|
38
|
-
}
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module VirustotalAPI
|
6
|
-
class URLScan < Base
|
7
|
-
attr_reader :report, :scan_id
|
8
|
-
|
9
|
-
def initialize(report)
|
10
|
-
@report = report
|
11
|
-
@scan_id = @report.fetch('scan_id') { nil }
|
12
|
-
end
|
13
|
-
|
14
|
-
# @param [String] url
|
15
|
-
# @param [String] api_key for virustotal
|
16
|
-
# @return [VirustotalAPI::URLScan] Report
|
17
|
-
def self.scan(url, api_key)
|
18
|
-
response = RestClient.post(
|
19
|
-
api_uri + '/url/scan',
|
20
|
-
apikey: api_key,
|
21
|
-
url: url
|
22
|
-
)
|
23
|
-
report = parse(response)
|
24
|
-
|
25
|
-
new(report)
|
26
|
-
end
|
27
|
-
|
28
|
-
# @return [Boolean] if file was queued
|
29
|
-
# 0 => not_present, 1 => exists, -2 => queued_for_analysis
|
30
|
-
def queued_for_analysis?
|
31
|
-
response_code = @report.fetch('response_code') { nil }
|
32
|
-
|
33
|
-
response_code == -2
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/test/domain_report_test.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/test_helper'
|
4
|
-
|
5
|
-
class VirustotalAPIDomainReportTest < Minitest::Test
|
6
|
-
def setup
|
7
|
-
@domain = 'virustotal.com'
|
8
|
-
@api_key = 'testapikey'
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_class_exists
|
12
|
-
assert VirustotalAPI::DomainReport
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_report_response
|
16
|
-
VCR.use_cassette('domain_report') do
|
17
|
-
vtdomain_report = VirustotalAPI::DomainReport.find(@domain, @api_key)
|
18
|
-
|
19
|
-
# Make sure that the JSON was parsed
|
20
|
-
assert vtdomain_report.is_a?(VirustotalAPI::DomainReport)
|
21
|
-
assert vtdomain_report.report.is_a?(Hash)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_exists?
|
26
|
-
VCR.use_cassette('domain_report') do
|
27
|
-
vtdomain_report = VirustotalAPI::DomainReport.find(@domain, @api_key)
|
28
|
-
|
29
|
-
assert vtdomain_report.exists?, true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
data/test/file_report_test.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/test_helper'
|
4
|
-
|
5
|
-
class VirustotalAPIFileReportTest < Minitest::Test
|
6
|
-
# rubocop:disable LineLength
|
7
|
-
def setup
|
8
|
-
@sha256 = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
|
9
|
-
@api_key = 'testapikey'
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_class_exists
|
13
|
-
assert VirustotalAPI::FileReport
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_report_response
|
17
|
-
VCR.use_cassette('report') do
|
18
|
-
virustotal_report = VirustotalAPI::FileReport.find(@sha256, @api_key)
|
19
|
-
|
20
|
-
# Make sure that the JSON was parsed
|
21
|
-
assert virustotal_report.is_a?(VirustotalAPI::FileReport)
|
22
|
-
assert virustotal_report.report.is_a?(Hash)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_report_url
|
27
|
-
permalink = 'https://www.virustotal.com/file/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b/analysis/1418032127/'
|
28
|
-
VCR.use_cassette('report') do
|
29
|
-
virustotal_report = VirustotalAPI::FileReport.find(@sha256, @api_key)
|
30
|
-
|
31
|
-
assert virustotal_report.report_url.is_a?(String)
|
32
|
-
assert virustotal_report.report_url, permalink
|
33
|
-
end
|
34
|
-
end
|
35
|
-
# rubocop:enable LineLength
|
36
|
-
end
|
data/test/file_rescan_test.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/test_helper'
|
4
|
-
|
5
|
-
class VirustotalAPIFileRescanTest < Minitest::Test
|
6
|
-
# rubocop:disable LineLength
|
7
|
-
def setup
|
8
|
-
@sha256 = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
|
9
|
-
@api_key = 'testapikey'
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_class_exists
|
13
|
-
assert VirustotalAPI::FileRescan
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_rescan_response
|
17
|
-
VCR.use_cassette('rescan') do
|
18
|
-
virustotal_rescan = VirustotalAPI::FileRescan.rescan(@sha256, @api_key)
|
19
|
-
|
20
|
-
assert virustotal_rescan.report.is_a?(Hash)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_rescan_id
|
25
|
-
VCR.use_cassette('rescan') do
|
26
|
-
virustotal_rescan = VirustotalAPI::FileRescan.rescan(@sha256, @api_key)
|
27
|
-
|
28
|
-
assert virustotal_rescan.rescan_id.is_a?(String)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
# rubocop:enable LineLength
|
32
|
-
end
|
data/test/file_scan_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/test_helper'
|
4
|
-
|
5
|
-
class VirustotalAPIFileScanTest < Minitest::Test
|
6
|
-
def setup
|
7
|
-
@file_path = File.expand_path('test/fixtures/null_file')
|
8
|
-
@api_key = 'testapikey'
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_class_exists
|
12
|
-
assert VirustotalAPI::FileScan
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_response
|
16
|
-
VCR.use_cassette('scan') do
|
17
|
-
virustotal_scan = VirustotalAPI::FileScan.scan(@file_path, @api_key)
|
18
|
-
|
19
|
-
assert virustotal_scan.report.is_a?(Hash)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_scan_id
|
24
|
-
VCR.use_cassette('scan') do
|
25
|
-
virustotal_scan = VirustotalAPI::FileScan.scan(@file_path, @api_key)
|
26
|
-
|
27
|
-
assert virustotal_scan.scan_id.is_a?(String)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|