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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +26 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +12 -5
  5. data/CHANGELOG.md +27 -2
  6. data/README.md +94 -56
  7. data/lib/virustotal_api.rb +7 -7
  8. data/lib/virustotal_api/analysis.rb +16 -0
  9. data/lib/virustotal_api/base.rb +41 -10
  10. data/lib/virustotal_api/domain.rb +18 -0
  11. data/lib/virustotal_api/exceptions.rb +3 -0
  12. data/lib/virustotal_api/file.rb +48 -0
  13. data/lib/virustotal_api/group.rb +18 -0
  14. data/lib/virustotal_api/ip.rb +18 -0
  15. data/lib/virustotal_api/uri.rb +2 -1
  16. data/lib/virustotal_api/url.rb +38 -0
  17. data/lib/virustotal_api/user.rb +18 -0
  18. data/lib/virustotal_api/version.rb +2 -1
  19. data/test/analysis_test.rb +26 -0
  20. data/test/base_test.rb +18 -23
  21. data/test/domain_test.rb +27 -0
  22. data/test/exceptions_test.rb +22 -0
  23. data/test/file_test.rb +63 -0
  24. data/test/fixtures/analysis.yml +544 -0
  25. data/test/fixtures/domain.yml +830 -0
  26. data/test/fixtures/domain_bad_request.yml +52 -0
  27. data/test/fixtures/file_analyse.yml +52 -0
  28. data/test/fixtures/file_find.yml +853 -0
  29. data/test/fixtures/file_not_found.yml +52 -0
  30. data/test/fixtures/file_rate_limit.yml +52 -0
  31. data/test/fixtures/file_unauthorized.yml +51 -0
  32. data/test/fixtures/file_upload.yml +54 -0
  33. data/test/fixtures/group_find.yml +216 -0
  34. data/test/fixtures/ip.yml +716 -0
  35. data/test/fixtures/unscanned_url_find.yml +44 -0
  36. data/test/fixtures/url_analyse.yml +52 -0
  37. data/test/fixtures/url_find.yml +599 -0
  38. data/test/fixtures/user_find.yml +213 -0
  39. data/test/group_test.rb +27 -0
  40. data/test/{ip_report_test.rb → ip_test.rb} +6 -4
  41. data/test/uri_test.rb +1 -1
  42. data/test/url_test.rb +47 -0
  43. data/test/user_test.rb +26 -0
  44. data/test/version_test.rb +1 -1
  45. data/virustotal_api.gemspec +10 -8
  46. metadata +102 -71
  47. data/.circleci/config.yml +0 -23
  48. data/.github/workflows/gem_publish.yml +0 -38
  49. data/lib/virustotal_api/domain_report.rb +0 -36
  50. data/lib/virustotal_api/file_report.rb +0 -37
  51. data/lib/virustotal_api/file_rescan.rb +0 -36
  52. data/lib/virustotal_api/file_scan.rb +0 -38
  53. data/lib/virustotal_api/ip_report.rb +0 -36
  54. data/lib/virustotal_api/url_report.rb +0 -41
  55. data/lib/virustotal_api/url_scan.rb +0 -36
  56. data/test/domain_report_test.rb +0 -32
  57. data/test/file_report_test.rb +0 -36
  58. data/test/file_rescan_test.rb +0 -32
  59. data/test/file_scan_test.rb +0 -30
  60. data/test/fixtures/domain_report.yml +0 -311
  61. data/test/fixtures/ip_report.yml +0 -1323
  62. data/test/fixtures/queue_unscanned_url_report.yml +0 -46
  63. data/test/fixtures/report.yml +0 -110
  64. data/test/fixtures/report_not_found.yml +0 -42
  65. data/test/fixtures/request_forbidden.yml +0 -38
  66. data/test/fixtures/rescan.yml +0 -47
  67. data/test/fixtures/scan.yml +0 -49
  68. data/test/fixtures/unscanned_url_report.yml +0 -43
  69. data/test/fixtures/url_report.yml +0 -95
  70. data/test/fixtures/url_scan.yml +0 -48
  71. data/test/url_report_test.rb +0 -57
  72. data/test/url_scan_test.rb +0 -30
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/domains' API
7
+ class Domain < Base
8
+ # Find a domain.
9
+ #
10
+ # @param [String] domain The domain to search
11
+ # @param [String] api_key for virustotal
12
+ # @return [VirustotalAPI::Domain] Report Search Result
13
+ def self.find(domain, api_key)
14
+ report = perform("/domains/#{domain}", api_key)
15
+ new(report)
16
+ end
17
+ end
18
+ end
@@ -3,4 +3,7 @@
3
3
  module VirustotalAPI
