uirusu 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf7de8705fa6a0e595f9c1a1781dd4936ea9df91
4
- data.tar.gz: 698407a8dddc1a1b8fb9aac9de18afb33b2c4248
3
+ metadata.gz: cd1b2173bea70412a787d51e6968bfefe2a5af9b
4
+ data.tar.gz: 9c00e08d2ccc82b620f7ba1670f4c0c2b30f35c6
5
5
  SHA512:
6
- metadata.gz: 1e9dc51ae0271f2640578e26572e76014d78c29125d47bab199c1715b56d273e68402da9d317ee4e47be21af698bd776359cb56138b9edba5338cd632888cf5d
7
- data.tar.gz: c86b7afc18da01de6482f0eb824684fa9534207e1f19fb1bee5993031f0fe1c2425ce9401ffb5b8cd42404589d88802c3670a76f89ccf70816c0bbb863ce5cb9
6
+ metadata.gz: 83754cc68a7631fded5d617588239bcb5928ccd7f536bfff6c0ec46644ec85c4b04d46e77a847aef182f0d2ee3fa2b503665e0e2a07550b700de315029dbdd93
7
+ data.tar.gz: ffbe2e9e701597b5b47384f076c1b7b993a90c937a150f6278172627543ce8f70e56b3d2a61e4995c17938d8b315a51403d5b77a51711176c77444e805a9f350
data/NEWS.markdown CHANGED
@@ -1,5 +1,9 @@
1
1
  # News
2
2
 
3
+ # 0.0.5 (June 14, 2013)
4
+ - Merged Pull request from [jfx41]
5
+ - Lots of cleanup from jfx41
6
+
3
7
  # 0.0.4 (April 11, 2013)
4
8
  - Added Proxy support [abenson]
5
9
  - Copyright date updates
data/Rakefile CHANGED
@@ -34,11 +34,11 @@ require 'rake'
34
34
  require 'rake/testtask'
35
35
 
36
36
  task :build do
37
- system "gem build #{Uirusu::APP_NAME}.gemspec"
37
+ system "gem build #{Uirusu::APP_NAME}.gemspec"
38
38
  end
39
39
 
40
40
  task :release => :build do
41
- system "gem push #{Uirusu::APP_NAME}-#{Uirusu::VERSION}.gem"
41
+ system "gem push #{Uirusu::APP_NAME}-#{Uirusu::VERSION}.gem"
42
42
  puts "Just released #{Uirusu::APP_NAME} v#{Uirusu::VERSION}. #{Uirusu::APP_NAME} is rubygem for using the Virustotal web service! More information at http://arxopia.com/projects/uirusu/"
43
43
  end
44
44
 
@@ -51,6 +51,6 @@ task :default => [:test]
51
51
 
52
52
  Rake::TestTask.new("test") do |t|
53
53
  t.libs << "test"
54
- t.pattern = 'test/*/*_test.rb'
55
- t.verbose = true
54
+ t.pattern = 'test/*/*_test.rb'
55
+ t.verbose = true
56
56
  end
data/lib/uirusu.rb CHANGED
@@ -28,8 +28,10 @@
28
28
 
29
29
  module Uirusu
30
30
  APP_NAME = "uirusu"
31
- VERSION = "0.0.4"
31
+ VERSION = "0.0.5"
32
32
  CONFIG_FILE = "~/.uirusu"
33
+ VT_API = "https://www.virustotal.com/vtapi/v2"
34
+ RESULT_FIELDS = [ :hash, :scanner, :version, :detected, :result, :md5, :sha1, :sha256, :update, :permalink, ]
33
35
  end
34
36
 
35
37
  require 'json'
@@ -1,20 +1,20 @@
1
1
  # Copyright (c) 2012-2013 Arxopia LLC.
2
2
  # All rights reserved.
3
- #
3
+ #
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
6
- #
7
- # Redistributions of source code must retain the above copyright notice,
6
+ #
7
+ # Redistributions of source code must retain the above copyright notice,
8
8
  # this list of conditions and the following disclaimer.
9
9
  #
10
- # Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
10
+ # Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
12
  # and/or other materials provided with the distribution.
13
13
  #
14
- # Neither the name of the project's author nor the names of its contributors
15
- # may be used to endorse or promote products derived from this software
14
+ # Neither the name of the project's author nor the names of its contributors
15
+ # may be used to endorse or promote products derived from this software
16
16
  # without specific prior written permission.
