hydra-works 0.10.0 → 0.11.0
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/lib/hydra/works.rb +7 -0
- data/lib/hydra/works/services/virus_checker_service.rb +3 -36
- data/lib/hydra/works/version.rb +1 -1
- data/lib/hydra/works/virus_scanner.rb +56 -0
- data/spec/hydra/works/services/virus_checker_service_spec.rb +5 -48
- data/spec/hydra/works/virus_scanner_spec.rb +48 -0
- data/spec/hydra/works_spec.rb +5 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ab0358efa05c2000773dbf94f9fdce307613889
|
4
|
+
data.tar.gz: 15dddd5f77310395add9882e5cf2887135bf0721
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2063fa30e2d4f5d26cd34d8b6968bcb046b414375a3c704974f10678630f4d72bf4bc92cec360734b6119c539b30eb28c3143b544cf7d9026e7b75d5ee95d151
|
7
|
+
data.tar.gz: 9002fa2a214853d15d44ff95eb96009d8d78c0a3e6bc826309d0bb7475cc0de7b69c7c4a9d69a8c6d5aa27433d3d152a200ba246e56faa35c7986483d00ac8db
|
data/lib/hydra/works.rb
CHANGED
@@ -6,6 +6,13 @@ module Hydra
|
|
6
6
|
module Works
|
7
7
|
extend ActiveSupport::Autoload
|
8
8
|
|
9
|
+
autoload :VirusScanner
|
10
|
+
|
11
|
+
class << self
|
12
|
+
class_attribute :default_system_virus_scanner
|
13
|
+
self.default_system_virus_scanner = VirusScanner
|
14
|
+
end
|
15
|
+
|
9
16
|
module Vocab
|
10
17
|
extend ActiveSupport::Autoload
|
11
18
|
eager_autoload do
|
@@ -6,14 +6,12 @@ module Hydra::Works
|
|
6
6
|
|
7
7
|
# @api public
|
8
8
|
# @param original_file [String, #path]
|
9
|
-
# @return true
|
10
|
-
# @return true if anti-virus was not able to run
|
11
|
-
# @return false if the file was scanned and no viruses were found
|
9
|
+
# @return true or false result from system_virus_scanner
|
12
10
|
def self.file_has_virus?(original_file)
|
13
11
|
new(original_file).file_has_virus?
|
14
12
|
end
|
15
13
|
|
16
|
-
def initialize(original_file, system_virus_scanner = default_system_virus_scanner)
|
14
|
+
def initialize(original_file, system_virus_scanner = Hydra::Works.default_system_virus_scanner)
|
17
15
|
self.original_file = original_file
|
18
16
|
self.system_virus_scanner = system_virus_scanner
|
19
17
|
end
|
@@ -21,42 +19,11 @@ module Hydra::Works
|
|
21
19
|
# Default behavior is to raise a validation error and halt the save if a virus is found
|
22
20
|
def file_has_virus?
|
23
21
|
path = original_file.is_a?(String) ? original_file : local_path_for_file(original_file)
|
24
|
-
|
25
|
-
handle_virus_scan_results(path, scan_result)
|
22
|
+
system_virus_scanner.infected?(path)
|
26
23
|
end
|
27
24
|
|
28
25
|
private
|
29
26
|
|
30
|
-
# Stubbing out the behavior of "The Clam" was growing into a rather nasty
|
31
|
-
# challenge. So instead I'm injecting a system scanner. This allows me to
|
32
|
-
# now test the default system scanner in isolation from the general response
|
33
|
-
# to a system scan.
|
34
|
-
def default_system_virus_scanner
|
35
|
-
if defined?(ClamAV)
|
36
|
-
ClamAV.instance.method(:scanfile)
|
37
|
-
else
|
38
|
-
lambda do |_path|
|
39
|
-
:no_anti_virus_was_run
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def handle_virus_scan_results(path, scan_result)
|
45
|
-
case scan_result
|
46
|
-
when 0 then return false
|
47
|
-
when 1
|
48
|
-
warning("A virus was found in #{path}: #{scan_result}")
|
49
|
-
true
|
50
|
-
else
|
51
|
-
warning "Virus checking disabled, #{path} not checked"
|
52
|
-
true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def warning(msg)
|
57
|
-
ActiveFedora::Base.logger.warn msg if ActiveFedora::Base.logger
|
58
|
-
end
|
59
|
-
|
60
27
|
# Returns a path for reading the content of +file+
|
61
28
|
# @param [File] file object to retrieve a path for
|
62
29
|
def local_path_for_file(file)
|
data/lib/hydra/works/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# The default virus scanner for Hydra::Works
|
2
|
+
# If ClamAV is present, it will be used to check for the presence of a virus. If ClamAV is not
|
3
|
+
# installed or otherwise not available to your application, Hydra::Works does no virus checking
|
4
|
+
# add assumes files have no viruses.
|
5
|
+
#
|
6
|
+
# To use a virus checker other than ClamAV:
|
7
|
+
# class MyScanner < Hydra::Works::VirusScanner
|
8
|
+
# def infected?
|
9
|
+
# my_result = Scanner.check_for_viruses(file)
|
10
|
+
# [return true or false]
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# Then set Hydra::Works to use your scanner either in a config file or initializer:
|
15
|
+
# Hydra::Works.default_system_virus_scanner = MyScanner
|
16
|
+
module Hydra::Works
|
17
|
+
class VirusScanner
|
18
|
+
attr_reader :file
|
19
|
+
|
20
|
+
# @api public
|
21
|
+
# @param file [String]
|
22
|
+
def self.infected?(file)
|
23
|
+
new(file).infected?
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(file)
|
27
|
+
@file = file
|
28
|
+
end
|
29
|
+
|
30
|
+
# Override this method to use your own virus checking software
|
31
|
+
# @return [Boolean]
|
32
|
+
def infected?
|
33
|
+
defined?(ClamAV) ? clam_av_scanner : null_scanner
|
34
|
+
end
|
35
|
+
|
36
|
+
def clam_av_scanner
|
37
|
+
scan_result = ClamAV.instance.method(:scanfile).call(file)
|
38
|
+
return false if scan_result == 0
|
39
|
+
warning "A virus was found in #{file}: #{scan_result}"
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Always return zero if there's nothing available to check for viruses. This means that
|
44
|
+
# we assume all files have no viruses because we can't conclusively say if they have or not.
|
45
|
+
def null_scanner
|
46
|
+
warning "Unable to check #{file} for viruses because no virus scanner is defined"
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def warning(msg)
|
53
|
+
ActiveFedora::Base.logger.warn(msg) if ActiveFedora::Base.logger
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Hydra::Works::VirusCheckerService do
|
4
|
-
let(:system_virus_scanner) { double
|
4
|
+
let(:system_virus_scanner) { double }
|
5
5
|
let(:file) { Hydra::PCDM::File.new { |f| f.content = File.new(File.join(fixture_path, 'sample-file.pdf')) } }
|
6
6
|
let(:virus_checker) { described_class.new(file, system_virus_scanner) }
|
7
7
|
|
@@ -14,27 +14,17 @@ describe Hydra::Works::VirusCheckerService do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
context 'with a system virus scanner that did not run' do
|
18
|
-
let(:virus_checker) { described_class.new(file) }
|
19
|
-
it 'will return false and set a system warning' do
|
20
|
-
expect(defined?(ClamAV)).to eq(nil) # A bit of a sanity test to make sure the default behaves
|
21
|
-
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
22
|
-
expect(virus_checker).to receive(:warning).with(kind_of(String))
|
23
|
-
expect(virus_checker.file_has_virus?).to eq(true)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
17
|
context 'with an infected file' do
|
28
18
|
context 'that responds to :path' do
|
29
19
|
it 'will return false' do
|
30
|
-
expect(system_virus_scanner).to receive(:
|
20
|
+
expect(system_virus_scanner).to receive(:infected?).with('/tmp/file.pdf').and_return(true)
|
31
21
|
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
32
22
|
expect(virus_checker.file_has_virus?).to eq(true)
|
33
23
|
end
|
34
24
|
end
|
35
25
|
context 'that does not respond to :path' do
|
36
26
|
it 'will return false' do
|
37
|
-
expect(system_virus_scanner).to receive(:
|
27
|
+
expect(system_virus_scanner).to receive(:infected?).with(kind_of(String)).and_return(true)
|
38
28
|
allow(file).to receive(:respond_to?).and_call_original
|
39
29
|
allow(file).to receive(:respond_to?).with(:path).and_return(false)
|
40
30
|
expect(virus_checker.file_has_virus?).to eq(true)
|
@@ -45,51 +35,18 @@ describe Hydra::Works::VirusCheckerService do
|
|
45
35
|
context 'with a clean file' do
|
46
36
|
context 'that responds to :path' do
|
47
37
|
it 'will return true' do
|
48
|
-
expect(system_virus_scanner).to receive(:
|
38
|
+
expect(system_virus_scanner).to receive(:infected?).with('/tmp/file.pdf').and_return(false)
|
49
39
|
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
50
40
|
expect(virus_checker.file_has_virus?).to eq(false)
|
51
41
|
end
|
52
42
|
end
|
53
43
|
context 'that does not respond to :path' do
|
54
44
|
it 'will return true' do
|
55
|
-
expect(system_virus_scanner).to receive(:
|
45
|
+
expect(system_virus_scanner).to receive(:infected?).with(kind_of(String)).and_return(false)
|
56
46
|
allow(file).to receive(:respond_to?).and_call_original
|
57
47
|
allow(file).to receive(:respond_to?).with(:path).and_return(false)
|
58
48
|
expect(virus_checker.file_has_virus?).to eq(false)
|
59
49
|
end
|
60
50
|
end
|
61
51
|
end
|
62
|
-
|
63
|
-
context '#default_system_virus_scanner' do
|
64
|
-
let(:virus_checker) { described_class.new(file) }
|
65
|
-
let(:system_virus_scanner) { virus_checker.send(:default_system_virus_scanner) }
|
66
|
-
it 'is callable' do
|
67
|
-
expect(system_virus_scanner).to respond_to(:call)
|
68
|
-
end
|
69
|
-
context 'when called and ClamAV is NOT defined' do
|
70
|
-
it 'will warn and return :no_anti_virus_was_run if ClamAV is not defined' do
|
71
|
-
expect(system_virus_scanner.call('/tmp/path')).to eq(:no_anti_virus_was_run)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
context 'when called and ClamAV is defined' do
|
75
|
-
before do
|
76
|
-
class ClamAV
|
77
|
-
def self.instance
|
78
|
-
@instance ||= ClamAV.new
|
79
|
-
end
|
80
|
-
|
81
|
-
def scanfile(path)
|
82
|
-
puts "scanfile: #{path}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
after do
|
87
|
-
Object.send(:remove_const, :ClamAV)
|
88
|
-
end
|
89
|
-
it "will call the Clam's scanfile" do
|
90
|
-
expect(ClamAV.instance).to receive(:scanfile).with('/tmp/path')
|
91
|
-
system_virus_scanner.call('/tmp/path')
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
52
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hydra::Works::VirusScanner do
|
4
|
+
let(:file) { '/tmp/path' }
|
5
|
+
let(:logger) { Logger.new(nil) }
|
6
|
+
|
7
|
+
before { allow(ActiveFedora::Base).to receive(:logger).and_return(logger) }
|
8
|
+
|
9
|
+
subject { described_class.new(file) }
|
10
|
+
|
11
|
+
context 'when ClamAV is defined' do
|
12
|
+
before do
|
13
|
+
class ClamAV
|
14
|
+
def self.instance
|
15
|
+
@instance ||= ClamAV.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def scanfile(path)
|
19
|
+
puts "scanfile: #{path}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
after do
|
24
|
+
Object.send(:remove_const, :ClamAV)
|
25
|
+
end
|
26
|
+
context 'with a clean file' do
|
27
|
+
before { allow(ClamAV.instance).to receive(:scanfile).with('/tmp/path').and_return(0) }
|
28
|
+
it 'returns false with no warning' do
|
29
|
+
expect(ActiveFedora::Base.logger).not_to receive(:warn)
|
30
|
+
is_expected.not_to be_infected
|
31
|
+
end
|
32
|
+
end
|
33
|
+
context 'with an infected file' do
|
34
|
+
before { allow(ClamAV.instance).to receive(:scanfile).with('/tmp/path').and_return(1) }
|
35
|
+
it 'returns true with a warning' do
|
36
|
+
expect(ActiveFedora::Base.logger).to receive(:warn).with(kind_of(String))
|
37
|
+
is_expected.to be_infected
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when ClamAV is not defined' do
|
43
|
+
it 'returns false with a warning' do
|
44
|
+
expect(ActiveFedora::Base.logger).to receive(:warn).with(kind_of(String))
|
45
|
+
is_expected.not_to be_infected
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/spec/hydra/works_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra-works
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hydra-pcdm
|
@@ -217,6 +217,7 @@ files:
|
|
217
217
|
- lib/hydra/works/services/upload_file_to_file_set.rb
|
218
218
|
- lib/hydra/works/services/virus_checker_service.rb
|
219
219
|
- lib/hydra/works/version.rb
|
220
|
+
- lib/hydra/works/virus_scanner.rb
|
220
221
|
- lib/hydra/works/vocab/works_terms.rb
|
221
222
|
- solr/config/_rest_managed.json
|
222
223
|
- solr/config/admin-extra.html
|
@@ -270,6 +271,7 @@ files:
|
|
270
271
|
- spec/hydra/works/services/persist_derivatives_spec.rb
|
271
272
|
- spec/hydra/works/services/upload_file_spec.rb
|
272
273
|
- spec/hydra/works/services/virus_checker_service_spec.rb
|
274
|
+
- spec/hydra/works/virus_scanner_spec.rb
|
273
275
|
- spec/hydra/works_spec.rb
|
274
276
|
- spec/spec_helper.rb
|
275
277
|
- spec/support/file_set_helper.rb
|
@@ -302,7 +304,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
302
304
|
version: '0'
|
303
305
|
requirements: []
|
304
306
|
rubyforge_project:
|
305
|
-
rubygems_version: 2.
|
307
|
+
rubygems_version: 2.4.8
|
306
308
|
signing_key:
|
307
309
|
specification_version: 4
|
308
310
|
summary: Fundamental repository data model for hydra
|
@@ -343,6 +345,7 @@ test_files:
|
|
343
345
|
- spec/hydra/works/services/persist_derivatives_spec.rb
|
344
346
|
- spec/hydra/works/services/upload_file_spec.rb
|
345
347
|
- spec/hydra/works/services/virus_checker_service_spec.rb
|
348
|
+
- spec/hydra/works/virus_scanner_spec.rb
|
346
349
|
- spec/hydra/works_spec.rb
|
347
350
|
- spec/spec_helper.rb
|
348
351
|
- spec/support/file_set_helper.rb
|