4
4
  class RateLimitError < RuntimeError
5
5
  end
6
+
7
+ class Unauthorized < RuntimeError
8
+ end
6
9
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/files' API
7
+ class File < Base
8
+ # Find a hash.
9
+ #
10
+ # @param [String] resource file as a md5/sha1/sha256 hash
11
+ # @param [String] api_key The key for virustotal
12
+ # @return [VirustotalAPI::File] Report Search Result
13
+ def self.find(resource, api_key)
14
+ report = perform("/files/#{resource}", api_key)
15
+ new(report)
16
+ end
17
+
18
+ # Upload a new file.
19
+ #
20
+ # @param [String] file_path for file to be sent for scan
21
+ # @param [String] api_key The key for virustotal
22
+ # @param [Hash] opts hash for additional options
23
+ # @return [VirusotalAPI::File] Report
24
+ def self.upload(file_path, api_key, opts = {})
25
+ filename = opts.fetch('filename') { ::File.basename(file_path) }
26
+ report = perform('/files', api_key, :post, filename: filename, file: ::File.open(file_path, 'r'))
27
+ new(report)
28
+ end
29
+
30
+ # Analyse a hash again.
31
+ #
32
+ # @param [String] resource file as a md5/sha1/sha256 hash
33
+ # @param [String] api_key The key for virustotal
34
+ # @return [VirustotalAPI::File] Report
35
+ def self.analyse(resource, api_key)
36
+ report = perform("/files/#{resource}/analyse", api_key, :post)
37
+ new(report)
38
+ end
39
+
40
+ # Check if the submitted hash is detected by an AV engine.
41
+ #
42
+ # @param [String] engine The engine to check.
43
+ # @return [Boolean] true if detected
44
+ def detected_by(engine)
45
+ report&.dig('data', 'attributes', 'last_analysis_results', engine, 'category') == 'malicious'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/groups' API
7
+ class Group < Base
8
+ # Find a Group.
9
+ #
10
+ # @param [String] group_id to find
11
+ # @param [String] api_key The key for virustotal
12
+ # @return [VirustotalAPI::User] Report
13
+ def self.find(group_id, api_key)
14
+ report = perform("/groups/#{group_id}", api_key)
15
+ new(report)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/ip_addresses' API
7
+ class IP < Base
8
+ # Find an IP.
9
+ #
10
+ # @param [String] ip address The IP to find.
11
+ # @param [String] api_key The key for virustotal
12
+ # @return [VirustotalAPI::IPReport] Report
13
+ def self.find(ip, api_key)
14
+ report = perform("/ip_addresses/#{ip}", api_key)
15
+ new(report)
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VirustotalAPI
4
- URI = 'https://www.virustotal.com/vtapi/v2'
4
+ # The API base URI
5
+ URI = 'https://www.virustotal.com/api/v3'
5
6
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/urls' API
7
+ class URL < Base
8
+ # Find a URL.
9
+ #
10
+ # @param [String] resource as an ip/domain/url
11
+ # @param [String] api_key The key for virustotal
12
+ # @return [VirustotalAPI::URL] Report
13
+ def self.find(resource, api_key)
14
+ report = perform("/urls/#{url_identifier(resource)}", api_key)
15
+ new(report)
16
+ end
17
+
18
+ # Analyse a URL again.
19
+ #
20
+ # @param [String] resource as an ip/domain/url
21
+ # @param [String] api_key The key for virustotal
22
+ # @return [VirustotalAPI::URL] Report
23
+ def self.analyse(resource, api_key)
24
+ report = perform("/urls/#{url_identifier(resource)}/analyse", api_key, :post)
25
+ new(report)
26
+ end
27
+
28
+ # Upload a URL for detection.
29
+ #
30
+ # @param [String] resource as an ip/domain/url
31
+ # @param [String] api_key The key for virustotal
32
+ # @return [VirustotalAPI::URL] Report
33
+ def self.upload(resource, api_key)
34
+ report = perform('/urls', api_key, :post, url: resource)
35
+ new(report)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module VirustotalAPI
6
+ # A class for '/users' API
7
+ class User < Base
8
+ # Find a User.
9
+ #
10
+ # @param [String] user_key with id or api_key
11
+ # @param [String] api_key The key for virustotal
12
+ # @return [VirustotalAPI::User] Report
13
+ def self.find(user_key, api_key)
14
+ report = perform("/users/#{user_key}", api_key)
15
+ new(report)
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VirustotalAPI
4
- VERSION = '0.4.1'
4
+ # The GEM version
5
+ VERSION = '0.5.4'
5
6
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './test/test_helper'
4
+
5
+ class VirustotalAPIAnalysisTest < Minitest::Test
6
+ def setup
7
+ @url = 'http://www.google.com'
8
+ @api_key = 'theapikey'
9
+ end
10
+
11
+ def test_todo
12
+ VCR.use_cassette('url_find') do
13
+ vtreport = VirustotalAPI::URL.find(@url, @api_key)
14
+
15
+ @id = vtreport.id
16
+ assert @id.is_a?(String)
17
+ end
18
+
19
+ VCR.use_cassette('analysis') do
20
+ analysis = VirustotalAPI::Analysis.find(@id, @api_key)
21
+
22
+ assert analysis.exists?
23
+ assert analysis.id.is_a?(String)
24
+ end
25
+ end
26
+ end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable LineLength
4
3
  require './test/test_helper'