17
- #
17
+ #
18
18
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
19
  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
20
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -29,7 +29,7 @@
29
29
  module Uirusu
30
30
  module CLI
31
31
  class Application
32
-
32
+
33
33
  # Creates a new instance of the [Application] class
34
34
  #
35
35
  def initialize
@@ -40,38 +40,44 @@ module Uirusu
40
40
  @sites = Array.new
41
41
  @uploads = Array.new
42
42
  end
43
-
43
+
44
44
  # Parses the command the line options and returns the parsed options hash
45
45
  #
46
46
  # @return [Hash] of the parsed options
47
47
  def parse_options(args)
48
48
  begin
49
- @options['output'] = :stdout
49
+ @options['output'] = :stdout
50
50
  @options['verbose'] = false
51
- @options[:timeout] = 25
52
-
51
+ @options['rescan'] = false
52
+ @options[:timeout] = 25
53
+
53
54
  opt = OptionParser.new do |opt|
54
- opt.banner = "#{APP_NAME} v#{VERSION}\nJacob Hammack\nhttp://www.hammackj.com\n\n"
55
+ opt.banner = "#{APP_NAME} v#{VERSION}\nJacob Hammack\nhttp://www.arxopia.com\n\n"
55
56
  opt.banner << "Usage: #{APP_NAME} <options>"
56
57
  opt.separator('')
57
- opt.separator("File Options")
58
-
59
- opt.on('-h HASH', '--search-hash HASH', 'Searches a single hash on virustotal.com') do |hash|
58
+ opt.separator('File Options')
59
+
60
+ opt.on('-h HASH', '--search-hash HASH', 'Searches a single hash on virustotal.com') do |hash|
61
+ @hashes.push(hash)
62
+ end
63
+
64
+ opt.on('-r HASH[,HASH]', '--rescan-hash HASH[,HASH]', 'Requests a rescan of a single hash, or multiple hashes (comma separated), by virustotal.com') do |hash|
65
+ @options['rescan'] = true
60
66
  @hashes.push(hash)
61
67
  end
62
68
 
63
69
  opt.on('-f FILE', '--search-hash-file FILE', 'Searches a each hash in a file of hashes on virustotal.com') do |file|
64
70
  if File.exists?(file)
65
- puts "[+] Adding file #{file}" if @options["verbose"]
71
+ puts "[+] Adding file #{file}" if @options['verbose']
66
72
  @files_of_hashes.push(file)
67
73
  else
68
74
  puts "[!] #{file} does not exist, please check your input!\n"
69
75
  end
70
76
  end
71
-
77
+
72
78
  opt.on('-u FILE', '--upload-file FILE', 'Uploads a file to virustotal.com for analysis') do |file|
73
79
  if File.exists?(file)
74
- puts "[+] Adding file #{file}" if @options["verbose"]
80
+ puts "[+] Adding file #{file}" if @options['verbose']
75
81
  @uploads.push(file)
76
82
  else
77
83
  puts "[!] #{file} does not exist, please check your input!\n"
@@ -80,22 +86,26 @@ module Uirusu
80
86
 
81
87
  opt.separator('')
82
88
  opt.separator("Url Options")
