ratonvirus 0.2.0 → 0.3.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/CHANGELOG.md +21 -0
- data/README.md +1 -1
- data/lib/ratonvirus.rb +1 -0
- data/lib/ratonvirus/error.rb +2 -0
- data/lib/ratonvirus/scanner/base.rb +2 -2
- data/lib/ratonvirus/scanner/eicar.rb +3 -3
- data/lib/ratonvirus/storage/active_storage.rb +5 -35
- data/lib/ratonvirus/storage/carrierwave.rb +14 -2
- data/lib/ratonvirus/storage/support/io_handling.rb +46 -0
- data/lib/ratonvirus/support/backend.rb +26 -25
- data/lib/ratonvirus/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a0ee734de35bb79c99398afaf866f42c87e023aa4ab813ee8e582f4a1ea89597
|
|
4
|
+
data.tar.gz: 3d15112835af1745bf61d7d7a0d6017a31b4e1d638211d26e909564baa19e733
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a663b2d27b3c98c8f4d83093cb87f4dc5f7ad87cdd8897358a923d1105ff69cfcd1bbb10831b657aad6d1bf1ef84a7b1ef42ed4817eccdb27782fbf081be3b7d
|
|
7
|
+
data.tar.gz: 5ba1e916ee109f4988c46c6bc325be84616af57f9a35b28390f55ea616b24a15de6a812d4dcbc58df11006b1d80b2636b4880c70abd45e517551392d64afc239
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# v0.3.0
|
|
2
|
+
|
|
3
|
+
Changed:
|
|
4
|
+
|
|
5
|
+
- Minimum Ruby version is now set to 2.5
|
|
6
|
+
|
|
7
|
+
Fixed:
|
|
8
|
+
|
|
9
|
+
- Issue related with scanning files with CarrierWave storage engine using remote storage engines such as Fog. Related
|
|
10
|
+
to [#9](https://github.com/mainio/ratonvirus/pull/9)
|
|
11
|
+
|
|
12
|
+
# v0.2.0
|
|
13
|
+
|
|
14
|
+
Support for Rails 6
|
|
15
|
+
|
|
16
|
+
The ActiveStorage storage engine has been updated and partly rewritten due to changes in its API. The new API introduces
|
|
17
|
+
a changes concept in the library which this update takes in to account. In the new API, the blobs will not get uploaded
|
|
18
|
+
to the storage service before the validations have been successful, which led to rethinking how this storage engine
|
|
19
|
+
works in Ratonvirus.
|
|
20
|
+
|
|
21
|
+
|
|
1
22
|
# v0.1.1
|
|
2
23
|
|
|
3
24
|
Fixed:
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Rails antivirus made easy.
|
|
4
4
|
Developed by [Mainio Tech](https://www.mainiotech.fi/).
|
|
5
5
|
|
|
6
|
-
[](https://github.com/mainio/ratonvirus/actions)
|
|
7
7
|
[](https://codecov.io/gh/mainio/ratonvirus)
|
|
8
8
|
|
|
9
9
|
Ratonvirus allows your Rails application to rat on the viruses that your users
|
data/lib/ratonvirus.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "ratonvirus/scanner/support/callbacks"
|
|
|
12
12
|
require_relative "ratonvirus/scanner/base"
|
|
13
13
|
require_relative "ratonvirus/scanner/eicar"
|
|
14
14
|
require_relative "ratonvirus/scanner/addon/remove_infected"
|
|
15
|
+
require_relative "ratonvirus/storage/support/io_handling"
|
|
15
16
|
require_relative "ratonvirus/storage/base"
|
|
16
17
|
require_relative "ratonvirus/storage/filepath"
|
|
17
18
|
require_relative "ratonvirus/storage/active_storage"
|
data/lib/ratonvirus/error.rb
CHANGED
|
@@ -11,8 +11,8 @@ module Ratonvirus
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
attr_reader :errors
|
|
14
|
+
# :errors - Only available after `virus?` has been called.
|
|
15
|
+
attr_reader :config, :errors
|
|
16
16
|
|
|
17
17
|
def initialize(configuration = {})
|
|
18
18
|
@config = default_config.merge!(configuration)
|
|
@@ -19,11 +19,11 @@ module Ratonvirus
|
|
|
19
19
|
protected
|
|
20
20
|
|
|
21
21
|
def run_scan(path)
|
|
22
|
-
if
|
|
23
|
-
errors << :antivirus_file_not_found
|
|
24
|
-
else
|
|
22
|
+
if File.file?(path)
|
|
25
23
|
sha256 = Digest::SHA256.file path
|
|
26
24
|
errors << :antivirus_virus_detected if sha256 == EICAR_SHA256
|
|
25
|
+
else
|
|
26
|
+
errors << :antivirus_file_not_found
|
|
27
27
|
end
|
|
28
28
|
rescue StandardError
|
|
29
29
|
errors << :antivirus_client_error
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Ratonvirus
|
|
4
4
|
module Storage
|
|
5
5
|
class ActiveStorage < Base
|
|
6
|
+
include Ratonvirus::Storage::Support::IoHandling
|
|
7
|
+
|
|
6
8
|
def changed?(record, attribute)
|
|
7
9
|
resource = record.public_send attribute
|
|
8
10
|
!resource.record.attachment_changes[resource.name].nil?
|
|
@@ -20,9 +22,10 @@ module Ratonvirus
|
|
|
20
22
|
|
|
21
23
|
change = resource.record.attachment_changes[resource.name]
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
case change
|
|
26
|
+
when ::ActiveStorage::Attached::Changes::CreateOne
|
|
24
27
|
handle_create_one(change, &block)
|
|
25
|
-
|
|
28
|
+
when ::ActiveStorage::Attached::Changes::CreateMany
|
|
26
29
|
handle_create_many(change, &block)
|
|
27
30
|
end
|
|
28
31
|
end
|
|
@@ -101,39 +104,6 @@ module Ratonvirus
|
|
|
101
104
|
|
|
102
105
|
yield processable([change.attachment, attachable])
|
|
103
106
|
end
|
|
104
|
-
|
|
105
|
-
# This creates a local copy of the io contents for the scanning process. A
|
|
106
|
-
# local copy is needed for processing because the io object may be a file
|
|
107
|
-
# stream in the memory which may not have a path associated with it on the
|
|
108
|
-
# filesystem.
|
|
109
|
-
def io_path(io, extension)
|
|
110
|
-
tempfile = Tempfile.open(
|
|
111
|
-
["Ratonvirus", extension],
|
|
112
|
-
tempdir
|
|
113
|
-
)
|
|
114
|
-
# Important for the scanner to be able to access the file.
|
|
115
|
-
prepare_for_scanner tempfile.path
|
|
116
|
-
|
|
117
|
-
begin
|
|
118
|
-
tempfile.binmode
|
|
119
|
-
IO.copy_stream(io, tempfile)
|
|
120
|
-
tempfile.flush
|
|
121
|
-
tempfile.rewind
|
|
122
|
-
|
|
123
|
-
yield tempfile.path
|
|
124
|
-
ensure
|
|
125
|
-
tempfile.close!
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def tempdir
|
|
130
|
-
Dir.tmpdir
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def prepare_for_scanner(filepath)
|
|
134
|
-
# Important for the scanner to be able to access the file.
|
|
135
|
-
File.chmod(0o644, filepath)
|
|
136
|
-
end
|
|
137
107
|
end
|
|
138
108
|
end
|
|
139
109
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Ratonvirus
|
|
4
4
|
module Storage
|
|
5
5
|
class Carrierwave < Base
|
|
6
|
+
include Ratonvirus::Storage::Support::IoHandling
|
|
7
|
+
|
|
6
8
|
def changed?(record, attribute)
|
|
7
9
|
record.public_send :"#{attribute}_changed?"
|
|
8
10
|
end
|
|
@@ -15,12 +17,22 @@ module Ratonvirus
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
def asset_path(asset)
|
|
20
|
+
def asset_path(asset, &block)
|
|
19
21
|
return unless block_given?
|
|
20
22
|
return if asset.nil?
|
|
21
23
|
return if asset.file.nil?
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
# If the file is a local SanitizedFile, it is faster to run the scan
|
|
26
|
+
# directly against that file instead of copying it to a tempfile first
|
|
27
|
+
# as below for external file storages.
|
|
28
|
+
return yield asset.file.path if asset.file.is_a?(::CarrierWave::SanitizedFile)
|
|
29
|
+
|
|
30
|
+
# The file could be externally stored, so we need to read it to memory
|
|
31
|
+
# in order to create a temporary file for the scanner to perform the
|
|
32
|
+
# scan on.
|
|
33
|
+
io = StringIO.new(asset.file.read)
|
|
34
|
+
ext = File.extname(asset.file.path)
|
|
35
|
+
io_path(io, ext, &block)
|
|
24
36
|
end
|
|
25
37
|
|
|
26
38
|
def asset_remove(asset)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
|
|
5
|
+
module Ratonvirus
|
|
6
|
+
module Storage
|
|
7
|
+
module Support
|
|
8
|
+
module IoHandling
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# This creates a local copy of the io contents for the scanning process.
|
|
12
|
+
# A local copy is needed for processing because the io object may be a
|
|
13
|
+
# file stream in the memory which may not have a path associated with it
|
|
14
|
+
# on the filesystem.
|
|
15
|
+
def io_path(io, extension)
|
|
16
|
+
tempfile = Tempfile.open(
|
|
17
|
+
["Ratonvirus", extension],
|
|
18
|
+
tempdir
|
|
19
|
+
)
|
|
20
|
+
# Important for the scanner to be able to access the file.
|
|
21
|
+
prepare_for_scanner tempfile.path
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
tempfile.binmode
|
|
25
|
+
IO.copy_stream(io, tempfile)
|
|
26
|
+
tempfile.flush
|
|
27
|
+
tempfile.rewind
|
|
28
|
+
|
|
29
|
+
yield tempfile.path
|
|
30
|
+
ensure
|
|
31
|
+
tempfile.close!
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def tempdir
|
|
36
|
+
Dir.tmpdir
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def prepare_for_scanner(filepath)
|
|
40
|
+
# Important for the scanner to be able to access the file.
|
|
41
|
+
File.chmod(0o644, filepath)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -88,37 +88,37 @@ module Ratonvirus
|
|
|
88
88
|
def define_backend(backend_type, backend_subclass)
|
|
89
89
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
|
90
90
|
# Getter for #{backend_type}
|
|
91
|
-
def self.#{backend_type}
|
|
92
|
-
@#{backend_type} ||= create_#{backend_type}
|
|
93
|
-
end
|
|
91
|
+
def self.#{backend_type} # def self.foo
|
|
92
|
+
@#{backend_type} ||= create_#{backend_type} # @foo ||= create_foo
|
|
93
|
+
end # end
|
|
94
94
|
|
|
95
95
|
# Setter for #{backend_type}
|
|
96
|
-
def self.#{backend_type}=(#{backend_type}_value)
|
|
97
|
-
set_backend(
|
|
98
|
-
:#{backend_type},
|
|
99
|
-
"#{backend_subclass}",
|
|
100
|
-
#{backend_type}_value
|
|
101
|
-
)
|
|
102
|
-
end
|
|
96
|
+
def self.#{backend_type}=(#{backend_type}_value) # def self.foo=(foo_value)
|
|
97
|
+
set_backend( # set_backend(
|
|
98
|
+
:#{backend_type}, # :foo
|
|
99
|
+
"#{backend_subclass}", # "Foo"
|
|
100
|
+
#{backend_type}_value # foo_value
|
|
101
|
+
) # )
|
|
102
|
+
end # end
|
|
103
103
|
|
|
104
104
|
# Destroys the currently active #{backend_type}.
|
|
105
105
|
# The #{backend_type} is re-initialized when the getter is called.
|
|
106
|
-
def self.destroy_#{backend_type}
|
|
107
|
-
@#{backend_type} = nil
|
|
108
|
-
end
|
|
106
|
+
def self.destroy_#{backend_type} # def self.destroy_foo
|
|
107
|
+
@#{backend_type} = nil # @foo = nil
|
|
108
|
+
end # end
|
|
109
109
|
|
|
110
110
|
# Creates a new backend instance
|
|
111
111
|
# private
|
|
112
|
-
def self.create_#{backend_type}
|
|
113
|
-
if @#{backend_type}_defs.nil?
|
|
114
|
-
raise NotDefinedError.new("#{backend_subclass} not defined!")
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
@#{backend_type}_defs[:klass].new(
|
|
118
|
-
@#{backend_type}_defs[:config]
|
|
119
|
-
)
|
|
120
|
-
end
|
|
121
|
-
private_class_method :create_#{backend_type}
|
|
112
|
+
def self.create_#{backend_type} # def self.create_foo
|
|
113
|
+
if @#{backend_type}_defs.nil? # if @foo_defs.nil?
|
|
114
|
+
raise NotDefinedError.new("#{backend_subclass} not defined!") # raise NotDefinedError.new("Foo not defined")
|
|
115
|
+
end # end
|
|
116
|
+
#
|
|
117
|
+
@#{backend_type}_defs[:klass].new( # @foo_defs[:klass].new(
|
|
118
|
+
@#{backend_type}_defs[:config] # @foo_defs[:config]
|
|
119
|
+
) # )
|
|
120
|
+
end # end
|
|
121
|
+
private_class_method :create_#{backend_type} # private_class_method :create_foo
|
|
122
122
|
CODE
|
|
123
123
|
end
|
|
124
124
|
|
|
@@ -154,12 +154,13 @@ module Ratonvirus
|
|
|
154
154
|
subtype = backend_value.class
|
|
155
155
|
config = backend_value.config
|
|
156
156
|
else
|
|
157
|
-
|
|
157
|
+
case backend_value
|
|
158
|
+
when Array
|
|
158
159
|
subtype = backend_value.shift
|
|
159
160
|
config = backend_value.shift || {}
|
|
160
161
|
|
|
161
162
|
raise InvalidError, "Invalid #{backend_type} type: #{subtype}" unless subtype.is_a?(Symbol)
|
|
162
|
-
|
|
163
|
+
when Symbol
|
|
163
164
|
subtype = backend_value
|
|
164
165
|
config = {}
|
|
165
166
|
else
|
data/lib/ratonvirus/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ratonvirus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antti Hukkanen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -128,28 +128,28 @@ dependencies:
|
|
|
128
128
|
requirements:
|
|
129
129
|
- - "~>"
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version:
|
|
131
|
+
version: 1.11.0
|
|
132
132
|
type: :development
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
136
|
- - "~>"
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
|
-
version:
|
|
138
|
+
version: 1.11.0
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
140
|
name: rubocop-rspec
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
142
142
|
requirements:
|
|
143
143
|
- - "~>"
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
|
-
version:
|
|
145
|
+
version: 2.2.0
|
|
146
146
|
type: :development
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
150
|
- - "~>"
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
|
-
version:
|
|
152
|
+
version: 2.2.0
|
|
153
153
|
description: Adds antivirus check capability for Rails applications.
|
|
154
154
|
email:
|
|
155
155
|
- antti.hukkanen@mainiotech.fi
|
|
@@ -177,6 +177,7 @@ files:
|
|
|
177
177
|
- lib/ratonvirus/storage/carrierwave.rb
|
|
178
178
|
- lib/ratonvirus/storage/filepath.rb
|
|
179
179
|
- lib/ratonvirus/storage/multi.rb
|
|
180
|
+
- lib/ratonvirus/storage/support/io_handling.rb
|
|
180
181
|
- lib/ratonvirus/support/backend.rb
|
|
181
182
|
- lib/ratonvirus/version.rb
|
|
182
183
|
- lib/tasks/ratonvirus.rake
|
|
@@ -192,7 +193,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
192
193
|
requirements:
|
|
193
194
|
- - ">="
|
|
194
195
|
- !ruby/object:Gem::Version
|
|
195
|
-
version: '
|
|
196
|
+
version: '2.5'
|
|
196
197
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
198
|
requirements:
|
|
198
199
|
- - ">="
|