5
4
 
6
5
  class VirustotalAPIBaseTest < Minitest::Test
7
6
  def setup
7
+ @domain = 'xpressco.za'
8
8
  @sha256 = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
9
9
  @api_key = 'testapikey'
10
10
  end
@@ -15,45 +15,40 @@ class VirustotalAPIBaseTest < Minitest::Test
15
15
 
16
16
  # Instance Method
17
17
  def test_api_uri_instance_method
18
- base_uri = 'https://www.virustotal.com/vtapi/v2'
19
- vt_base = VirustotalAPI::Base.new
18
+ base_uri = 'https://www.virustotal.com/api/v3'
19
+ vt_base = VirustotalAPI::Base.new(nil)
20
20
 
21
21
  assert vt_base.api_uri.is_a?(String)
22
- assert vt_base.api_uri, base_uri
22
+ assert_equal base_uri, vt_base.api_uri
23
23
  end
24
24
 
25
25
  # Class Method
26
26
  def test_api_uri_class_method
27
- base_uri = 'https://www.virustotal.com/vtapi/v2'
27
+ base_uri = 'https://www.virustotal.com/api/v3'
28
28
 
29
29
  assert VirustotalAPI::Base.api_uri.is_a?(String)
30
- assert VirustotalAPI::Base.api_uri, base_uri
30
+ assert_equal base_uri, VirustotalAPI::Base.api_uri
31
31
  end
32
32
 
33
- def test_parse_code_200
34
- mock_response200 = Minitest::Mock.new
35
- mock_response200.expect(:code, 200)
36
- mock_response200.expect(:body, '{}')
33
+ def test_exists?
34
+ VCR.use_cassette('file_find') do
35
+ virustotal_report = VirustotalAPI::File.find(@sha256, @api_key)
37
36
 
38
- assert VirustotalAPI::Base.parse(mock_response200), {}
37
+ assert virustotal_report.exists?
38
+ end
39
39
  end
40
40
 
41
- def test_parse_code_204
42
- mock_response204 = Minitest::Mock.new
43
- mock_response204.expect(:code, 204)
44
- mock_response204.expect(:body, '{}')
41
+ def test_not_exists?
42
+ VCR.use_cassette('file_not_found') do
43
+ virustotal_report = VirustotalAPI::File.find(@sha256, @api_key)
45
44
 
46
- assert_raises VirustotalAPI::RateLimitError do
47
- VirustotalAPI::Base.parse(mock_response204)
45
+ assert !virustotal_report.exists?
48
46
  end
49
- end
50
47
 
51
- # Test using FileReport
52
- def test_exists?
53
- VCR.use_cassette('report') do
54
- virustotal_report = VirustotalAPI::FileReport.find(@sha256, @api_key)
48
+ VCR.use_cassette('domain_bad_request') do
49
+ virustotal_report = VirustotalAPI::Domain.find(@domain, @api_key)
55
50
 
56
- assert virustotal_report.exists?, true
51
+ assert !virustotal_report.exists?
57
52
  end
58
53
  end
