clam_scan 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea305456c7f41d11c6dc629ccf15ad6807ebc127
4
+ data.tar.gz: d6e2cb317c9e6d053f5ec1e60d7fd55414f3abea
5
+ SHA512:
6
+ metadata.gz: b6db45f5403778c1209dac018f95d073aaa6cddc8bbcc2589dbdb1179b71f802761f16388972ab92f4cf5c8d0f0ccbf6be86f8fe25810d380573d4c8ec6ea73e
7
+ data.tar.gz: ffeab6f0d74d3d5c7439cfbbf12330c0ce271d17b001aa4a4382749be31a20e00856d6e01aba2cec6791c29dbe2dc8a863d44f940a012e391a5e6d4baa9f7b61
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ spec/data/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in clam_scan.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 John Schroeder
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ # ClamScan
2
+
3
+ Ruby wrapper for ClamAV's clamscan/clamdscan.
4
+
5
+ ## Features
6
+
7
+ * Lightweight pure-ruby wrapper
8
+ * System call arguments always properly escaped with `IO.popen`
9
+ * Scan a data stream before writing to disk
10
+ * Supports and validates all arguments supported by clamscan/clamdscan
11
+
12
+ ## Installation
13
+
14
+ ### Gem
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'clam_scan'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install clam_scan
29
+
30
+ ### ClamAV
31
+
32
+ You will also need ClamAV (and optionally the ClamAV daemon) installed. On Ubuntu:
33
+
34
+ `$ sudo apt-get install clamav` will install ClamAV and the `clamscan` cli client.
35
+
36
+ `$ sudo apt-get install clamav-daemon` will install the ClamAV daemon and the 'clamdscan' cli client.
37
+
38
+ Other *nix systems can do the equivalent from their respective package manager or install from source. Mac users should be able to something equivalent with homebrew. Windows... good luck.
39
+
40
+ If you _really_ have an aversion to installing the daemon on your development machine, that's OK, but be aware that using the daemon can be literally thousands of orders of magnitude faster for scanning small files because it doesn't have to load the virus database every time a scan is initiated. You'll also need to set `client_location` to point to clamscan (see below).
41
+
42
+ ## Usage
43
+
44
+ ### Configuration
45
+
46
+ ```ruby
47
+ ClamScan.configure do |config|
48
+ # provide default options to be passed to ClamScan::Client.scan
49
+ # options passed directly to a call to ClamScan::Client.scan will override these
50
+ # by merging the default options with the passed options
51
+ config.default_scan_options = {stdout: true} # default (request all output to be sent to STDOUT so it can be captured)
52
+
53
+ # path to clamscan/clamdscan client
54
+ # try `which clamdscan` or `which clamscan` in your shell to see where you should point this to
55
+ # recommended to set to an absolute path to clamdscan
56
+ config.client_location = '/usr/bin/clamdscan' # default
57
+
58
+ # if set to true, ClamScan will raise an exception
59
+ # unless a scan is successful and no viruses were found
60
+ config.raise_unless_safe = false # default
61
+ end
62
+ ```
63
+
64
+ ### Example Code
65
+
66
+ ```ruby
67
+ # scan file on disk
68
+ options = {location: '/path/to/file'}
69
+
70
+ # scan data stream
71
+ options = {stream: some_binary_data}
72
+
73
+ # initiate scan - returns ClamScan::Response object
74
+ respone = ClamScan::Client.scan(options)
75
+
76
+ # check output from clamscan
77
+ puts response.body
78
+
79
+ # check response status
80
+ response.safe? # true if scan was successful and no virus was found
81
+ response.virus? # true if scan was successful an virus was found
82
+ response.error? # true if scan returned with a known error status
83
+ response.unknown? # true if scan returned with an unknown status
84
+ response.status # one of [:error, :safe, :unknown, :virus]
85
+
86
+ # short snippet appropriate for most situations
87
+ unless ClamScan::Client.scan(location: '/path/to/file').safe?
88
+ # do something
89
+ end
90
+ ```
91
+
92
+ ### Advanced Usage
93
+
94
+ ClamScan supports and validates any options supported by the clamscan cli client. The convention when passing options to ClamScan is to remove the first two leading hyphens and chang the remaining hyphens to underscores.
95
+
96
+ ```ruby
97
+ # equivalent to `clamscan --recursive --max-recursion=5 /path/to/dir`
98
+ ClamScan::Client.scan(location: '/path/to/dir', recursive: true, max_recursion: 5)
99
+ ```
100
+
101
+ You can also pass an array of custom options that will not be validated.
102
+
103
+ ```ruby
104
+ # equivalent to `clamscan --recursive --max-recursion=5 /path/to/dir`
105
+ args = ['--recursive', '--max-recursion=5', '/path/to'dir']
106
+ ClamScan::Client.scan(custom_args: args)
107
+ ```
108
+
109
+ ClamScan _should_ support and validate any arguments supported by ClamAV 0.98. See lib/request.rb and ClamAV's man page.
110
+
111
+ ### Deleting infected files
112
+
113
+ ClamScan does _not_ delete infected files by default, conforming with the defaults of clamscan/clamdscan. If you want that behaviour, you can do something like:
114
+
115
+ ```ruby
116
+ ClamScan.configure do |config|
117
+ # merge instead of re-assign so as to not blow away {stdout: true} default
118
+ config.default_scan_options.merge {remove: 'yes'}
119
+ end
120
+ ```
121
+
122
+ Or you could arrange to have them moved or copied somewhere. See `man clamscan`.
123
+
124
+ ### Exceptions
125
+
126
+ Any exception raised by ClamScan _should_ be a subclass of `ClamScan::Error`.
127
+
128
+ If an unrecognized option is passed to `ClamScan::Client::scan` or an error occurs while making attempting to make the system call, a `ClamScan::RequestError` is raised.
129
+
130
+ If `config.raise_unless_safe` is true, a `ClamScan::VirusDetected`, `ClamScan::UnknownError` or `ClamScan::ResponseError` could be raised. The first two are subclasses of the last and all have a `response` attribute that contains a `ClamScan::Response` object that can be further inspected.
131
+
132
+ ### Rails
133
+
134
+ ClamScan is a pure ruby wrapper and thus can be used in any ruby project, including one using rails.
135
+
136
+ ```ruby
137
+ # add virus-free validation with carrierwave
138
+ validate :virus_free
139
+
140
+ def virus_free
141
+ if self.file.present? && !ClamScan::Client.scan(location: self.file.url).safe?
142
+ File.delete(self.file.url)
143
+ errors.add(:file, 'That file can not be accepted')
144
+ end
145
+ end
146
+ ```
147
+
148
+ ## Contributing
149
+
150
+ 1. Fork it ( https://github.com/jschroeder9000/clam_scan/fork )
151
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
152
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
153
+ 4. Push to the branch (`git push origin my-new-feature`)
154
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'clam_scan/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "clam_scan"
8
+ spec.version = ClamScan::VERSION
9
+ spec.authors = ["John Schroeder"]
10
+ spec.email = ["jschroeder@multiadsolutions.com"]
11
+ spec.summary = %q{Ruby wrapper for ClamAV's clamscan/clamdscan.}
12
+ spec.description = %q{Ruby wrapper for ClamAV's clamscan/clamdscan.}
13
+ spec.homepage = "https://github.com/jschroeder9000/clam_scan"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,20 @@
1
+ require "clam_scan/client"
2
+ require "clam_scan/configuration"
3
+ require "clam_scan/exceptions"
4
+ require "clam_scan/request"
5
+ require "clam_scan/response"
6
+ require "clam_scan/version"
7
+
8
+ module ClamScan
9
+ @@configuration = Configuration.new
10
+
11
+ def self.configure
12
+ yield @@configuration if block_given?
13
+ end
14
+
15
+ def self.configuration
16
+ @@configuration
17
+ end
18
+
19
+ configure
20
+ end
@@ -0,0 +1,21 @@
1
+ module ClamScan
2
+ class Client
3
+ class << self
4
+ def scan (opts={})
5
+ response = Request.send(opts)
6
+
7
+ if ::ClamScan.configuration.raise_unless_safe
8
+ if response.virus?
9
+ raise VirusDetected.new(response)
10
+ elsif response.unknown?
11
+ raise UnknownError.new(response)
12
+ elsif !response.safe?
13
+ raise ResponseError.new(response)
14
+ end
15
+ end
16
+
17
+ response
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module ClamScan
2
+ class Configuration
3
+ attr_accessor :default_scan_options
4
+ attr_accessor :client_location
5
+ attr_accessor :raise_unless_safe
6
+
7
+ def initialize
8
+ @default_scan_options = {stdout: true}
9
+ @client_location = '/usr/bin/clamdscan'
10
+ @raise_unless_safe = false
11
+ end
12
+
13
+ def reset!
14
+ initialize
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ module ClamScan
2
+ class Error < StandardError
3
+ end
4
+
5
+ class RequestError < Error
6
+ end
7
+
8
+ class ResponseError < Error
9
+ attr_reader :response
10
+
11
+ def initialize (response, message=nil)
12
+ @response = response
13
+ message ||= response.body
14
+ super(message)
15
+ end
16
+ end
17
+
18
+ class UnknownError < ResponseError
19
+ def initialize (response, message=nil)
20
+ message ||= response.body
21
+ message = "An unknown error caused #{::ClamScan.configuration.client_location} to exit with status #{response.process_status.exitstatus.to_s}\n#{message}"
22
+ super(response, message)
23
+ end
24
+ end
25
+
26
+ class VirusDetected < ResponseError
27
+ end
28
+ end
@@ -0,0 +1,128 @@
1
+ module ClamScan
2
+ class Request
3
+ class << self
4
+ def send (opts={})
5
+ output_lines = []
6
+
7
+ begin
8
+ IO.popen(popen_args(opts), 'r+') do |f|
9
+ if opts[:stream]
10
+ f.write opts[:stream]
11
+ f.close_write
12
+ end
13
+ while line = f.gets
14
+ output_lines << line
15
+ end
16
+ end
17
+ rescue SystemCallError => e
18
+ raise RequestError, "An error occured while making system call to #{::ClamScan.configuration.client_location}: #{e.to_s}"
19
+ end
20
+
21
+ output_string = output_lines.join("\n")
22
+ Response.new($?, output_string)
23
+ end
24
+
25
+ private
26
+
27
+ BOOLEAN_ARGS = %w(
28
+ allmatch
29
+ bell
30
+ infected
31
+ leave_temps
32
+ no_summary
33
+ quiet
34
+ recursive
35
+ stdout
36
+ verbose
37
+ )
38
+
39
+ IGNORE_ARGS = %w(
40
+ custom_args
41
+ location
42
+ stream
43
+ )
44
+
45
+ VALUE_ARGS = %w(
46
+ algorithmic_detection
47
+ block_encrypted
48
+ bytecode
49
+ bytecode_statistics
50
+ bytecode_timeout
51
+ bytecode_unsigned
52
+ copy
53
+ cross_fs
54
+ database
55
+ detect_broken
56
+ detect_pua
57
+ detect_structured
58
+ exclude
59
+ exclude_dir
60
+ exclude_pua
61
+ file_list
62
+ follow_dir_symlinks
63
+ follow_file_symlinks
64
+ heuristic_scan_precedence
65
+ include
66
+ include_dir
67
+ include_pua
68
+ log
69
+ max_dir_recursion
70
+ max_files
71
+ max_filesize
72
+ max_recursion
73
+ max_scansize
74
+ move
75
+ official_db_only
76
+ phishing_cloak
77
+ phishing_scan_urls
78
+ phishing_sigs
79
+ phishing_ssl
80
+ remove
81
+ scan_archive
82
+ scan_elf
83
+ scan_html
84
+ scan_mail
85
+ scan_ole2
86
+ scan_pdf
87
+ scan_pe
88
+ structured_cc_count
89
+ structured_ssn_count
90
+ structured_ssn_format
91
+ tempdir
92
+ )
93
+
94
+ def argify (key, value=nil)
95
+ "--#{key.gsub('_', '-')}" + (value ? "=#{value}" : '')
96
+ end
97
+
98
+ def popen_args (opts={})
99
+ args = [::ClamScan.configuration.client_location]
100
+
101
+ if opts[:custom_args]
102
+ args += opts[:custom_args]
103
+ else
104
+ opts = ::ClamScan.configuration.default_scan_options.merge(opts)
105
+
106
+ opts.each do |key, value|
107
+ key_string = key.to_s
108
+
109
+ if BOOLEAN_ARGS.include? key_string
110
+ args << argify(key_string) if value
111
+ elsif VALUE_ARGS.include? key_string
112
+ args << argify(key_string, value) if value
113
+ elsif IGNORE_ARGS.include? key_string
114
+ # do nothing
115
+ else
116
+ raise RequestError, "Invalid option: #{key}"
117
+ end
118
+ end
119
+
120
+ args << opts[:location] if opts[:location]
121
+ args << '-' if opts[:stream]
122
+ end
123
+
124
+ args
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,44 @@
1
+ module ClamScan
2
+ class Response
3
+ attr_accessor :output
4
+ attr_accessor :process_status
5
+
6
+ def initialize (process_status, output)
7
+ @output = output
8
+ @process_status = process_status
9
+ end
10
+
11
+ def body
12
+ @output
13
+ end
14
+
15
+ def error?
16
+ status == :error
17
+ end
18
+
19
+ def safe?
20
+ status == :safe
21
+ end
22
+
23
+ def status
24
+ case @process_status.exitstatus
25
+ when 0
26
+ :safe
27
+ when 1
28
+ :virus
29
+ when 2
30
+ :error
31
+ else
32
+ :unknown
33
+ end
34
+ end
35
+
36
+ def unknown?
37
+ status == :unknown
38
+ end
39
+
40
+ def virus?
41
+ status == :virus
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module ClamScan
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe ClamScan do
4
+ context :error do
5
+ it 'raises ClamScan::RequestError if failure to make system call to client_location' do
6
+ ClamScan.configure do |config|
7
+ config.client_location = '/asdf/zxcv'
8
+ end
9
+ expect{scan_eicar}.to raise_error(ClamScan::RequestError)
10
+ end
11
+
12
+ it 'raises ClamScan::RequestError when scanning a non-existant path and raise_unless_safe is true' do
13
+ ClamScan.configure do |config|
14
+ config.raise_unless_safe = true
15
+ end
16
+ expect{scan(location: '/asdf/zxcv')}.to raise_error(ClamScan::ResponseError)
17
+ end
18
+
19
+ it 'raises ClamScan::RequestError if an unrecognized option is passed' do
20
+ expect{ClamScan::Client.scan(loaction: eicar_path)}.to raise_error(ClamScan::RequestError)
21
+ end
22
+
23
+ it 'raises ClamScan::VirusDetected if virus is detected when raise_unless_safe is true' do
24
+ ClamScan.configure do |config|
25
+ config.raise_unless_safe = true
26
+ end
27
+ expect{scan_eicar}.to raise_error(ClamScan::VirusDetected)
28
+ end
29
+
30
+ it 'returns true for error? when scanning a non-existant path' do
31
+ expect(scan(location: '/asdf/zxcv').error?).to be_truthy
32
+ end
33
+
34
+ it 'has status of :error when scanning a non-existant path' do
35
+ expect(scan(location: '/asdf/zxcv').status).to eq(:error)
36
+ end
37
+ end
38
+
39
+ context :safe do
40
+ before :each do
41
+ @response = scan_safe
42
+ end
43
+
44
+ it 'returns false for error?' do
45
+ expect(@response.error?).to be_falsey
46
+ end
47
+
48
+ it 'returns true for safe?' do
49
+ expect(@response.safe?).to be_truthy
50
+ end
51
+
52
+ it 'returns false for unknown?' do
53
+ expect(@response.unknown?).to be_falsey
54
+ end
55
+
56
+ it 'returns false for virus?' do
57
+ expect(@response.virus?).to be_falsey
58
+ end
59
+
60
+ it 'has status of :safe' do
61
+ expect(@response.status).to eq(:safe)
62
+ end
63
+ end
64
+
65
+ context :streaming do
66
+ it 'detects safety from streamed data' do
67
+ expect(scan(stream: File.read(safe_path)).safe?).to be_truthy
68
+ end
69
+
70
+ it 'detects a virus from streamed data' do
71
+ expect(scan(stream: File.read(eicar_path)).virus?).to be_truthy
72
+ end
73
+ end
74
+
75
+ context :virus do
76
+ before :each do
77
+ @response = scan_eicar
78
+ end
79
+
80
+ it 'returns false for error?' do
81
+ expect(@response.error?).to be_falsey
82
+ end
83
+
84
+ it 'returns false for safe?' do
85
+ expect(@response.safe?).to be_falsey
86
+ end
87
+
88
+ it 'returns false for unknown?' do
89
+ expect(@response.unknown?).to be_falsey
90
+ end
91
+
92
+ it 'returns true for virus?' do
93
+ expect(@response.virus?).to be_truthy
94
+ end
95
+
96
+ it 'has status of :virus' do
97
+ expect(@response.status).to eq(:virus)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,120 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+
18
+ # end intro stuff
19
+
20
+ require 'clam_scan'
21
+
22
+ Dir[File.expand_path(File.join('..', 'support', '**', '*.rb'), __FILE__)].each { |f| require f }
23
+
24
+ RSpec.configure do |config|
25
+ # The settings below are suggested to provide a good initial experience
26
+ # with RSpec, but feel free to customize to your heart's content.
27
+
28
+ # These two settings work together to allow you to limit a spec run
29
+ # to individual examples or groups you care about by tagging them with
30
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
31
+ # get run.
32
+ config.filter_run :focus
33
+ config.run_all_when_everything_filtered = true
34
+
35
+ # Many RSpec users commonly either run the entire suite or an individual
36
+ # file, and it's useful to allow more verbose output when running an
37
+ # individual spec file.
38
+ if config.files_to_run.one?
39
+ # Use the documentation formatter for detailed output,
40
+ # unless a formatter has already been configured
41
+ # (e.g. via a command-line flag).
42
+ config.default_formatter = 'doc'
43
+ end
44
+
45
+ # Print the 10 slowest examples and example groups at the
46
+ # end of the spec run, to help surface which specs are running
47
+ # particularly slow.
48
+ config.profile_examples = 10
49
+
50
+ # Run specs in random order to surface order dependencies. If you find an
51
+ # order dependency and want to debug it, you can fix the order by providing
52
+ # the seed, which is printed after each run.
53
+ # --seed 1234
54
+ config.order = :random
55
+
56
+ # Seed global randomization in this process using the `--seed` CLI option.
57
+ # Setting this allows you to use `--seed` to deterministically reproduce
58
+ # test failures related to randomization by passing the same `--seed` value
59
+ # as the one that triggered the failure.
60
+ Kernel.srand config.seed
61
+
62
+ # rspec-expectations config goes here. You can use an alternate
63
+ # assertion/expectation library such as wrong or the stdlib/minitest
64
+ # assertions if you prefer.
65
+ config.expect_with :rspec do |expectations|
66
+ # Enable only the newer, non-monkey-patching expect syntax.
67
+ # For more details, see:
68
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
69
+ expectations.syntax = :expect
70
+ end
71
+
72
+ # rspec-mocks config goes here. You can use an alternate test double
73
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
74
+ config.mock_with :rspec do |mocks|
75
+ # Enable only the newer, non-monkey-patching expect syntax.
76
+ # For more details, see:
77
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
+ mocks.syntax = :expect
79
+
80
+ # Prevents you from mocking or stubbing a method that does not exist on
81
+ # a real object. This is generally recommended.
82
+ mocks.verify_partial_doubles = true
83
+ end
84
+
85
+ # end default init stuff
86
+
87
+ config.before(:suite) do
88
+ # make data dir if it doesn't exist
89
+ unless File.directory? data_path
90
+ require 'fileutils'
91
+ FileUtils.mkdir_p data_path
92
+ end
93
+
94
+ # get eicar sample file if we don't have it
95
+ unless File.exist? eicar_path
96
+ require 'net/http'
97
+ Net::HTTP.start('www.eicar.org') do |http|
98
+ resp = http.get('/download/eicar.com')
99
+ File.open(eicar_path, 'wb') do |file|
100
+ file.write(resp.body)
101
+ end
102
+ end
103
+ end
104
+
105
+ # make a safe file if we don't have it
106
+ unless File.exist? safe_path
107
+ File.open(safe_path, 'w') do |file|
108
+ file.write 'bar'
109
+ end
110
+ end
111
+ end
112
+
113
+ config.before(:each) do
114
+ # reset to sane defaults, maybe override from ENV
115
+ ClamScan.configure do |clam_config|
116
+ clam_config.reset!
117
+ clam_config.client_location = 'clamdscan'
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,11 @@
1
+ def data_path
2
+ File.expand_path(File.join('..', '..', 'data'), __FILE__)
3
+ end
4
+
5
+ def eicar_path
6
+ File.join(data_path, 'eicar.com')
7
+ end
8
+
9
+ def safe_path
10
+ File.join(data_path, 'foo.txt')
11
+ end
@@ -0,0 +1,11 @@
1
+ def scan (opts={})
2
+ ClamScan::Client.scan(opts)
3
+ end
4
+
5
+ def scan_eicar
6
+ scan(location: eicar_path)
7
+ end
8
+
9
+ def scan_safe
10
+ scan(location: safe_path)
11
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clam_scan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John Schroeder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Ruby wrapper for ClamAV's clamscan/clamdscan.
56
+ email:
57
+ - jschroeder@multiadsolutions.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - clam_scan.gemspec
69
+ - lib/clam_scan.rb
70
+ - lib/clam_scan/client.rb
71
+ - lib/clam_scan/configuration.rb
72
+ - lib/clam_scan/exceptions.rb
73
+ - lib/clam_scan/request.rb
74
+ - lib/clam_scan/response.rb
75
+ - lib/clam_scan/version.rb
76
+ - spec/clam_scan_spec.rb
77
+ - spec/spec_helper.rb
78
+ - spec/support/data.rb
79
+ - spec/support/scan.rb
80
+ homepage: https://github.com/jschroeder9000/clam_scan
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.2.2
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby wrapper for ClamAV's clamscan/clamdscan.
104
+ test_files:
105
+ - spec/clam_scan_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/data.rb
108
+ - spec/support/scan.rb