ruby_clamdscan 0.1.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.
@@ -0,0 +1,204 @@
1
+ ##
2
+ ## Example config file for freshclam
3
+ ## Please read the freshclam.conf(5) manual before editing this file.
4
+ ##
5
+
6
+
7
+ # Comment or remove the line below.
8
+ # Example
9
+
10
+ # Path to the database directory.
11
+ # WARNING: It must match clamd.conf's directive!
12
+ # Default: hardcoded (depends on installation options)
13
+ #DatabaseDirectory /var/lib/clamav
14
+
15
+ # Path to the log file (make sure it has proper permissions)
16
+ # Default: disabled
17
+ UpdateLogFile /var/log/clamav/freshclam.log
18
+
19
+ # Maximum size of the log file.
20
+ # Value of 0 disables the limit.
21
+ # You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
22
+ # and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes).
23
+ # in bytes just don't use modifiers. If LogFileMaxSize is enabled,
24
+ # log rotation (the LogRotate option) will always be enabled.
25
+ # Default: 1M
26
+ #LogFileMaxSize 2M
27
+
28
+ # Log time with each message.
29
+ # Default: no
30
+ #LogTime yes
31
+
32
+ # Enable verbose logging.
33
+ # Default: no
34
+ #LogVerbose yes
35
+
36
+ # Use system logger (can work together with UpdateLogFile).
37
+ # Default: no
38
+ #LogSyslog yes
39
+
40
+ # Specify the type of syslog messages - please refer to 'man syslog'
41
+ # for facility names.
42
+ # Default: LOG_LOCAL6
43
+ #LogFacility LOG_MAIL
44
+
45
+ # Enable log rotation. Always enabled when LogFileMaxSize is enabled.
46
+ # Default: no
47
+ #LogRotate yes
48
+
49
+ # This option allows you to save the process identifier of the daemon
50
+ # This file will be owned by root, as long as freshclam was started by root.
51
+ # It is recommended that the directory where this file is stored is
52
+ # also owned by root to keep other users from tampering with it.
53
+ # Default: disabled
54
+ PidFile /tmp/freshclam.pid
55
+
56
+ # By default when started freshclam drops privileges and switches to the
57
+ # "clamav" user. This directive allows you to change the database owner.
58
+ # Default: clamav (may depend on installation options)
59
+ DatabaseOwner clamav
60
+
61
+ # Use DNS to verify virus database version. FreshClam uses DNS TXT records
62
+ # to verify database and software versions. With this directive you can change
63
+ # the database verification domain.
64
+ # WARNING: Do not touch it unless you're configuring freshclam to use your
65
+ # own database verification domain.
66
+ # Default: current.cvd.clamav.net
67
+ #DNSDatabaseInfo current.cvd.clamav.net
68
+
69
+ # database.clamav.net is now the primary domain name to be used world-wide.
70
+ # Now that CloudFlare is being used as our Content Delivery Network (CDN),
71
+ # this one domain name works world-wide to direct freshclam to the closest
72
+ # geographic endpoint.
73
+ # If the old db.XY.clamav.net domains are set, freshclam will automatically
74
+ # use database.clamav.net instead.
75
+ DatabaseMirror database.clamav.net
76
+
77
+ # How many attempts to make before giving up.
78
+ # Default: 3 (per mirror)
79
+ #MaxAttempts 5
80
+
81
+ # With this option you can control scripted updates. It's highly recommended
82
+ # to keep it enabled.
83
+ # Default: yes
84
+ ScriptedUpdates yes
85
+
86
+ # By default freshclam will keep the local databases (.cld) uncompressed to
87
+ # make their handling faster. With this option you can enable the compression;
88
+ # the change will take effect with the next database update.
89
+ # Default: no
90
+ #CompressLocalDatabase no
91
+
92
+ # With this option you can provide custom sources for database files.
93
+ # This option can be used multiple times. Support for:
94
+ # http(s)://, ftp(s)://, or file://
95
+ # Default: no custom URLs
96
+ #DatabaseCustomURL http://myserver.example.com/mysigs.ndb
97
+ #DatabaseCustomURL https://myserver.example.com/mysigs.ndb
98
+ #DatabaseCustomURL https://myserver.example.com:4567/allow_list.wdb
99
+ #DatabaseCustomURL ftp://myserver.example.com/example.ldb
100
+ #DatabaseCustomURL ftps://myserver.example.com:4567/example.ndb
101
+ #DatabaseCustomURL file:///mnt/nfs/local.hdb
102
+
103
+ # This option allows you to easily point freshclam to private mirrors.
104
+ # If PrivateMirror is set, freshclam does not attempt to use DNS
105
+ # to determine whether its databases are out-of-date, instead it will
106
+ # use the If-Modified-Since request or directly check the headers of the
107
+ # remote database files. For each database, freshclam first attempts
108
+ # to download the CLD file. If that fails, it tries to download the
109
+ # CVD file. This option overrides DatabaseMirror, DNSDatabaseInfo
110
+ # and ScriptedUpdates. It can be used multiple times to provide
111
+ # fall-back mirrors.
112
+ # Default: disabled
113
+ #PrivateMirror mirror1.example.com
114
+ #PrivateMirror mirror2.example.com
115
+
116
+ # Number of database checks per day.
117
+ # Default: 12 (every two hours)
118
+ #Checks 24
119
+
120
+ # Proxy settings
121
+ # The HTTPProxyServer may be prefixed with [scheme]:// to specify which kind
122
+ # of proxy is used.
123
+ # http:// HTTP Proxy. Default when no scheme or proxy type is specified.
124
+ # https:// HTTPS Proxy. (Added in 7.52.0 for OpenSSL, GnuTLS and NSS)
125
+ # socks4:// SOCKS4 Proxy.
126
+ # socks4a:// SOCKS4a Proxy. Proxy resolves URL hostname.
127
+ # socks5:// SOCKS5 Proxy.
128
+ # socks5h:// SOCKS5 Proxy. Proxy resolves URL hostname.
129
+ # Default: disabled
130
+ #HTTPProxyServer https://proxy.example.com
131
+ #HTTPProxyPort 1234
132
+ #HTTPProxyUsername myusername
133
+ #HTTPProxyPassword mypass
134
+
135
+ # If your servers are behind a firewall/proxy which applies User-Agent
136
+ # filtering you can use this option to force the use of a different
137
+ # User-Agent header.
138
+ # As of ClamAV 0.103.3, this setting may not be used when updating from the
139
+ # clamav.net CDN and can only be used when updating from a private mirror.
140
+ # Default: clamav/version_number (OS: ..., ARCH: ..., CPU: ..., UUID: ...)
141
+ #HTTPUserAgent SomeUserAgentIdString
142
+
143
+ # Use aaa.bbb.ccc.ddd as client address for downloading databases. Useful for
144
+ # multi-homed systems.
145
+ # Default: Use OS'es default outgoing IP address.
146
+ #LocalIPAddress aaa.bbb.ccc.ddd
147
+
148
+ # Send the RELOAD command to clamd.
149
+ # Default: no
150
+ NotifyClamd /etc/clamav/clamd.conf
151
+
152
+ # Run command after successful database update.
153
+ # Use EXIT_1 to return 1 after successful database update.
154
+ # Default: disabled
155
+ #OnUpdateExecute command
156
+
157
+ # Run command when database update process fails.
158
+ # Default: disabled
159
+ #OnErrorExecute command
160
+
161
+ # Run command when freshclam reports outdated version.
162
+ # In the command string %v will be replaced by the new version number.
163
+ # Default: disabled
164
+ #OnOutdatedExecute command
165
+
166
+ # Don't fork into background.
167
+ # Default: no
168
+ #Foreground yes
169
+
170
+ # Enable debug messages in libclamav.
171
+ # Default: no
172
+ #Debug yes
173
+
174
+ # Timeout in seconds when connecting to database server.
175
+ # Default: 30
176
+ #ConnectTimeout 60
177
+
178
+ # Timeout in seconds when reading from database server. 0 means no timeout.
179
+ # Default: 60
180
+ #ReceiveTimeout 300
181
+
182
+ # With this option enabled, freshclam will attempt to load new databases into
183
+ # memory to make sure they are properly handled by libclamav before replacing
184
+ # the old ones.
185
+ # Tip: This feature uses a lot of RAM. If your system has limited RAM and you
186
+ # are actively running ClamD or ClamScan during the update, then you may need
187
+ # to set `TestDatabases no`.
188
+ # Default: yes
189
+ #TestDatabases no
190
+
191
+ # This option enables downloading of bytecode.cvd, which includes additional
192
+ # detection mechanisms and improvements to the ClamAV engine.
193
+ # Default: yes
194
+ #Bytecode no
195
+
196
+ # Include an optional signature databases (opt-in).
197
+ # This option can be used multiple times.
198
+ #ExtraDatabase dbname1
199
+ #ExtraDatabase dbname2
200
+
201
+ # Exclude a standard signature database (opt-out).
202
+ # This option can be used multiple times.
203
+ #ExcludeDatabase dbname1
204
+ #ExcludeDatabase dbname2
@@ -0,0 +1,18 @@
1
+ version: "3.9"
2
+ services:
3
+ clamav:
4
+ image: clamav/clamav:latest
5
+ ports:
6
+ - "3310:3310"
7
+ volumes:
8
+ - clamav-dev:/var/lib/clamav # Virus database
9
+ - ./docker/clamav/config/clamd.conf:/etc/clamav/clamd.conf
10
+ - ./docker/clamav/config/freshclam.conf:/etc/clamav/freshclam.conf
11
+
12
+ volumes:
13
+ clamav-dev:
14
+
15
+ networks:
16
+ ruby-clamdscan:
17
+ external: true
18
+ name: ruby-clamdscan
data/eicar.com ADDED
@@ -0,0 +1 @@
1
+ X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/commands/utils"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Management commands for
8
+ module Manage
9
+ # Force ClamAV to reload the virus databases
10
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
11
+ def self.reload_server_database(configuration)
12
+ RubyClamdscan::Commands::Utils.send_single_command("RELOAD", configuration)
13
+ end
14
+
15
+ # Shutdown ClamAV server
16
+ # Note: this will completely close socket communication. Server cannot be restarted through this library
17
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
18
+ def self.shutdown_server(configuration)
19
+ RubyClamdscan::Commands::Utils.send_single_command("SHUTDOWN", configuration)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "ruby_clamdscan/models/scan_result"
5
+ require "ruby_clamdscan/errors/clamav_errors"
6
+
7
+ module RubyClamdscan
8
+ module Commands
9
+ # Methods for scanning file contents
10
+ module Scan
11
+ SCAN_COMMAND = "zINSTREAM\0"
12
+
13
+ # Stream file contents to ClamAV
14
+ # @param file_input_stream [IO] Input file_input_stream to scan
15
+ # @param configuration [RubyClamdscan::Configuration] Configuration settings
16
+ # @return [RubyClamdscan::Models::ScanResult]
17
+ # @raise [RubyClamdscan::Errors::VirusDetectedError] if Configuration is set to raise exception and malware is detected
18
+ # @raise [RubyClamdscan::Errors::ClamAVCommunicationError] if communication with ClamAV server fails
19
+ def self.scan(file_input_stream, configuration)
20
+ response = ""
21
+ clam_av_stream = nil
22
+
23
+ begin
24
+ clam_av_stream = RubyClamdscan::Socket.open_clamav_socket(configuration)
25
+ send_contents(clam_av_stream, configuration, file_input_stream)
26
+ response = get_response(clam_av_stream)
27
+ rescue StandardError => e
28
+ raise RubyClamdscan::Errors::ClamAVCommunicationError.new(SCAN_COMMAND, e)
29
+ ensure
30
+ clam_av_stream&.close
31
+ end
32
+
33
+ result = build_result(response)
34
+
35
+ raise RubyClamdscan::Errors::VirusDetectedError, result if configuration.raise_error_on_virus_detected && result.contains_virus
36
+
37
+ result
38
+ end
39
+
40
+ # Stream file contents to ClamAV
41
+ # @param filepath [String] Path to file in local storage to scan
42
+ # @param configuration [RubyClamdscan::Configuration] Configuration settings
43
+ # @return [RubyClamdscan::Models::ScanResult]
44
+ # @raise IOError if there is no file found at filepath
45
+ def self.scan_file(filepath, configuration)
46
+ raise IOError, "Unable to find file #{filepath}" unless File.exist?(filepath)
47
+
48
+ begin
49
+ fd = IO.sysopen(filepath, "rb")
50
+ fin = IO.new(fd)
51
+ result = scan(fin, configuration)
52
+ ensure
53
+ fin.close
54
+ end
55
+ result
56
+ end
57
+
58
+ # Builds a result object after parsing the response from ClamAV
59
+ # @param response [String] Response from ClamAV stream
60
+ # @return [RubyClamdscan::Models::ScanResult] Constructed result object
61
+ def self.build_result(response)
62
+ # OK response: "stream: OK"
63
+ # Malware response: "stream: Win.Test.EICAR_HDB-1 FOUND"
64
+ # Error response "stream: <message> ERROR"
65
+
66
+ response = response.strip # Strip out any trailing empty chars from the buffer
67
+ tokens = response.split(" ")
68
+ puts("RESPONSE:'#{response}'")
69
+
70
+ case tokens
71
+ in ["stream:", "OK"]
72
+ RubyClamdscan::Models::ScanResult.new(is_successful: true, contains_virus: false)
73
+ in ["stream:", virus_info, "FOUND"]
74
+ RubyClamdscan::Models::ScanResult.new(is_successful: true, contains_virus: true, virus_info:)
75
+ in []
76
+ RubyClamdscan::Models::ScanResult.new(is_successful: false, contains_virus: nil,
77
+ error_message: "Empty response from ClamAV, is the server accepting connections?")
78
+ else
79
+ RubyClamdscan::Models::ScanResult.new(is_successful: false, contains_virus: nil, error_message: response)
80
+ end
81
+ end
82
+
83
+ private_class_method :build_result
84
+
85
+ # Gets the response from ClamAV off the stream
86
+ # @param clam_av_stream [IO] Read stream from ClamAV
87
+ # @return [String] Response
88
+ def self.get_response(clam_av_stream)
89
+ response = ""
90
+ while (data = clam_av_stream.gets)
91
+ response += data
92
+ end
93
+ response
94
+ end
95
+
96
+ private_class_method :get_response
97
+
98
+ # Sends file contents from stream to ClamAV
99
+ # @param clam_av_stream [IO] Stream to ClamAV
100
+ # @param configuration [RubyClamdscan::Configuration] Params defining how much data to send per chunk
101
+ # @param file_input_stream [IO] Stream to read file contents from
102
+ def self.send_contents(clam_av_stream, configuration, file_input_stream)
103
+ clam_av_stream.write(SCAN_COMMAND) # Write the command to tell ClamAV to start scanning
104
+ clam_av_stream.flush
105
+ while (chunk = file_input_stream.read(configuration.chunk_size))
106
+ chunk_len = [chunk.length].pack("N")
107
+ clam_av_stream.write(chunk_len + chunk)
108
+ clam_av_stream.flush
109
+ end
110
+ clam_av_stream.write([0x00, 0x00, 0x00, 0x00].pack("NNNN"))
111
+ clam_av_stream.flush
112
+ end
113
+
114
+ private_class_method :send_contents
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/commands/utils"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Status commands for ClamAV
8
+ module Status
9
+ # Attempts to ping the ClamAV server
10
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
11
+ # @raise [RubyClamdscan::Exceptions::EmptyResponseError] If server response is empty
12
+ def self.ping_server(configuration)
13
+ RubyClamdscan::Commands::Utils.send_single_command("PING", configuration)
14
+ end
15
+
16
+ # Attempts to retrieve the ClamAV server's version information
17
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
18
+ # @raise [RubyClamdscan::Exceptions::EmptyResponseError] If server response is empty
19
+ def self.server_version(configuration)
20
+ RubyClamdscan::Commands::Utils.send_single_command("VERSION", configuration)
21
+ end
22
+
23
+ # Replies with statistics about the scan queue, contents of scan queue, and memory usage
24
+ # Because the format of this response is subject to change, this method will only return the string
25
+ # Uses "nSTATS\n", blocks in the returned response will be separated by the \n character
26
+ # @param configuration [RubyClamdscan::Configuration] configuration for building the ClamAV connection
27
+ # @return [String] Format (currently):
28
+ # "POOLS: 1\n\nSTATE: VALID PRIMARY\nTHREADS: live 1 idle 0 max 10 idle-timeout 30\nQUEUE: 0 items\n\tSTATS 0.000375 \n\n
29
+ # MEMSTATS: heap N/A mmap N/A used N/A free N/A releasable N/A pools 1 pools_used 1281.773M pools_total 1281.827M\nEND"
30
+ # @raise [RubyClamdscan::Errors::EmptyResponseError] If server response is empty
31
+ def self.server_stats(configuration)
32
+ RubyClamdscan::Commands::Utils.send_single_command("nSTATS\n", configuration)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/errors/clamav_errors"
4
+
5
+ module RubyClamdscan
6
+ module Commands
7
+ # Utilities for running commands
8
+ module Utils
9
+ # Sends a single command to the ClamAV server and return its response
10
+ # @param command [String] Command to send
11
+ # @param configuration [RubyClamdscan::Configuration] Configuration used for building socket
12
+ # @return [String] Response from ClamAV server
13
+ # @raise [RubyClamdscan::Errors::EmptyResponseError] if configuration.raise_error_on_empty_response is true and server doesn't send response
14
+ # @raise
15
+ def self.send_single_command(command, configuration)
16
+ response = ""
17
+ begin
18
+ clam_av_stream = RubyClamdscan::Socket.open_clamav_socket(configuration)
19
+ clam_av_stream.write(command)
20
+ clam_av_stream.flush
21
+
22
+ while (data = clam_av_stream.gets)
23
+ response += data
24
+ end
25
+
26
+ response = response.strip
27
+ rescue StandardError => e
28
+ raise RubyClamdscan::Errors::ClamAVCommunicationError.new(command, e)
29
+ ensure
30
+ clam_av_stream&.close
31
+ end
32
+
33
+ raise RubyClamdscan::Errors::EmptyResponseError, command if configuration.raise_error_on_empty_response && response.empty?
34
+
35
+ response
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ # Configuration for the gem
5
+ class Configuration
6
+ # TCP Port ClamAV is listening on if using TCP
7
+ # Default: 3310
8
+ # @return [Integer]
9
+ attr_accessor :tcp_port
10
+
11
+ # Host ClamAV is listening on if using TCP
12
+ # Default: localhost
13
+ # @return [String]
14
+ attr_accessor :tcp_host
15
+
16
+ # Unix Socket for ClamAV
17
+ # Default: /tmp/clamd.socket
18
+ # @return [String]
19
+ attr_accessor :unix_socket
20
+
21
+ # Chunk size in bytes for streaming files
22
+ # Default: 1024
23
+ # @return [Integer]
24
+ attr_accessor :chunk_size
25
+
26
+ # If TCP socket should be used. If false, the Unix socket will be used instead
27
+ # Note, if running ClamAV on the same host, it is recommended to use the Unix socket as it's much faster
28
+ # Default: false
29
+ # @return [Boolean]
30
+ attr_accessor :use_tcp_socket
31
+
32
+ # If the server responds with an empty string, raise an error instead of just returning the empty string
33
+ # Default: true
34
+ # @return [Boolean]
35
+ attr_accessor :raise_error_on_empty_response
36
+
37
+ # If a virus is detected in the scanned contents, raise an error
38
+ # RubyClamdscan::Commands::Scan methods will raise RubyClamdscan::Errors::VirusDetected
39
+ # Default: true
40
+ # @return [Boolean]
41
+ attr_accessor :raise_error_on_virus_detected
42
+
43
+ def initialize
44
+ @tcp_host = "localhost"
45
+ @tcp_port = 3310
46
+ @chunk_size = 1024
47
+ @unix_socket = "/tmp/clamd.socket"
48
+ @raise_error_on_empty_response = true
49
+ @raise_error_on_virus_detected = true
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ module Errors
5
+ # Raised when ClamAV returns an empty response - usually means that the server has not finished starting or is shutdown
6
+ class EmptyResponseError < StandardError
7
+ # @param command [String] Command that failed
8
+ # @param msg [String, nil] Optional message
9
+ def initialize(command, msg: nil)
10
+ msg = "Got empty response when attempting to run command: #{command}. Are you sure the ClamAV server is running?" unless msg.nil?
11
+ super(msg)
12
+ end
13
+ end
14
+
15
+ # Raised when there is some error in communicating with the ClamAV server
16
+ # @param command [String] Command that failed
17
+ # @param cause [StandardError, nil] Underlying error if found
18
+ # @param msg [String, nil] Optional message
19
+ class ClamAVCommunicationError < StandardError
20
+ # @return [StandardError, nil] Underlying error if found
21
+ attr_reader :cause
22
+
23
+ def initialize(command, cause, msg: nil)
24
+ @cause = cause
25
+ msg = "Error while communicating with ClamAV - cause: #{cause&.msg} command: #{command}." unless msg.nil?
26
+ super(msg)
27
+ end
28
+ end
29
+
30
+ # Raised if ClamAV detects malware in the scanned contents
31
+ class VirusDetectedError < StandardError
32
+ # @return [RubyClamdscan::Models::ScanResult] Information about scan and virus
33
+ attr_reader :scan_result
34
+
35
+ # @param scan_result [RubyClamdscan::Models::ScanResult] Information about scan result
36
+ # @param msg [String, nil] Optional message
37
+ def initialize(scan_result, msg: nil)
38
+ @scan_result = scan_result
39
+ msg = "Detected malware in scanned contents: #{scan_result.virus_info}" unless msg.nil?
40
+ super(msg)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ module Models
5
+ # Represents the result from scanning a file with ClamAV
6
+ class ScanResult
7
+ # If the command successfully - does not indicate file was safe! Check contains_virus for that information
8
+ # @return [Boolean]
9
+ attr_reader :is_successful
10
+
11
+ # If ClamAV detected malware in the passed file, will be nil if there was an error running the command
12
+ # @return [Boolean, nil]
13
+ attr_reader :contains_virus
14
+
15
+ # Returns the error string if the command failed
16
+ # @return [Exception, nil]
17
+ attr_reader :exception
18
+
19
+ # Returns the error string if the command failed
20
+ # @return [String, nil]
21
+ attr_reader :error_message
22
+
23
+ # Returns virus information if a virus was detected
24
+ # Value is the response from ClamAV, the malware classification - should be in the form of "Win.Test.EICAR_HDB-1"
25
+ # @return [String, nil]
26
+ attr_reader :virus_info
27
+
28
+ def initialize(is_successful:, contains_virus:, virus_info: nil, exception: nil, error_message: nil)
29
+ @is_successful = is_successful
30
+ @contains_virus = contains_virus
31
+ @exception = exception
32
+ @error_message = error_message
33
+ @virus_info = virus_info
34
+ end
35
+ end
36
+
37
+ class StatsResult
38
+ attr_reader :total_pools, :state, :threads_live, :threads_idle, :threads_max
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+
5
+ module RubyClamdscan
6
+ # Socket related methods to open communication
7
+ module Socket
8
+ # Open a socket to ClamAV based on RubyClamdscan.Configuration
9
+ # @param configuration [RubyClamdscan::Configuration] configuration used to determine socket
10
+ # @return [IO]
11
+ def self.open_clamav_socket(configuration)
12
+ if configuration.use_tcp_socket
13
+ open_tcp_socket(configuration)
14
+ else
15
+ open_unix_socket(configuration)
16
+ end
17
+ end
18
+
19
+ def self.open_tcp_socket(configuration)
20
+ TCPSocket.open(configuration.tcp_host, configuration.tcp_port)
21
+ end
22
+
23
+ private_class_method :open_tcp_socket
24
+
25
+ def self.open_unix_socket(configuration)
26
+ UNIXSocket.new(configuration.unix_socket)
27
+ end
28
+
29
+ private_class_method :open_unix_socket
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyClamdscan
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_clamdscan/socket"
4
+ require "ruby_clamdscan/commands/scan"
5
+ require "ruby_clamdscan/commands/manage"
6
+ require "ruby_clamdscan/commands/status"
7
+ require "ruby_clamdscan/configuration"
8
+ require "ruby_clamdscan/version"
9
+
10
+ # Utility for interacting with ClamAV
11
+ module RubyClamdscan
12
+ class << self
13
+ # Configuration to use interacting with the ClamAV server
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ @configuration.use_tcp_socket = true
17
+ @configuration.tcp_host = "localhost"
18
+ @configuration.tcp_port = 3310
19
+
20
+ @configuration
21
+ end
22
+
23
+ # Configure RubyClamdscan
24
+ def configure
25
+ yield(configuration)
26
+ end
27
+
28
+ # Scans a file
29
+ # @param filepath [String] Path to file in local storage
30
+ # @return [RubyClamdscan::Models::ScanResult] Result from the scan attempt
31
+ def scan_file_from_path(filepath)
32
+ RubyClamdscan::Commands::Scan.scan_file(filepath, @configuration)
33
+ end
34
+
35
+ # Scans the contents of the stream passed in
36
+ # @param stream [IO] stream of file contents
37
+ # @return [RubyClamdscan::Models::ScanResult] Result from the scan attempt
38
+ def scan_contents(stream)
39
+ RubyClamdscan::Commands::Scan.scan(stream, @configuration)
40
+ end
41
+
42
+ def ping_server
43
+ RubyClamdscan::Commands::Status.ping_server(@configuration)
44
+ end
45
+
46
+ def server_version
47
+ RubyClamdscan::Commands::Status.server_version(@configuration)
48
+ end
49
+
50
+ def server_stats
51
+ RubyClamdscan::Commands::Status.server_stats(@configuration)
52
+ end
53
+
54
+ def reload_server_database
55
+ RubyClamdscan::Commands::Manage.reload_server_database(@configuration)
56
+ end
57
+
58
+ def shutdown_server
59
+ RubyClamdscan::Commands::Manage.shutdown_server(@configuration)
60
+ end
61
+ end
62
+ end