59
54
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './test/test_helper'
4
+
5
+ class VirustotalAPIDomainTest < Minitest::Test
6
+ def setup
7
+ @domain = 'virustotal.com'
8
+ @api_key = 'testapikey'
9
+ end
10
+
11
+ def test_class_exists
12
+ assert VirustotalAPI::Domain
13
+ end
14
+
15
+ def test_report_response
16
+ VCR.use_cassette('domain') do
17
+ vtdomain_report = VirustotalAPI::Domain.find(@domain, @api_key)
18
+
19
+ # Make sure that the JSON was parsed
20
+ assert vtdomain_report.exists?
21
+ assert vtdomain_report.is_a?(VirustotalAPI::Domain)
22
+ assert vtdomain_report.report.is_a?(Hash)
23
+ assert vtdomain_report.id.is_a?(String)
24
+ assert vtdomain_report.report_url.is_a?(String)
25
+ end
26
+ end
27
+ end
@@ -3,7 +3,29 @@
3
3
  require './test/test_helper'
4
4
 
5
5
  class RateLimitErrorTest < Minitest::Test
6
+ def setup
7
+ @sha256 = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
8
+ @api_key = 'testapikey'
9
+ end
10
+
6
11
  def test_class_exists
7
12
  assert VirustotalAPI::RateLimitError
13
+ assert VirustotalAPI::Unauthorized
14
+ end
15
+
16
+ def test_unauthorized
17
+ VCR.use_cassette('file_unauthorized') do
18
+ assert_raises VirustotalAPI::Unauthorized do
19
+ VirustotalAPI::File.find(@sha256, @api_key)
20
+ end
21
+ end
22
+ end
23
+
24
+ def test_rate_limit
25
+ VCR.use_cassette('file_rate_limit') do
26
+ assert_raises VirustotalAPI::RateLimitError do
27
+ VirustotalAPI::File.analyse(@sha256, @api_key)
28
+ end
29
+ end
8
30
  end
