ratonvirus 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://
|
6
|
+
[![Build Status](https://github.com/mainio/ratonvirus/actions/workflows/ci_ratonvirus.yml/badge.svg)](https://github.com/mainio/ratonvirus/actions)
|
7
7
|
[![codecov](https://codecov.io/gh/mainio/ratonvirus/branch/master/graph/badge.svg)](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
|
- - ">="
|