83
-
84
- opt.on('-s SITE', '--search-site SITE', 'Searches for a single url on virustotal.com') { |site|
89
+
90
+ opt.on('-s SITE', '--search-site SITE', 'Searches for a single url on virustotal.com') { |site|
85
91
  @sites.push(site)
86
92
  }
87
-
93
+
88
94
  opt.separator('')
89
95
  opt.separator('Output Options')
90
96
 
97
+ opt.on('-j', '--json-output', 'Print results as json to stdout') do
98
+ @options['output'] = :json
99
+ end
100
+
91
101
  opt.on('-x', '--xml-output', 'Print results as xml to stdout') do
92
- @options["output"] = :xml
102
+ @options['output'] = :xml
93
103
  end
94
-
104
+
95
105
  opt.on('-y', '--yaml-output', 'Print results as yaml to stdout') do
96
106
  @options['output'] = :yaml
97
107
  end
98
-
108
+
99
109
  opt.on('--stdout-output', 'Print results as normal text line to stdout, this is default') do
100
110
  @options['output'] = :stdout
101
111
  end
@@ -103,10 +113,10 @@ module Uirusu
103
113
  opt.separator ''
104
114
  opt.separator 'Advanced Options'
105
115
 
106
- opt.on('-c', '--create-config', 'Creates a skeleton config file to use') do
116
+ opt.on('-c', '--create-config', 'Creates a skeleton config file to use') do
107
117
  if File.exists?(File.expand_path(CONFIG_FILE)) == false
108
- File.open(File.expand_path(CONFIG_FILE), 'w+') do |f|
109
- f.write("virustotal: \n api-key: \n timeout: 25\n\n")
118
+ File.open(File.expand_path(CONFIG_FILE), 'w+') do |f|
119
+ f.write("virustotal: \n api-key: \n timeout: 25\n\n")
110
120
  end
111
121
 
112
122
  puts "[*] An empty #{File.expand_path(CONFIG_FILE)} has been created. Please edit and fill in the correct values."
@@ -122,35 +132,35 @@ module Uirusu
122
132
  end
123
133
 
124
134
  opt.on('--[no-]verbose', 'Print verbose information') do |v|
125
- @options["verbose"] = v
135
+ @options['verbose'] = v
126
136
  end
127
-
137
+
128
138
  opt.separator ''
129
139
  opt.separator 'Other Options'
130
-
131
- opt.on('-v', '--version', "Shows application version information") do
140
+
141
+ opt.on('-v', '--version', 'Shows application version information') do
132
142
  puts "#{APP_NAME} - #{VERSION}"
133
143
  exit
134
144
  end
135
145
 
136
- opt.on_tail("-?", "--help", "Show this message") { |help|
146
+ opt.on_tail('-?', '--help', 'Show this message') { |help|
137
147
  puts opt.to_s + "\n"
138
148
  exit
139
- }
149
+ }
140
150
  end
141
-
142
- if ARGV.length != 0
151
+
152
+ if ARGV.length != 0
143
153
  opt.parse!
144
154
  else
145
155
  puts opt.to_s + "\n"
146
156
  exit
147
- end
157
+ end
148
158
  rescue OptionParser::MissingArgument => m
149
159
  puts opt.to_s + "\n"
150
160
  exit
151
161
  end
152
162
  end
153
-
163
+
154
164
  # Loads the .uirusu config file for the api key
155
165
  #
156
166
  def load_config
@@ -161,9 +171,9 @@ module Uirusu
161
171
  exit
162
172
  end
163
173
 
164
- @options[:timeout] = @config["virustotal"]["timeout"] if @config["virustotal"]["timeout"] != nil
174
+ @options[:timeout] = @config['virustotal']['timeout'] if @config['virustotal']['timeout'] != nil
165
175
  end
166
-
176
+
167
177
  # Submits a file/url and waits for analysis to be complete and returns the results.
168
178
  #
169
179
  # @param mod
@@ -173,65 +183,91 @@ module Uirusu
173
183
  def scan_and_wait(mod, resource, attempts)
174
184
  method = nil
175
185
  retries = attempts
176
-
186
+
177
187
  if mod.name == "Uirusu::VTFile"
178
- method = mod.method :scan_file
188
+ STDERR.puts "[*] Attempting to rescan #{resource}" if @options['verbose']
189
+ method = @options['rescan'] ? mod.method(:rescan_file) : mod.method(:scan_file)
179
190
  else
191
+ STDERR.puts "[*] Attempting to upload file #{resource}" if @options['verbose']
180
192
  method = mod.method :scan_url
181
193
  end
182
194
 
183
195
  begin
184
- STDERR.puts "[*] Attempting to upload file #{resource}" if @options["verbose"]
185
- result = method.call(@config["virustotal"]["api-key"], resource)
196
+ result = method.call(@config['virustotal']['api-key'], resource)
186
197
  rescue => e
187
- STDERR.puts "[!] An error has occured uploading the file. Retrying 60 seconds up #{retries} retries.\n" if @options["verbose"]
198
+ if @options['rescan']
199
+ STDERR.puts "[!] An error has occurred with the rescan request. Retrying 60 seconds up #{retries} retries: #{e.message}\n" if @options['verbose']
200
+ else
201
+ STDERR.puts "[!] An error has occurred uploading the file. Retrying 60 seconds up #{retries} retries.\n" if @options['verbose']
202
+ end
203
+
188
204
  if retries >= 0
189
205
  sleep 60
190
206
  retry
191
207
  retries = retries - 1
192
208
  end
193
209
  end
194
-
210
+
195
211
  begin
196
- if result['response_code'] == 1
197
- results = mod.query_report(@config["virustotal"]["api-key"], result['resource'])
198
-
199
- while results["response_code"] != 1
200
- STDERR.puts "[*] File has not been analyized yet, waiting 60 seconds to try again" if @options["verbose"]
201
- sleep 60
202
- results = mod.query_report(@config["virustotal"]["api-key"], result['resource'])
212
+
213
+ # Convert all single result replies to an array. This is because
214
+ # rescan_file returns an array of results if more than one hash
215
+ # is requested to be rescanned.
216
+ result_array = result.is_a?(Array) ? result : [ result ]
217
+
218
+ result_array.collect do |result|
219
+ if result['response_code'] == 1
220
+ STDERR.puts "[*] Attempting to parse the results for: #{result['resource']}" if @options['verbose']
221
+ results = mod.query_report(@config['virustotal']['api-key'], result['resource'])
222
+
223
+ while results['response_code'] != 1
224
+ STDERR.puts "[*] File has not been analyized yet, waiting 60 seconds to try again" if @options['verbose']
225
+ sleep 60
226
+ results = mod.query_report(@config['virustotal']['api-key'], result['resource'])
227
+ end
228
+
229
+ [result['resource'], results]
230
+ #return [result['resource'], results]
231
+
232
+ elsif result['response_code'] == 0 and @options['rescan']
233
+ STDERR.puts "[!] Unknown Virustotal error for rescan of #{result['resource']}." if @options['verbose']
234
+ next
235
+
236
+ elsif result['response_code'] == -1 and @options['rescan']
237
+ STDERR.puts "[!] Virustotal does not have a sample of #{result['resource']}." if @options['verbose']
238
+ next
239
+
240
+ elsif result['response_code'] == -2
241
+ STDERR.puts "[!] Virustotal limits exceeded, ***do not edit the timeout values.***"
242
+ exit(1)
243
+ else
244
+ nil
203
245
  end
204
-
205
- return [result['resource'], results]
206
- elsif result['response_code'] == -2
207
- STDERR.puts "[!] Virustotal limits exceeded, ***do not edit the timeout values.***"
208
- exit(1)
209
- else
210
- nil
211
- end
212
- rescue => e
213
- STDERR.puts "[!] An error has occurred retrieving the report. Retrying 60 seconds up #{retries} retries.\n" if @options["verbose"]
246
+ end
247
+ rescue => e
248
+ STDERR.puts "[!] An error has occurred retrieving the report. Retrying 60 seconds up #{retries} retries. #{e.message}\n" if @options['verbose']
214
249
  if retries >= 0
215
250
  sleep 60
216
251
  retry
217
252
  retries = retries - 1
218
- end
253
+ end
219
254
  end
220
255
  end
221
-
256
+
222
257
  #
223
258
  #
224
259
  def main(args)
225
260
  parse_options(args)
226
261
  load_config
227
-
262
+
228
263
  if @options['output'] == :stdout
229
264
  output_method = :to_stdout
265
+ elsif @options['output'] == :json
266
+ output_method = :to_json
230
267
  elsif @options['output'] == :yaml
231
268
  output_method = :to_yaml
232
269
  elsif @options['output'] == :xml
233
270
  output_method = :to_xml
234
- print "<results>\n"
235
271
  end
236
272
 
237
273
  if @options['proxy'] != nil
@@ -242,16 +278,21 @@ module Uirusu
242
278
  @files_of_hashes.each do |file|
243
279
  f = File.open(file, 'r')
244
280
 
245
- f.each do |hash|
246
- hash.chomp!
247
- @hashes.push hash
248
- end
281
+ f.each do |hash|
282
+ hash.chomp!
283
+ @hashes.push hash
284
+ end
249
285
  end
250
- end
286
+ end
251
287
 
252
288
  if @hashes != nil
253
289
  @hashes.each_with_index do |hash, index|
254
- results = Uirusu::VTFile.query_report(@config["virustotal"]["api-key"], hash)
290
+ if @options['rescan']
291
+ results = scan_and_wait(Uirusu::VTFile, hash, 5)
292
+ else
293
+ results = Uirusu::VTFile.query_report(@config['virustotal']['api-key'], hash)
294
+ end
295
+
255
296
  result = Uirusu::VTResult.new(hash, results)
256
297
  print result.send output_method if result != nil
257
298
  sleep @options[:timeout] if index != @hashes.length - 1
@@ -270,16 +311,13 @@ module Uirusu
270
311
  if @uploads != nil
271
312
  @uploads.each_with_index do |upload, index|
272
313
  results = scan_and_wait(Uirusu::VTFile, upload, 5)
273
- result = Uirusu::VTResult.new(results[0], results[1])
314
+ result = Uirusu::VTResult.new(results[0], results[1])
274
315
  print result.send output_method if result != nil
275
316
  sleep @options[:timeout] if index != @uploads.length - 1
276
317
  end
277
318
  end
278
-
279
- if @options['output'] == :xml
280
- print "</results>\n"
281
- end
282
319
  end
283
320
  end
284
321
  end
285
- end
322
+ end
323
+
@@ -15,7 +15,7 @@
15
15
  # may be used to endorse or promote products derived from this software
16
16
  # without specific prior written permission.
17
17
  #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
19
19
  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
20
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
21
  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
@@ -30,7 +30,7 @@ module Uirusu
30
30
  # Module for submiting comments to Virustotal.com resources using the
31
31
  # Virustotal.com public API
32
32
  module VTComment
33
- POST_URL = "https://www.virustotal.com/vtapi/v2/comments/put"
33
+ POST_URL = Uirusu::VT_API + "/comments/put"
34
34
 
35
35
  # Submits a comment to Virustotal.com for a specific resource
36
36
  #
data/lib/uirusu/vtfile.rb CHANGED
@@ -15,7 +15,7 @@
15
15
  # may be used to endorse or promote products derived from this software
16
16
  # without specific prior written permission.
17
17
  #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
19
19
  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
20
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
21
  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
@@ -31,8 +31,9 @@ module Uirusu
31
31
  # Module for Accessing the File scan and report functionalities of the
32
32
  # Virustotal.com public API
33
33
  module VTFile
34
- SCAN_URL = "http://www.virustotal.com/vtapi/v2/file/scan"
35
- REPORT_URL = "https://www.virustotal.com/vtapi/v2/file/report"
34
+ SCAN_URL = Uirusu::VT_API + "/file/scan"
35
+ RESCAN_URL = Uirusu::VT_API + "/file/rescan"
36
+ REPORT_URL = Uirusu::VT_API + "/file/report"
36
37
 
37
38
  # Queries a report from Virustotal.com
38
39
  #
@@ -60,6 +61,8 @@ module Uirusu
60
61
  JSON.parse(response)
61
62
  when 500
62
63
  nil
64
+ else
65
+ raise "Unknown Server error."
63
66
  end
64
67
  end
65
68
 
@@ -91,5 +94,36 @@ module Uirusu
91
94
  raise "Unknown Server error."
92
95
  end
93
96
  end
97
+
98
+ # Requests an existing file to be rescanned.
99
+ #
100
+ # @param api_key Virustotal.com API key
101
+ # @param resource MD5/sha1/sha256/scan_id to rescan
102
+ #
103
+ # @return [JSON] Parsed response
104
+ def self.rescan_file(api_key, resource)
105
+ if api_key == nil
106
+ raise "Invalid API Key"
107
+ end
108
+
109
+ if resource == nil
110
+ raise "Invalid resource, must be md5/sha1/sha256/scan_id"
111
+ end
112
+
113
+ response = RestClient.post RESCAN_URL, :apikey => api_key, :resource => resource
114
+
115
+ case response.code
116
+ when 429
117
+ raise "Virustotal limit reached. Try again later."
118
+ when 403
119
+ raise "Invalid privileges, please check your API key."
120
+ when 200
121
+ JSON.parse(response)
122
+ when 500
123
+ nil
124
+ else
125
+ raise "Unknown Server error."
126
+ end
127
+ end
94
128
  end
95
129
  end
@@ -28,61 +28,65 @@
28
28
 
29
29
  module Uirusu
30
30
 
31
- #A wrapper class to hold all of the data for a single Virus total result
31
+ # A wrapper class to hold all of the data for a single Virus total result
32
32
  class VTResult
33
- def initialize hash, result
34
- if result == nil
33
+ RESULT_FIELDS = Uirusu::RESULT_FIELDS
34
+
35
+ def initialize hash, results
36
+ if results == nil or results.empty?
35
37
  return
38
+
39
+ # Take into consideration being passed an array of results.
40
+ # For instance, rescan_file will return an array if more than
41
+ # one sample is given. This ensures single results work.
42
+ elsif not results.is_a? Array
43
+ results = [ [ hash, results ] ]
36
44
  end
37
45
 
38
46
  @results = Array.new
39
47
 
40
- if result["response_code"] == 0
41
- res = Hash.new
42
- res['hash'] = hash
43
- res['scanner'] = '-'
44
- res['md5'] = '-'
45
- res['sha1'] = '-'
46
- res['sha256'] = '-'
47
- res['detected'] = '-'
48
- res['version'] = '-'
49
- res['result'] = '-'
50
- res['update'] = '-'
51
- res['permalink'] = '-'
52
- res['result'] = result["verbose_msg"]
53
-
54
- @results.push res
55
- elsif result["response_code"] == 0
56
- puts "[!] Invalid API KEY! Please correct this! Check ~/.uirusu"
57
- exit
58
- else
59
- permalink = result["permalink"]
60
- date = result["scan_date"]
61
- md5 = result["md5"]
62
- sha1 = result["sha1"]
63
- sha256 = result["sha256"]
64
-
65
- result["scans"].each do |scanner, value|
66
- if value != ''
67
- res = Hash.new
68
- res['hash'] = hash
69
- res['md5'] = md5
70
- res['sha1'] = sha1
71
- res['sha256'] = sha256
72
- res['scanner'] = scanner
73
- res['detected'] = value["detected"]
74
- res['version'] = value["version"]
75
-
76
- if value["result"] == nil
77
- res['result'] = "Nothing detected"
78
- else
79
- res['result'] = value["result"]
48
+ # Results will be an array of: [ [resource, result hash ] ]
49
+ results.each do |entry|
50
+ hash = entry.first # Grab the resource (checksum hash)
51
+ result = entry.last # Grab the query report
52
+
53
+ if result['response_code'] == 0
54
+ res = Hash.new
55
+ RESULT_FIELDS.each{|field| res[field] = '-' }
56
+ res['result'] = result['verbose_msg']
57
+ @results.push res
58
+
59
+ elsif result['response_code'] == 0
60
+ abort "[!] Invalid API KEY! Please correct this! Check ~/.uirusu"
61
+ else
62
+ permalink = result['permalink']
63
+ date = result['scan_date']
64
+ md5 = result['md5']
65
+ sha1 = result['sha1']
66
+ sha256 = result['sha256']
67
+
68
+ result['scans'].each do |scanner, value|
69
+ if value != ''
70
+ res = Hash.new
71
+ res[:hash] = hash
72
+ res[:md5] = md5
73
+ res[:sha1] = sha1
74
+ res[:sha256] = sha256
75
+ res[:scanner] = scanner
76
+ res[:detected] = value['detected']
77
+ res[:version] = value['version']
78
+
79
+ if value['result'] == nil
80
+ res[:result] = "Nothing detected"
81
+ else
82
+ res[:result] = value['result']
83
+ end
84
+
85
+ res[:update] = value['update']
86
+ res[:permalink] = permalink unless permalink == nil
87
+
88
+ @results.push res
80
89
  end
81
-
82
- res['update'] = value['update']
83
- res['permalink'] = permalink unless permalink == nil
84
-
85
- @results.push res
86
90
  end
87
91
  end
88
92
  end
@@ -90,17 +94,8 @@ module Uirusu
90
94
  #if we didn't have any results lets create a fake not found
91
95
  if @results.size == 0
92
96
  res = Hash.new
93
- res['hash'] = hash
94
- res['scanner'] = '-'
95
- res['md5'] = '-'
96
- res['sha1'] = '-'
97
- res['sha256'] = '-'
98
- res['permalink'] = '-'
99
- res['detected'] = '-'
100
- res['version'] = '-'
101
- res['result'] = '-'
102
- res['update'] = '-'
103
- res['result'] = result["verbose_msg"]
97
+ RESULT_FIELDS.each{|field| res[field] = '-' }
98
+ res['result'] = result['verbose_msg']
104
99
  @results.push res
105
100
  end
106
101
  end
@@ -109,52 +104,46 @@ module Uirusu
109
104
  #
110
105
  def to_stdout
111
106
  result_string = String.new
112
- @results.each do |result|
113
- result_string << "#{result['hash']}: Scanner: #{result['scanner']} Result: #{result['result']}\n"
107
+ hashes = Array.new
108
+
109
+ @results.sort_by {|k| k[:scanner] }.each do |result|
110
+ unless hashes.include? result[:hash].downcase
111
+ result_string << "#{result[:hash]}:\n"
112
+ hashes << result[:hash].downcase
113
+ end
114
+ result_string << "#{result[:scanner]}: ".rjust(25) + "#{result[:result]}\n"
114
115
  end if @results != nil
115
116
 
116
- print result_string
117
+ result_string
117
118
  end
118
119
 
119
120
  #
120
121
  #
121
- def to_yaml
122
- result_string = String.new
123
- @results.each do |result|
124
- result_string << "vtresult:\n"
125
- result_string << " hash: #{result['hash']}\n"
126
- result_string << " md5: #{result['md5']}\n"
127
- result_string << " sha1: #{result['sha1']}\n"
128
- result_string << " sha256: #{result['sha256']}\n"
129
- result_string << " scanner: #{result['scanner']}\n"
130
- result_string << " detected: #{result['detected']}\n"
131
- result_string << " date: #{result['date']}\n"
132
- result_string << " permalink: #{result['permalink']}\n" unless result['permalink'] == nil
133
- result_string << " result: #{result['result']}\n\n"
134
- end if @results != nil
122
+ def to_json
123
+ JSON::pretty_generate(@results.map{|entry| { :vtresult => entry } })
124
+ end
135
125
 
136
- print result_string
126
+ #
127
+ #
128
+ def to_yaml
129
+ @results.map{|entry| { :vtresult => entry } }.to_yaml
137
130
  end
138
131
 
139
132
  #
140
133
  #
141
134
  def to_xml
142
135
  result_string = String.new
136
+ result_string << "<results>\n"
143
137
  @results.each do |result|
144
138
  result_string << "\t<vtresult>\n"
145
- result_string << "\t\t<hash>#{result['hash']}</hash>\n"
146
- result_string << "\t\t<md5>#{result['md5']}</md5>\n"
147
- result_string << "\t\t<sha1>#{result['sha1']}</sha1>\n"
148
- result_string << "\t\t<sha256>#{result['sha256']}</sha256>\n"
149
- result_string << "\t\t<scanner>#{result['scanner']}</scanner>\n"
150
- result_string << "\t\t<detected>#{result['detected']}</detected>\n"
151
- result_string << "\t\t<date>#{result['date']}</date>\n"
152
- result_string << "\t\t<permalink>#{result['permalink']}</permalink>\n" unless result['permalink'] == nil
153
- result_string << "\t\t<result>#{result['result']}</result>\n"
139
+ RESULT_FIELDS.each{|field|
140
+ result_string << "\t\t<#{field.to_s}>#{result[field]}</#{field.to_s}>\n" unless field == :permalink and result['permalink'].nil?
141
+ }
154
142
  result_string << "\t</vtresult>\n"
155
143
  end if @results != nil
144
+ result_string << "</results>\n"
156
145
 
157
- print result_string
146
+ result_string
158
147
  end
159
148
  end
160
149
  end
data/lib/uirusu/vturl.rb CHANGED
@@ -30,8 +30,8 @@ module Uirusu
30
30
  #
31
31
  #
32
32
  module VTUrl
33
- SCAN_URL = "https://www.virustotal.com/vtapi/v2/url/scan"
34
- REPORT_URL = "http://www.virustotal.com/vtapi/v2/url/report"
33
+ SCAN_URL = Uirusu::VT_API + "/url/scan"
34
+ REPORT_URL = Uirusu::VT_API + "/url/report"
35
35
 
36
36
  # Submits a URL to be scanned by Virustotal.com
37
37
  #
@@ -91,4 +91,5 @@ module Uirusu
91
91
  end
92
92
  end
93
93
  end
94
- end
94
+ end
95
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uirusu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Hammack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-09 00:00:00.000000000 Z
11
+ date: 2013-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json