ratonvirus 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2858dfe945bf74c96269185692c5737c5469adf2404f144aeb4f04e9ae546687
4
- data.tar.gz: 07262f10a07c229a92fa8e0b7f7747cff8f33d538804048706b0bd60650d8aeb
3
+ metadata.gz: 4b47a31e5d403f39f0b7496a292532b2dbaa5c38fe624368b09a2cb28c949623
4
+ data.tar.gz: 7a37d2f6d7b20e45c417b87ea22bbadbaf434714c1ce7082c1b4a4d87b646845
5
5
  SHA512:
6
- metadata.gz: 0f039177a939be1eb63a0fc00c626b533dffafae9c906c607e22bf968247e602380304e6075b636d3d08daaa98815adaca5cafa8d3cf87572fd232a15cb3c1c1
7
- data.tar.gz: 041f921088ba88398efddd3d437a38360435b88b4a0ab424047768c59b3ecabda69ca1597a5e0a6ac555a818946713b18492597858b29c167d755c3811ccafb4
6
+ metadata.gz: a52088960f46b6e4aad10616e9f2b65ad082490bd7158484178f88cc6aa68fa76397e471fa4e791e38cd51bcca799aabdbe868656c03226a9157bb2d82be4aaa
7
+ data.tar.gz: 62b103a30f7711cad63d9c9095eec42f98baf372b7fe2308ee03dc3ae063a74bf458afa8026e36ac10aa184df40302a9d721eafbbd93f6fc92efcc090efd9c4c
data/README.md CHANGED
@@ -26,13 +26,13 @@ end
26
26
  Running manual scans:
27
27
 
28
28
  ```ruby
29
- puts "File contains a virus" if Ratonvirus.scanner.virus?('/path/to/file.pdf')
29
+ puts "File contains a virus" if Ratonvirus.scanner.virus?("/path/to/file.pdf")
30
30
  ```
31
31
 
32
32
  Manual scanning works e.g. for file uploads, file object and file paths.
33
33
 
34
- Ratonvirus works well with Active Storage out of the box. Support for
35
- CarrierWave is provided through an additional gem (see details well).
34
+ Ratonvirus works with Active Storage out of the box. Support for CarrierWave is
35
+ also built in, assuming you already have CarrierWave as a dependency.
36
36
 
37
37
  ## When to use this?
38
38
 
@@ -53,7 +53,9 @@ as you are used to with many other gems.
53
53
 
54
54
  You will need to setup a virus scanner on your machine. If you have done that
55
55
  before, configuration should be rather simple. Instructions are provided for