9
31
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './test/test_helper'
4
+
5
+ class VirustotalAPIFileTest < Minitest::Test
6
+ def setup
7
+ @sha256 = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
8
+ @file_path = File.expand_path('test/fixtures/null_file')
9
+ @api_key = 'testapikey'
10
+ end
11
+
12
+ def test_class_exists
13
+ assert VirustotalAPI::File
14
+ end
15
+
16
+ def test_report_response
17
+ VCR.use_cassette('file_find') do
18
+ vt_file_report = VirustotalAPI::File.find(@sha256, @api_key)
19
+
20
+ # Make sure that the JSON was parsed
21
+ assert vt_file_report.exists?
22
+ assert vt_file_report.is_a?(VirustotalAPI::File)
23
+ assert vt_file_report.report.is_a?(Hash)
24
+ assert vt_file_report.id.is_a?(String)
25
+ assert vt_file_report.report_url.is_a?(String)
26
+ end
27
+ end
28
+
29
+ def test_find
30
+ id = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b'
31
+ permalink = "https://www.virustotal.com/api/v3/files/#{id}"
32
+
33
+ VCR.use_cassette('file_find') do
34
+ vt_file_report = VirustotalAPI::File.find(@sha256, @api_key)
35
+
36
+ assert_equal permalink, vt_file_report.report_url
37
+ assert_equal id, vt_file_report.id
38
+ assert vt_file_report.detected_by('Avira')
39
+ assert !vt_file_report.detected_by('Acronis')
40
+ assert !vt_file_report.detected_by('Yeyeyeye') # not present in file
41
+ end
42
+ end
43
+
44
+ def test_upload
45
+ VCR.use_cassette('file_upload') do
46
+ vt_file_upload = VirustotalAPI::File.upload(@file_path, @api_key)
47
+
48
+ assert vt_file_upload.exists?
49
+ assert vt_file_upload.report.is_a?(Hash)
50
+ assert vt_file_upload.id.is_a?(String)
51
+ end
52
+ end
53
+
54
+ def test_analyse
55
+ VCR.use_cassette('file_analyse') do
56
+ vt_file_analyse = VirustotalAPI::File.analyse(@sha256, @api_key)
57
+
58
+ assert vt_file_analyse.exists?
59
+ assert vt_file_analyse.report.is_a?(Hash)
60
+ assert vt_file_analyse.id.is_a?(String)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,544 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://www.virustotal.com/api/v3/analyses/u-a354494a73382ea0b4bc47f4c9e8d6c578027cd4598196dc88f05a22b5817293-1599122231
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ User-Agent:
13
+ - rest-client/2.1.0 (linux-gnu x86_64) ruby/2.5.1p57
14
+ X-Apikey:
15
+ - theapikey
16
+ Content-Length:
17
+ - '0'
18
+ Content-Type:
19
+ - application/x-www-form-urlencoded
20
+ Accept-Encoding:
21
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
22
+ Host:
23
+ - www.virustotal.com
24
+ response:
25
+ status:
26
+ code: 200
27
+ message: OK
28
+ headers:
29
+ Cache-Control:
30
+ - no-cache
31
+ Content-Type:
32
+ - application/json; charset=utf-8
33
+ X-Cloud-Trace-Context:
34
+ - ee845ce2e3e28aee8c7f2c8e2de417cd
35
+ Date:
36
+ - Thu, 03 Sep 2020 08:43:03 GMT
37
+ Server:
38
+ - Google Frontend
39
+ Content-Length:
40
+ - '18600'
41
+ body:
42
+ encoding: UTF-8
43
+ string: |-
44
+ {
45
+ "data": {
46
+ "attributes": {
47
+ "date": 1599122231,
48
+ "results": {
49
+ "ADMINUSLabs": {
50
+ "category": "harmless",
51
+ "engine_name": "ADMINUSLabs",
52
+ "method": "blacklist",
53
+ "result": "clean"
54
+ },
55
+ "AegisLab WebGuard": {
56
+ "category": "harmless",
57
+ "engine_name": "AegisLab WebGuard",
58
+ "method": "blacklist",
59
+ "result": "clean"
60
+ },
61
+ "AlienVault": {
62
+ "category": "harmless",
63
+ "engine_name": "AlienVault",
64
+ "method": "blacklist",
65
+ "result": "clean"
66
+ },
67
+ "Antiy-AVL": {
68
+ "category": "harmless",
69
+ "engine_name": "Antiy-AVL",
70
+ "method": "blacklist",
71
+ "result": "clean"
72
+ },
73
+ "Artists Against 419": {
74
+ "category": "harmless",
75
+ "engine_name": "Artists Against 419",
76
+ "method": "blacklist",
77
+ "result": "clean"
78
+ },
79
+ "AutoShun": {
80
+ "category": "undetected",
81
+ "engine_name": "AutoShun",
82
+ "method": "blacklist",
83
+ "result": "unrated"
84
+ },
85
+ "Avira": {
86
+ "category": "harmless",
87
+ "engine_name": "Avira",
88
+ "method": "blacklist",
89
+ "result": "clean"
90
+ },
91
+ "BADWARE.INFO": {
92
+ "category": "harmless",
93
+ "engine_name": "BADWARE.INFO",
94
+ "method": "blacklist",
95
+ "result": "clean"
96
+ },
97
+ "Baidu-International": {
98
+ "category": "harmless",
99
+ "engine_name": "Baidu-International",
100
+ "method": "blacklist",
101
+ "result": "clean"
102
+ },
103
+ "BitDefender": {
104
+ "category": "harmless",
105
+ "engine_name": "BitDefender",
106
+ "method": "blacklist",
107
+ "result": "clean"
108
+ },
109
+ "BlockList": {
110
+ "category": "harmless",
111
+ "engine_name": "BlockList",
112
+ "method": "blacklist",
113
+ "result": "clean"
114
+ },
115
+ "Blueliv": {
116
+ "category": "harmless",
117
+ "engine_name": "Blueliv",
118
+ "method": "blacklist",
119
+ "result": "clean"
120
+ },
121
+ "CINS Army": {
122
+ "category": "harmless",
123
+ "engine_name": "CINS Army",
124
+ "method": "blacklist",
125
+ "result": "clean"
126
+ },
127
+ "CLEAN MX": {
128
+ "category": "harmless",
129
+ "engine_name": "CLEAN MX",
130
+ "method": "blacklist",
131
+ "result": "clean"
132
+ },
133
+ "CRDF": {
134
+ "category": "harmless",
135
+ "engine_name": "CRDF",
136
+ "method": "blacklist",
137
+ "result": "clean"
138
+ },
139
+ "Certego": {
140
+ "category": "harmless",
141
+ "engine_name": "Certego",
142
+ "method": "blacklist",
143
+ "result": "clean"
144
+ },
145
+ "Comodo Valkyrie Verdict": {
146
+ "category": "harmless",
147
+ "engine_name": "Comodo Valkyrie Verdict",
148
+ "method": "blacklist",
149
+ "result": "clean"
150
+ },
151
+ "CyRadar": {
152
+ "category": "harmless",
153
+ "engine_name": "CyRadar",
154
+ "method": "blacklist",
155
+ "result": "clean"
156
+ },
157
+ "Cyan": {
158
+ "category": "undetected",
159
+ "engine_name": "Cyan",
160
+ "method": "blacklist",
161
+ "result": "unrated"
162
+ },
163
+ "CyberCrime": {
164
+ "category": "harmless",
165
+ "engine_name": "CyberCrime",
166
+ "method": "blacklist",
167
+ "result": "clean"
168
+ },
169
+ "Cyren": {
170
+ "category": "harmless",
171
+ "engine_name": "Cyren",
172
+ "method": "blacklist",
173
+ "result": "clean"
174
+ },
175
+ "DNS8": {
176
+ "category": "harmless",
177
+ "engine_name": "DNS8",
178
+ "method": "blacklist",
179
+ "result": "clean"
180
+ },
181
+ "Dr.Web": {
182
+ "category": "harmless",
183
+ "engine_name": "Dr.Web",
184
+ "method": "blacklist",
185
+ "result": "clean"
186
+ },
187
+ "ESET": {
188
+ "category": "harmless",
189
+ "engine_name": "ESET",
190
+ "method": "blacklist",
191
+ "result": "clean"
192
+ },
193
+ "EmergingThreats": {
194
+ "category": "harmless",
195
+ "engine_name": "EmergingThreats",
196
+ "method": "blacklist",
197
+ "result": "clean"
198
+ },
199
+ "Emsisoft": {
200
+ "category": "harmless",
201
+ "engine_name": "Emsisoft",
202
+ "method": "blacklist",
203
+ "result": "clean"
204
+ },
205
+ "EonScope": {
206
+ "category": "harmless",
207
+ "engine_name": "EonScope",
208
+ "method": "blacklist",
209
+ "result": "clean"
210
+ },
211
+ "Feodo Tracker": {
212
+ "category": "harmless",
213
+ "engine_name": "Feodo Tracker",
214
+ "method": "blacklist",
215
+ "result": "clean"
216
+ },
217
+ "Forcepoint ThreatSeeker": {
218
+ "category": "harmless",
219
+ "engine_name": "Forcepoint ThreatSeeker",
220
+ "method": "blacklist",
221
+ "result": "clean"
222
+ },
223
+ "Fortinet": {
224
+ "category": "harmless",
225
+ "engine_name": "Fortinet",
226
+ "method": "blacklist",
227
+ "result": "clean"
228
+ },
229
+ "FraudScore": {
230
+ "category": "harmless",
231
+ "engine_name": "FraudScore",
232
+ "method": "blacklist",
233
+ "result": "clean"
234
+ },
235
+ "G-Data": {
236
+ "category": "harmless",
237
+ "engine_name": "G-Data",
238
+ "method": "blacklist",
239
+ "result": "clean"
240
+ },
241
+ "Google Safebrowsing": {
242
+ "category": "harmless",
243
+ "engine_name": "Google Safebrowsing",
244
+ "method": "blacklist",
245
+ "result": "clean"
246
+ },
247
+ "GreenSnow": {
248
+ "category": "harmless",
249
+ "engine_name": "GreenSnow",
250
+ "method": "blacklist",
251
+ "result": "clean"
252
+ },
253
+ "Hoplite Industries": {
254
+ "category": "harmless",
255
+ "engine_name": "Hoplite Industries",
256
+ "method": "blacklist",
257
+ "result": "clean"
258
+ },
259
+ "IPsum": {
260
+ "category": "harmless",
261
+ "engine_name": "IPsum",
262
+ "method": "blacklist",
263
+ "result": "clean"
264
+ },
265
+ "K7AntiVirus": {
266
+ "category": "harmless",
267
+ "engine_name": "K7AntiVirus",
268
+ "method": "blacklist",
269
+ "result": "clean"
270
+ },
271
+ "Kaspersky": {
272
+ "category": "harmless",
273
+ "engine_name": "Kaspersky",
274
+ "method": "blacklist",
275
+ "result": "clean"
276
+ },
277
+ "Lumu": {
278
+ "category": "undetected",
279
+ "engine_name": "Lumu",
280
+ "method": "blacklist",
281
+ "result": "unrated"
282
+ },
283
+ "MalSilo": {
284
+ "category": "harmless",
285
+ "engine_name": "MalSilo",
286
+ "method": "blacklist",
287
+ "result": "clean"
288
+ },
289
+ "Malware Domain Blocklist": {
290
+ "category": "harmless",
291
+ "engine_name": "Malware Domain Blocklist",
292
+ "method": "blacklist",
293
+ "result": "clean"
294
+ },
295
+ "MalwareDomainList": {
296
+ "category": "harmless",
297
+ "engine_name": "MalwareDomainList",
298
+ "method": "blacklist",
299
+ "result": "clean"
300
+ },
301
+ "MalwarePatrol": {
302
+ "category": "harmless",
303
+ "engine_name": "MalwarePatrol",
304
+ "method": "blacklist",
305
+ "result": "clean"
306
+ },
307
+ "Malwared": {
308
+ "category": "harmless",
309
+ "engine_name": "Malwared",
310
+ "method": "blacklist",
311
+ "result": "clean"
312
+ },
313
+ "Netcraft": {
314
+ "category": "undetected",
315
+ "engine_name": "Netcraft",
316
+ "method": "blacklist",
317
+ "result": "unrated"
318
+ },
319
+ "NotMining": {
320
+ "category": "undetected",
321
+ "engine_name": "NotMining",
322
+ "method": "blacklist",
323
+ "result": "unrated"
324
+ },
325
+ "Nucleon": {
326
+ "category": "harmless",
327
+ "engine_name": "Nucleon",
328
+ "method": "blacklist",
329
+ "result": "clean"
330
+ },
331
+ "OpenPhish": {
332
+ "category": "harmless",
333
+ "engine_name": "OpenPhish",
334
+ "method": "blacklist",
335
+ "result": "clean"
336
+ },
337
+ "PREBYTES": {
338
+ "category": "harmless",
339
+ "engine_name": "PREBYTES",
340
+ "method": "blacklist",
341
+ "result": "clean"
342
+ },
343
+ "PhishLabs": {
344
+ "category": "undetected",
345
+ "engine_name": "PhishLabs",
346
+ "method": "blacklist",
347
+ "result": "unrated"
348
+ },
349
+ "Phishing Database": {
350
+ "category": "harmless",
351
+ "engine_name": "Phishing Database",
352
+ "method": "blacklist",
353
+ "result": "clean"
354
+ },
355
+ "Phishtank": {
356
+ "category": "harmless",
357
+ "engine_name": "Phishtank",
358
+ "method": "blacklist",
359
+ "result": "clean"
360
+ },
361
+ "Quick Heal": {
362
+ "category": "harmless",
363
+ "engine_name": "Quick Heal",
364
+ "method": "blacklist",
365
+ "result": "clean"
366
+ },
367
+ "Quttera": {
368
+ "category": "harmless",
369
+ "engine_name": "Quttera",
370
+ "method": "blacklist",
371
+ "result": "clean"
372
+ },
373
+ "Rising": {
374
+ "category": "harmless",
375
+ "engine_name": "Rising",
376
+ "method": "blacklist",
377
+ "result": "clean"
378
+ },
379
+ "SCUMWARE.org": {
380
+ "category": "harmless",
381
+ "engine_name": "SCUMWARE.org",
382
+ "method": "blacklist",
383
+ "result": "clean"
384
+ },
385
+ "Sangfor": {
386
+ "category": "harmless",
387
+ "engine_name": "Sangfor",
388
+ "method": "blacklist",
389
+ "result": "clean"
390
+ },
391
+ "SecureBrain": {
392
+ "category": "harmless",
393
+ "engine_name": "SecureBrain",
394
+ "method": "blacklist",
395
+ "result": "clean"
396
+ },
397
+ "Snort IP sample list": {
398
+ "category": "harmless",
399
+ "engine_name": "Snort IP sample list",
400
+ "method": "blacklist",
401
+ "result": "clean"
402
+ },
403
+ "Sophos": {
404
+ "category": "harmless",
405
+ "engine_name": "Sophos",
406
+ "method": "blacklist",
407
+ "result": "clean"
408
+ },
409
+ "Spam404": {
410
+ "category": "harmless",
411
+ "engine_name": "Spam404",
412
+ "method": "blacklist",
413
+ "result": "clean"
414
+ },
415
+ "Spamhaus": {
416
+ "category": "harmless",
417
+ "engine_name": "Spamhaus",
418
+ "method": "blacklist",
419
+ "result": "clean"
420
+ },
421
+ "StopBadware": {
422
+ "category": "undetected",
423
+ "engine_name": "StopBadware",
424
+ "method": "blacklist",
425
+ "result": "unrated"
426
+ },
427
+ "StopForumSpam": {
428
+ "category": "harmless",
429
+ "engine_name": "StopForumSpam",
430
+ "method": "blacklist",
431
+ "result": "clean"
432
+ },
433
+ "Sucuri SiteCheck": {
434
+ "category": "harmless",
435
+ "engine_name": "Sucuri SiteCheck",
436
+ "method": "blacklist",
437
+ "result": "clean"
438
+ },
439
+ "Tencent": {
440
+ "category": "harmless",
441
+ "engine_name": "Tencent",
442
+ "method": "blacklist",
443
+ "result": "clean"
444
+ },
445
+ "ThreatHive": {
446
+ "category": "harmless",
447
+ "engine_name": "ThreatHive",
448
+ "method": "blacklist",
449
+ "result": "clean"
450
+ },
451
+ "Threatsourcing": {
452
+ "category": "harmless",
453
+ "engine_name": "Threatsourcing",
454
+ "method": "blacklist",
455
+ "result": "clean"
456
+ },
457
+ "Trustwave": {
458
+ "category": "harmless",
459
+ "engine_name": "Trustwave",
460
+ "method": "blacklist",
461
+ "result": "clean"
462
+ },
463
+ "URLhaus": {
464
+ "category": "harmless",
465
+ "engine_name": "URLhaus",
466
+ "method": "blacklist",
467
+ "result": "clean"
468
+ },
469
+ "VX Vault": {
470
+ "category": "harmless",
471
+ "engine_name": "VX Vault",
472
+ "method": "blacklist",
473
+ "result": "clean"
474
+ },
475
+ "Virusdie External Site Scan": {
476
+ "category": "harmless",
477
+ "engine_name": "Virusdie External Site Scan",
478
+ "method": "blacklist",
479
+ "result": "clean"
480
+ },
481
+ "Web Security Guard": {
482
+ "category": "harmless",
483
+ "engine_name": "Web Security Guard",
484
+ "method": "blacklist",
485
+ "result": "clean"
486
+ },
487
+ "Yandex Safebrowsing": {
488
+ "category": "harmless",
489
+ "engine_name": "Yandex Safebrowsing",
490
+ "method": "blacklist",
491
+ "result": "clean"
492
+ },
493
+ "ZeroCERT": {
494
+ "category": "harmless",
495
+ "engine_name": "ZeroCERT",
496
+ "method": "blacklist",
497
+ "result": "clean"
498
+ },
499
+ "desenmascara.me": {
500
+ "category": "harmless",
501
+ "engine_name": "desenmascara.me",
502
+ "method": "blacklist",
503
+ "result": "clean"
504
+ },
505
+ "malwares.com URL checker": {
506
+ "category": "harmless",
507
+ "engine_name": "malwares.com URL checker",
508
+ "method": "blacklist",
509
+ "result": "clean"
510
+ },
511
+ "securolytics": {
512
+ "category": "harmless",
513
+ "engine_name": "securolytics",
514
+ "method": "blacklist",
515
+ "result": "clean"
516
+ },
517
+ "zvelo": {
518
+ "category": "harmless",
519
+ "engine_name": "zvelo",
520
+ "method": "blacklist",
521
+ "result": "clean"
522
+ }
523
+ },
524
+ "stats": {
525
+ "harmless": 72,
526
+ "malicious": 0,
527
+ "suspicious": 0,
528
+ "timeout": 0,
529
+ "undetected": 7
530
+ },
531
+ "status": "completed"
532
+ },
533
+ "id": "u-a354494a73382ea0b4bc47f4c9e8d6c578027cd4598196dc88f05a22b5817293-1599122231",
534
+ "type": "analysis"
535
+ },
536
+ "meta": {
537
+ "url_info": {
538
+ "id": "a354494a73382ea0b4bc47f4c9e8d6c578027cd4598196dc88f05a22b5817293",
539
+ "url": "http://virustotal.com/"
540
+ }
541
+ }
542
+ }
543
+ recorded_at: Thu, 03 Sep 2020 08:43:03 GMT
544
+ recorded_with: VCR 6.0.0