56
- the open source ClamAV scanner.
56
+ the open source ClamAV scanner in the
57
+ [`ratonvirus-clamby`](https://github.com/mainio/ratonvirus-clamby)
58
+ documentation.
57
59
 
58
60
  This gem ships with an example
59
61
  [EICAR file](https://en.wikipedia.org/wiki/EICAR_test_file) scanner to test out
@@ -66,7 +68,7 @@ environments.
66
68
  Add this line to your application's Gemfile:
67
69
 
68
70
  ```ruby
69
- gem 'ratonvirus'
71
+ gem "ratonvirus"
70
72
  ```
71
73
 
72
74
  And then execute:
@@ -102,7 +104,7 @@ Ratonvirus correctly configured.
102
104
 
103
105
  By default Ratonvirus is set to remove all infected files that it detects after
104
106
  scanning them. If you want to remove this functionality, please refer to the
105
- [Scanner addons](doc/index.md#scanner-addons) section of the developer
107
+ [Scanner addons](docs/index.md#scanner-addons) section of the developer
106
108
  documentation.
107
109
 
108
110
  ## Usage
@@ -153,7 +155,7 @@ end
153
155
 
154
156
  # When scanning files, file paths or active storage resources
155
157
  Ratonvirus.configure do |config|
156
- config.storage = :multi, [:filepath, :active_storage]
158
+ config.storage = :multi, {storages: [:filepath, :active_storage]}
157
159
  end
158
160
  ```
159
161
 
@@ -164,7 +166,7 @@ examples:
164
166
  # It is a good idea to check first that the scanner is available.
165
167
  if Ratonvirus.scanner.available?
166
168
  # Scanning a file path
167
- path = '/path/to/file.pdf'
169
+ path = "/path/to/file.pdf"
168
170
  if Ratonvirus.scanner.virus?(path)
169
171
  puts "There is a virus at #{path}"
170
172
  end
@@ -186,8 +188,8 @@ Here are few sample configurations to speed up the configuration process.
186
188
  Gemfile:
187
189
 
188
190
  ```ruby
189
- gem 'ratonvirus'
190
- gem 'ratonvirus-clamby'
191
+ gem "ratonvirus"
192
+ gem "ratonvirus-clamby"
191
193
  ```
192
194
 
193
195
  Initializer:
@@ -209,13 +211,16 @@ class YourModel < ApplicationRecord
209
211
  end
210
212
  ```
211
213
 
214
+ For installing ClamAV, refer to
215
+ [`ratonvirus-clamby`](https://github.com/mainio/ratonvirus-clamby)
216
+
212
217
  #### CarrierWave and ClamAV
213
218
 
214
219
  Gemfile:
215
220
 
216
221
  ```ruby
217
- gem 'ratonvirus'
218
- gem 'ratonvirus-clamby'
222
+ gem "ratonvirus"
223
+ gem "ratonvirus-clamby"
219
224
  ```
220
225
 
221
226
  Initializer:
@@ -237,10 +242,13 @@ class YourModel < ApplicationRecord
237
242
  end
238
243
  ```
239
244
 
245
+ For installing ClamAV, refer to
246
+ [`ratonvirus-clamby`](https://github.com/mainio/ratonvirus-clamby)
247
+
240
248
  ## Further configuration and development
241
249
 
242
250
  For further information about the configurations and how to create custom
243
- scanners, please refer to the [documentation](doc/index.md).
251
+ scanners, please refer to the [documentation](docs/index.md).
244
252
 
245
253
  ## License
246
254
 
@@ -13,14 +13,14 @@ class AntivirusValidator < ActiveModel::EachValidator
13
13
  scanner = Ratonvirus.scanner
14
14
  return unless scanner.available?
15
15
 
16
- if scanner.virus?(value)
17
- if scanner.errors.any?
18
- scanner.errors.each do |err|
19
- record.errors.add attribute, err
20
- end
21
- else
22
- record.errors.add attribute, :antivirus_virus_detected
16
+ return unless scanner.virus?(value)
17
+
18
+ if scanner.errors.any?
19
+ scanner.errors.each do |err|
20
+ record.errors.add attribute, err
23
21
  end
22
+ else
23
+ record.errors.add attribute, :antivirus_virus_detected
24
24
  end
25
25
  end
26
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Binding it to rails to make the app and config folders available in the Rails
2
4
  # load paths.
3
5
  module Ratonvirus
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  class Error < StandardError; end
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  class Processable
3
5
  def initialize(storage, asset)
@@ -7,6 +9,7 @@ module Ratonvirus
7
9
 
8
10
  def path(&block)
9
11
  return unless block_given?
12
+
10
13
  @storage.asset_path(@asset, &block)
11
14
  end
12
15
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Scanner
3
5
  module Addon
@@ -7,11 +9,12 @@ module Ratonvirus
7
9
  end
8
10
 
9
11
  private
10
- def remove_infected_file(processable)
11
- return unless errors.include?(:antivirus_virus_detected)
12
12
 
13
- processable.remove
14
- end
13
+ def remove_infected_file(processable)
14
+ return unless errors.include?(:antivirus_virus_detected)
15
+
16
+ processable.remove
17
+ end
15
18
  end
16
19
  end
17
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Scanner
3
5
  class Base
@@ -12,7 +14,7 @@ module Ratonvirus
12
14
  attr_reader :config
13
15
  attr_reader :errors # Only available after `virus?` has been called.
14
16
 
15
- def initialize(configuration={})
17
+ def initialize(configuration = {})
16
18
  @config = default_config.merge!(configuration)
17
19
 
18
20
  # Make the following callbacks available:
@@ -113,42 +115,40 @@ module Ratonvirus
113
115
  end
114
116
 
115
117
  protected
116
- def default_config
117
- {
118
- force_availability: false,
119
- }
120
- end
121
118
 
122
- def storage
123
- Ratonvirus.storage
124
- end
119
+ def default_config
120
+ { force_availability: false }
121
+ end
125
122
 
126
- def scan(processable)
127
- processable.path do |path|
128
- run_callbacks :scan, processable do
129
- run_scan(path)
130
- end
123
+ def storage
124
+ Ratonvirus.storage
125
+ end
126
+
127
+ def scan(processable)
128
+ processable.path do |path|
129
+ run_callbacks :scan, processable do
130
+ run_scan(path)
131
131
  end
132
132
  end
133
+ end
133
134
 
134
- def run_scan(path)
135
- raise NotImplementedError.new(
136
- "Implement run_scan on #{self.class.name}"
137
- )
138
- end
135
+ def run_scan(_path)
136
+ raise NotImplementedError, "Implement run_scan on #{self.class.name}"
137
+ end
139
138
 
140
139
  private
141
- # Prepare is called each time before scanning is run. During the first
142
- # call to this method, the addons are applied to the scanner instance.
143
- def prepare
144
- return if @ready
145
140
 
146
- Ratonvirus.addons.each do |addon_cls|
147
- extend addon_cls
148
- end
141
+ # Prepare is called each time before scanning is run. During the first
142
+ # call to this method, the addons are applied to the scanner instance.
143
+ def prepare
144
+ return if @ready
149
145
 
150
- @ready = true
146
+ Ratonvirus.addons.each do |addon_cls|
147
+ extend addon_cls
151
148
  end
149
+
150
+ @ready = true
151
+ end
152
152
  end
153
153
  end
154
154
  end
@@ -8,7 +8,7 @@ module Ratonvirus
8
8
  class Eicar < Base
9
9
  # SHA256 digest of the EICAR test file for virus testing
10
10
  # See: https://en.wikipedia.org/wiki/EICAR_test_file
11
- EICAR_SHA256 = '131f95c51cc819465fa1797f6ccacf9d494aaaff46fa3eac73ae63ffbdfd8267'
11
+ EICAR_SHA256 = "131f95c51cc819465fa1797f6ccacf9d494aaaff46fa3eac73ae63ffbdfd8267"
12
12
 
13
13
  class << self
14
14
  def executable?
@@ -17,18 +17,17 @@ module Ratonvirus
17
17
  end
18
18
 
19
19
  protected
20
- def run_scan(path)
21
- if !File.file?(path)
22
- errors << :antivirus_file_not_found
23
- else
24
- sha256 = Digest::SHA256.file path
25
- if sha256 == EICAR_SHA256
26
- errors << :antivirus_virus_detected
27
- end
28
- end
29
- rescue
30
- errors << :antivirus_client_error
20
+
21
+ def run_scan(path)
22
+ if !File.file?(path)
23
+ errors << :antivirus_file_not_found
24
+ else
25
+ sha256 = Digest::SHA256.file path
26
+ errors << :antivirus_virus_detected if sha256 == EICAR_SHA256
31
27
  end
28
+ rescue StandardError
29
+ errors << :antivirus_client_error
30
+ end
32
31
  end
33
32
  end
34
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Scanner
3
5
  module Support
@@ -44,40 +46,37 @@ module Ratonvirus
44
46
  # end
45
47
  module Callbacks
46
48
  private
47
- def run_callbacks(type, *args, &block)
48
- if @_callbacks.nil?
49
- raise NotDefinedError.new("No callbacks defined")
50
- end
51
- if @_callbacks[type].nil?
52
- raise NotDefinedError.new("Callbacks for #{type} not defined")
53
- end
54
49
 
55
- run_callback_callables @_callbacks[type][:before], *args
56
- result = yield *args
57
- run_callback_callables @_callbacks[type][:after], *args
50
+ def run_callbacks(type, *args, &_block)
51
+ raise NotDefinedError, "No callbacks defined" if @_callbacks.nil?
52
+ raise NotDefinedError, "Callbacks for #{type} not defined" if @_callbacks[type].nil?
58
53
 
59
- result
60
- end
54
+ run_callback_callables @_callbacks[type][:before], *args
55
+ result = yield(*args)
56
+ run_callback_callables @_callbacks[type][:after], *args
61
57
 
62
- def run_callback_callables(callables, *args)
63
- callables.each do |callable|
64
- send(callable, *args)
65
- end
58
+ result
59
+ end
60
+
61
+ def run_callback_callables(callables, *args)
62
+ callables.each do |callable|
63
+ send(callable, *args)
66
64
  end
65
+ end
67
66
 
68
- def define_callbacks(type)
69
- @_callbacks ||= {}
70
- @_callbacks[type] ||= {}
71
- @_callbacks[type][:before] = []
72
- @_callbacks[type][:after] = []
67
+ def define_callbacks(type)
68
+ @_callbacks ||= {}
69
+ @_callbacks[type] ||= {}
70
+ @_callbacks[type][:before] = []
71
+ @_callbacks[type][:after] = []
73
72
 
74
- define_singleton_method "before_#{type}" do |callable|
75
- @_callbacks[type][:before] << callable
76
- end
77
- define_singleton_method "after_#{type}" do |callable|
78
- @_callbacks[type][:after] << callable
79
- end
73
+ define_singleton_method "before_#{type}" do |callable|
74
+ @_callbacks[type][:before] << callable
75
+ end
76
+ define_singleton_method "after_#{type}" do |callable|
77
+ @_callbacks[type][:after] << callable
80
78
  end
79
+ end
81
80
  end
82
81
  end
83
82
  end
@@ -3,7 +3,7 @@
3
3
  module Ratonvirus
4
4
  module Storage
5
5
  class ActiveStorage < Base
6
- def changed?(record, attribute)
6
+ def changed?(_record, _attribute)
7
7
  # With Active Storage we assume the record is always changed because
8
8
  # there is currently no way to know if the attribute has actually
9
9
  # changed.
@@ -22,22 +22,20 @@ module Ratonvirus
22
22
 
23
23
  def accept?(resource)
24
24
  resource.is_a?(::ActiveStorage::Attached::One) ||
25
- resource.is_a?(::ActiveStorage::Attached::Many)
25
+ resource.is_a?(::ActiveStorage::Attached::Many)
26
26
  end
27
27
 
28
- def process(resource, &block)
28
+ def process(resource, &_block)
29
29
  return unless block_given?
30
30
  return if resource.nil?
31
31
 
32
- if resource.attached?
33
- if resource.is_a?(::ActiveStorage::Attached::One)
34
- if resource.attachment
35
- yield processable(resource.attachment)
36
- end
37
- elsif resource.is_a?(::ActiveStorage::Attached::Many)
38
- resource.attachments.each do |attachment|
39
- yield processable(attachment)
40
- end
32
+ return unless resource.attached?
33
+
34
+ if resource.is_a?(::ActiveStorage::Attached::One)
35
+ yield processable(resource.attachment) if resource.attachment
36
+ elsif resource.is_a?(::ActiveStorage::Attached::Many)
37
+ resource.attachments.each do |attachment|
38
+ yield processable(attachment)
41
39
  end
42
40
  end
43
41
  end
@@ -55,42 +53,45 @@ module Ratonvirus
55
53
  end
56
54
 
57
55
  private
58
- # This creates a local copy of the blob for the scanning process. A
59
- # local copy is needed for processing because the actual blob may be
60
- # stored at a remote storage service (such as Amazon S3), meaning it
61
- # cannot be otherwise processed locally.
62
- #
63
- # NOTE:
64
- # Later implementations of Active Storage have the blob.open method that
65
- # provides similar functionality. However, Rails 5.2.x still does not
66
- # include this functionality, so we need to take care of it ourselves.
67
- #
68
- # This was introduced in the following commit:
69
- # https://github.com/rails/rails/commit/ee21b7c2eb64def8f00887a9fafbd77b85f464f1
70
- #
71
- # SEE:
72
- # https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files
73
- def blob_path(blob)
74
- tempfile = Tempfile.open(
75
- ["Ratonvirus", blob.filename.extension_with_delimiter ],
76
- tempdir
77
- )
78
56
 
79
- begin
80
- tempfile.binmode
81
- blob.download { |chunk| tempfile.write(chunk) }
82
- tempfile.flush
83
- tempfile.rewind
57
+ # This creates a local copy of the blob for the scanning process. A
58
+ # local copy is needed for processing because the actual blob may be
59
+ # stored at a remote storage service (such as Amazon S3), meaning it
60
+ # cannot be otherwise processed locally.
61
+ #
62
+ # NOTE:
63
+ # Later implementations of Active Storage have the blob.open method that
64
+ # provides similar functionality. However, Rails 5.2.x still does not
65
+ # include this functionality, so we need to take care of it ourselves.
66
+ #
67
+ # This was introduced in the following commit:
68
+ # https://github.com/rails/rails/commit/ee21b7c2eb64def8f00887a9fafbd77b85f464f1
69
+ #
70
+ # SEE:
71
+ # https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files
72
+ def blob_path(blob)
73
+ tempfile = Tempfile.open(
74
+ ["Ratonvirus", blob.filename.extension_with_delimiter],
75
+ tempdir
76
+ )
84
77
 
85
- yield tempfile.path
86
- ensure
87
- tempfile.close!
88
- end
89
- end
78
+ begin
79
+ tempfile.binmode
80
+ blob.download { |chunk| tempfile.write(chunk) }
81
+ tempfile.flush
82
+ tempfile.rewind
90
83
 
91
- def tempdir
92
- Dir.tmpdir
84
+ yield tempfile.path
85
+ rescue StandardError
86
+ return
87
+ ensure
88
+ tempfile.close!
93
89
  end
90
+ end
91
+
92
+ def tempdir
93
+ Dir.tmpdir
94
+ end
94
95
  end
95
96
  end
96
97
  end
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Storage
3
5
  class Base
4
6
  attr_reader :config
5
7
 
6
- def initialize(configuration={})
8
+ def initialize(configuration = {})
7
9
  @config = configuration.dup
8
10
 
9
- if respond_to?(:setup)
10
- setup
11
- end
11
+ setup if respond_to?(:setup)
12
12
  end
13
13
 
14
14
  # Default process implementation.
@@ -23,34 +23,27 @@ module Ratonvirus
23
23
  end
24
24
  end
25
25
 
26
- def changed?(record, attribute)
27
- raise NotImplementedError.new(
28
- "Implement changed? on #{self.class.name}"
29
- )
26
+ def changed?(_record, _attribute)
27
+ raise NotImplementedError, "Implement changed? on #{self.class.name}"
30
28
  end
31
29
 
32
- def accept?(resource)
33
- raise NotImplementedError.new(
34
- "Implement accept? on #{self.class.name}"
35
- )
30
+ def accept?(_resource)
31
+ raise NotImplementedError, "Implement accept? on #{self.class.name}"
36
32
  end
37
33
 
38
- def asset_path(asset)
39
- raise NotImplementedError.new(
40
- "Implement path on #{self.class.name}"
41
- )
34
+ def asset_path(_asset)
35
+ raise NotImplementedError, "Implement path on #{self.class.name}"
42
36
  end
43
37
 
44
- def asset_remove(asset)
45
- raise NotImplementedError.new(
46
- "Implement remove on #{self.class.name}"
47
- )
38
+ def asset_remove(_asset)
39
+ raise NotImplementedError, "Implement remove on #{self.class.name}"
48
40
  end
49
41
 
50
42
  protected
51
- def processable(asset)
52
- Processable.new(self, asset)
53
- end
43
+
44
+ def processable(asset)
45
+ Processable.new(self, asset)
46
+ end
54
47
  end
55
48
  end
56
49
  end
@@ -25,7 +25,7 @@ module Ratonvirus
25
25
 
26
26
  def asset_remove(asset)
27
27
  path = asset.file.path
28
- result = asset.remove!
28
+ asset.remove!
29
29
 
30
30
  # Remove the temp cache dir if it exists
31
31
  dir = File.dirname(path)
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Storage
3
5
  class Filepath < Base
4
6
  def changed?(record, attribute)
5
- if record.respond_to? :"#{attribute}_changed?"
6
- return record.public_send :"#{attribute}_changed?"
7
- end
7
+ return record.public_send :"#{attribute}_changed?" if record.respond_to? :"#{attribute}_changed?"
8
8
 
9
9
  # Some backends do not implement the `attribute_changed?` methods for
10
10
  # the file resources. In that case our best guess is to check whether
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Storage
3
5
  # Multi storage allows the developers to configure multiple storage backends
@@ -12,18 +14,18 @@ module Ratonvirus
12
14
  def setup
13
15
  @storages = []
14
16
 
15
- if config[:storages].is_a?(Array)
16
- config[:storages].each do |storage|
17
- if storage.is_a?(Array)
18
- type = storage[0]
19
- storage_config = storage[1]
20
- else
21
- type = storage
22
- end
17
+ return unless config[:storages].is_a?(Array)
23
18
 
24
- cls = Ratonvirus.backend_class('Storage', type)
25
- @storages << cls.new(storage_config || {})
19
+ config[:storages].each do |storage|
20
+ if storage.is_a?(Array)
21
+ type = storage[0]
22
+ storage_config = storage[1]
23
+ else
24
+ type = storage
26
25
  end
26
+
27
+ cls = Ratonvirus.backend_class("Storage", type)
28
+ @storages << cls.new(storage_config || {})
27
29
  end
28
30
  end
29
31
 
@@ -55,7 +57,7 @@ module Ratonvirus
55
57
 
56
58
  # Check if any of the storages accept the resource.
57
59
  def accept?(resource)
58
- storage_for(resource) do |storage|
60
+ storage_for(resource) do |_storage|
59
61
  return true
60
62
  end
61
63
 
@@ -63,16 +65,17 @@ module Ratonvirus
63
65
  end
64
66
 
65
67
  private
66
- # Iterates through the @storages array and returns the first storage
67
- # that accepts the resource.
68
- def storage_for(resource)
69
- @storages.each do |storage|
70
- if storage.accept?(resource)
71
- yield storage
72
- return
73
- end
68
+
69
+ # Iterates through the @storages array and yields the first storage
70
+ # that accepts the resource.
71
+ def storage_for(resource)
72
+ @storages.each do |storage|
73
+ if storage.accept?(resource)
74
+ yield storage
75
+ break
74
76
  end
75
77
  end
78
+ end
76
79
  end
77
80
  end
78
81
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ratonvirus
2
4
  module Support
3
5
  # The backend implementation allows us to set different backends on the main
@@ -30,152 +32,150 @@ module Ratonvirus
30
32
 
31
33
  subclass = ActiveSupport::Inflector.camelize(backend_type.to_s)
32
34
  ActiveSupport::Inflector.constantize(
33
- "#{self.name}::#{backend_cls}::#{subclass}"
35
+ "#{name}::#{backend_cls}::#{subclass}"
34
36
  )
35
37
  end
36
38
 
37
39
  private
38
- # Defines the "backend" methods.
39
- #
40
- # For example, this:
41
- # define_backend :foo, 'Foo'
42
- #
43
- # Would define the following methods:
44
- # # Getter for foo
45
- # def self.foo
46
- # @foo ||= create_foo
47
- # end
48
- #
49
- # # Setter for foo
50
- # def self.foo=(foo_type)
51
- # set_backend(
52
- # :foo,
53
- # 'Foo',
54
- # foo_type
55
- # )
56
- # end
57
- #
58
- # # Destroys the currently active foo.
59
- # # The foo is re-initialized when the getter is called.
60
- # def self.destroy_foo
61
- # @foo = nil
62
- # end
63
- #
64
- # private
65
- # def self.create_foo
66
- # if @foo_defs.nil?
67
- # raise NotDefinedError.new("Foo not defined!")
68
- # end
69
- #
70
- # @foo_defs[:klass].new(@foo_defs[:config])
71
- # end
72
- #
73
- # Usage (getter):
74
- # Ratonvirus.foo
75
- #
76
- # Usage (setter):
77
- # Ratonvirus.foo = :bar
78
- # Ratonvirus.foo = :bar, {option: 'value'}
79
- # Ratonvirus.foo = Ratonvirus::Foo::Bar.new
80
- # Ratonvirus.foo = Ratonvirus::Foo::Bar.new({option: 'value'})
81
- #
82
- # Usage (destroyer):
83
- # Ratonvirus.destroy_foo
84
- #
85
- def define_backend(backend_type, backend_subclass)
86
- self.class_eval <<-CODE, __FILE__, __LINE__ + 1
87
- # Getter for #{backend_type}
88
- def self.#{backend_type}
89
- @#{backend_type} ||= create_#{backend_type}
90
- end
91
40
 
92
- # Setter for #{backend_type}
93
- def self.#{backend_type}=(#{backend_type}_value)
94
- set_backend(
95
- :#{backend_type},
96
- "#{backend_subclass}",
97
- #{backend_type}_value
98
- )
99
- end
41
+ # Defines the "backend" methods.
42
+ #
43
+ # For example, this:
44
+ # define_backend :foo, 'Foo'
45
+ #
46
+ # Would define the following methods:
47
+ # # Getter for foo
48
+ # def self.foo
49
+ # @foo ||= create_foo
50
+ # end
51
+ #
52
+ # # Setter for foo
53
+ # def self.foo=(foo_type)
54
+ # set_backend(
55
+ # :foo,
56
+ # 'Foo',
57
+ # foo_type
58
+ # )
59
+ # end
60
+ #
61
+ # # Destroys the currently active foo.
62
+ # # The foo is re-initialized when the getter is called.
63
+ # def self.destroy_foo
64
+ # @foo = nil
65
+ # end
66
+ #
67
+ # private
68
+ # def self.create_foo
69
+ # if @foo_defs.nil?
70
+ # raise NotDefinedError.new("Foo not defined!")
71
+ # end
72
+ #
73
+ # @foo_defs[:klass].new(@foo_defs[:config])
74
+ # end
75
+ #
76
+ # Usage (getter):
77
+ # Ratonvirus.foo
78
+ #
79
+ # Usage (setter):
80
+ # Ratonvirus.foo = :bar
81
+ # Ratonvirus.foo = :bar, {option: 'value'}
82
+ # Ratonvirus.foo = Ratonvirus::Foo::Bar.new
83
+ # Ratonvirus.foo = Ratonvirus::Foo::Bar.new({option: 'value'})
84
+ #
85
+ # Usage (destroyer):
86
+ # Ratonvirus.destroy_foo
87
+ #
88
+ def define_backend(backend_type, backend_subclass)
89
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
90
+ # Getter for #{backend_type}
91
+ def self.#{backend_type}
92
+ @#{backend_type} ||= create_#{backend_type}
93
+ end
100
94
 
101
- # Destroys the currently active #{backend_type}.
102
- # The #{backend_type} is re-initialized when the getter is called.
103
- def self.destroy_#{backend_type}
104
- @#{backend_type} = nil
105
- end
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
106
103
 
107
- # Creates a new backend instance
108
- # private
109
- def self.create_#{backend_type}
110
- if @#{backend_type}_defs.nil?
111
- raise NotDefinedError.new("#{backend_subclass} not defined!")
112
- end
104
+ # Destroys the currently active #{backend_type}.
105
+ # The #{backend_type} is re-initialized when the getter is called.
106
+ def self.destroy_#{backend_type}
107
+ @#{backend_type} = nil
108
+ end
113
109
 
114
- @#{backend_type}_defs[:klass].new(
115
- @#{backend_type}_defs[:config]
116
- )
110
+ # Creates a new backend instance
111
+ # private
112
+ def self.create_#{backend_type}
113
+ if @#{backend_type}_defs.nil?
114
+ raise NotDefinedError.new("#{backend_subclass} not defined!")
117
115
  end
118
- private_class_method :create_#{backend_type}
119
- CODE
120
- end
121
116
 
122
- # Sets the backend to local variables for the backend initialization.
123
- # The goal of this method is to get the following configuration set to
124
- # local `@x_defs` variable, where 'x' is the type of backend.
125
- #
126
- # For example, for a backend with type "scanner", this would be
127
- # @scanner_defs.
128
- #
129
- # The first argument, "backend_type" is the type of backend we are
130
- # configuring, e.g. `:scanner`.
131
- #
132
- # The second argument "backend_cls" is the backend subclass that is
133
- # used in the module's namespace, e.g. "Scanner". This would refer to
134
- # subclasses `Ratonvirus::Scanner::...`.
135
- #
136
- # The third argument "backend_value" is the actual value the user
137
- # provided for the setter method, e.g. `:eicar` or
138
- # `Ratonvirus::Scanner::Eicar.new`. The user may also provide a second
139
- # argument to the setter method e.g. like
140
- # `Ratonvirus.scanner = :eicar, {conf: 'option'}`, in which case these
141
- # both arguments are provided in this argument as an array.
142
- def set_backend(backend_type, backend_cls, backend_value)
143
- base_class = backend_class(backend_cls, "Base")
117
+ @#{backend_type}_defs[:klass].new(
118
+ @#{backend_type}_defs[:config]
119
+ )
120
+ end
121
+ private_class_method :create_#{backend_type}
122
+ CODE
123
+ end
144
124
 
145
- if backend_value.is_a?(base_class)
146
- # Set the instance
147
- instance_variable_set(:"@#{backend_type}", backend_value)
125
+ # Sets the backend to local variables for the backend initialization.
126
+ # The goal of this method is to get the following configuration set to
127
+ # local `@x_defs` variable, where 'x' is the type of backend.
128
+ #
129
+ # For example, for a backend with type "scanner", this would be
130
+ # @scanner_defs.
131
+ #
132
+ # The first argument, "backend_type" is the type of backend we are
133
+ # configuring, e.g. `:scanner`.
134
+ #
135
+ # The second argument "backend_cls" is the backend subclass that is
136
+ # used in the module's namespace, e.g. "Scanner". This would refer to
137
+ # subclasses `Ratonvirus::Scanner::...`.
138
+ #
139
+ # The third argument "backend_value" is the actual value the user
140
+ # provided for the setter method, e.g. `:eicar` or
141
+ # `Ratonvirus::Scanner::Eicar.new`. The user may also provide a second
142
+ # argument to the setter method e.g. like
143
+ # `Ratonvirus.scanner = :eicar, {conf: 'option'}`, in which case these
144
+ # both arguments are provided in this argument as an array.
145
+ def set_backend(backend_type, backend_cls, backend_value)
146
+ base_class = backend_class(backend_cls, "Base")
148
147
 
149
- # Store the class (type) and config for storing them below to local
150
- # variable in case it needs to be re-initialized at some point.
151
- subtype = backend_value.class
152
- config = backend_value.config
153
- else
154
- if backend_value.is_a?(Array)
155
- subtype = backend_value.shift
156
- config = backend_value.shift || {}
148
+ if backend_value.is_a?(base_class)
149
+ # Set the instance
150
+ instance_variable_set(:"@#{backend_type}", backend_value)
157
151
 
158
- unless subtype.is_a?(Symbol)
159
- raise InvalidError.new(
160
- "Invalid #{backend_type} type: #{subtype}"
161
- )
162
- end
163
- elsif backend_value.is_a?(Symbol)
164
- subtype = backend_value
165
- config = {}
166
- else
167
- raise InvalidError.new("Invalid #{backend_type} provided!")
168
- end
152
+ # Store the class (type) and config for storing them below to local
153
+ # variable in case it needs to be re-initialized at some point.
154
+ subtype = backend_value.class
155
+ config = backend_value.config
156
+ else
157
+ if backend_value.is_a?(Array)
158
+ subtype = backend_value.shift
159
+ config = backend_value.shift || {}
169
160
 
170
- # Destroy the current one
171
- send(:"destroy_#{backend_type}")
161
+ raise InvalidError, "Invalid #{backend_type} type: #{subtype}" unless subtype.is_a?(Symbol)
162
+ elsif backend_value.is_a?(Symbol)
163
+ subtype = backend_value
164
+ config = {}
165
+ else
166
+ raise InvalidError, "Invalid #{backend_type} provided!"
172
167
  end
173
168
 
174
- instance_variable_set(:"@#{backend_type}_defs", {
175
- klass: backend_class(backend_cls, subtype),
176
- config: config,
177
- })
169
+ # Destroy the current one
170
+ send(:"destroy_#{backend_type}")
178
171
  end
172
+
173
+ instance_variable_set(
174
+ :"@#{backend_type}_defs",
175
+ klass: backend_class(backend_cls, subtype),
176
+ config: config
177
+ )
178
+ end
179
179
  end
180
180
  end
181
181
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ratonvirus
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/ratonvirus.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fileutils"
2
4
  require "active_support"
3
5
  require "digest"
@@ -42,7 +44,7 @@ module Ratonvirus
42
44
  #
43
45
  # Usage (destroy):
44
46
  # Ratonvirus.destroy_scanner
45
- define_backend :scanner, 'Scanner'
47
+ define_backend :scanner, "Scanner"
46
48
 
47
49
  # Usage (set):
48
50
  # Ratonvirus.storage = :active_storage
@@ -55,19 +57,19 @@ module Ratonvirus
55
57
  #
56
58
  # Usage (destroy):
57
59
  # Ratonvirus.destroy_storage
58
- define_backend :storage, 'Storage'
60
+ define_backend :storage, "Storage"
59
61
 
60
62
  # Resets Ratonvirus to its initial state and configuration
61
63
  def self.reset
62
64
  # Default addons
63
65
  @addons = [
64
66
  ActiveSupport::Inflector.constantize(
65
- "#{self.name}::Scanner::Addon::RemoveInfected"
66
- ),
67
+ "#{name}::Scanner::Addon::RemoveInfected"
68
+ )
67
69
  ]
68
70
 
69
- self.destroy_scanner
70
- self.destroy_storage
71
+ destroy_scanner
72
+ destroy_storage
71
73
  end
72
74
 
73
75
  def self.addons
@@ -77,15 +79,13 @@ module Ratonvirus
77
79
  def self.addons=(addons)
78
80
  @addons = []
79
81
  addons.each do |addon|
80
- self.add_addon addon
82
+ add_addon addon
81
83
  end
82
84
  end
83
85
 
84
86
  def self.add_addon(addon)
85
87
  addon_cls = addon_class(addon)
86
- unless @addons.include?(addon_cls)
87
- @addons << addon_cls
88
- end
88
+ @addons << addon_cls unless @addons.include?(addon_cls)
89
89
  end
90
90
 
91
91
  def self.remove_addon(addon)
@@ -99,7 +99,7 @@ module Ratonvirus
99
99
 
100
100
  subclass = ActiveSupport::Inflector.camelize(type.to_s)
101
101
  ActiveSupport::Inflector.constantize(
102
- "#{self.name}::Scanner::Addon::#{subclass}"
102
+ "#{name}::Scanner::Addon::#{subclass}"
103
103
  )
104
104
  end
105
105
  private_class_method :addon_class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :ratonvirus do
2
4
  desc "Tests if the antivirus scanner is available and properly configured"
3
5
  task test: :environment do
@@ -9,7 +11,7 @@ namespace :ratonvirus do
9
11
  puts ""
10
12
  puts "Please refer to Ratonvirus documentation for proper configuration."
11
13
  end
12
- rescue
14
+ rescue StandardError
13
15
  puts "Ratonvirus scanner is not configured."
14
16
  puts ""
15
17
  puts "Please refer to Ratonvirus documentation for proper configuration."
@@ -18,7 +20,7 @@ namespace :ratonvirus do
18
20
 
19
21
  desc "Scans the given file through the antivirus scanner"
20
22
  task scan: :environment do |t, args|
21
- if args.extras.length < 1
23
+ if args.extras.empty?
22
24
  puts "No files given."
23
25
  puts "Usage:"
24
26
  puts " #{t.name}[/path/to/first/file.pdf,/path/to/second/file.pdf]"
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.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antti Hukkanen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-10 00:00:00.000000000 Z
11
+ date: 2019-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -122,6 +122,34 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '1.2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.64.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.64.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.32'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.32'
125
153
  description: Adds antivirus check capability for Rails applications.
126
154
  email:
127
155
  - antti.hukkanen@mainiotech.fi
@@ -171,8 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
199
  - !ruby/object:Gem::Version
172
200
  version: '0'
173
201
  requirements: []
174
- rubyforge_project:
175
- rubygems_version: 2.7.7
202
+ rubygems_version: 3.0.3
176
203
  signing_key:
177
204
  specification_version: 4
178
205
  summary: Provides antivirus checks for Rails.