clamav-client 1.0.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,120 @@
1
+ # ClamAV::Client
2
+
3
+ ClamAV::Client is a client library that can talk to the clam daemon.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'clamav-client', require: 'clamav/client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install clamav-client
18
+
19
+ Alternatively, you can spawn a `pry` console right away by just running:
20
+
21
+ $ rake console
22
+
23
+ ## Requirements
24
+
25
+ * Ruby >= 2 (and Ruby >= 2.1 to be able to contribute to the project as it's making use of required keyword arguments)
26
+ * clamd
27
+
28
+ ## Usage
29
+
30
+ The `ClamAV::Client` class is responsible for opening a connection to a remote
31
+ ClamAV clam daemon.
32
+
33
+ You will find below the implemented commands.
34
+
35
+ ### PING => Boolean
36
+
37
+ Pings the daemon to check whether it is alive.
38
+
39
+ client = ClamAV::Client.new
40
+ client.execute(ClamAV::Commands::PingCommand.new)
41
+ => true
42
+
43
+ ### SCAN <file_or_directory> => Array[Response]
44
+
45
+ Scans a file or a directory for the existence of a virus.
46
+
47
+ The absolute path must be given to that command.
48
+
49
+ client = ClamAV::Client.new
50
+
51
+ client.execute(ClamAV::Commands::ScanCommand.new('/tmp/path/foo.c')
52
+ => [#<ClamAV::SuccessResponse:0x007fbf314b9478 @file="/tmp/foo.c">]
53
+
54
+ client.execute(ClamAV::Commands::ScanCommand.new('/tmp/path')
55
+ => [#<ClamAV::SuccessResponse:0x007fc30c273298 @file="/tmp/path/foo.c">,
56
+ #<ClamAV::SuccessResponse:0x007fc30c272910 @file="/tmp/path/foo.cpp">]
57
+
58
+
59
+ ### Custom commands
60
+
61
+ Custom commands can be given to the client. The contract between the client
62
+ and the command is thru the `call` method call. The `call` method is being
63
+ passed a `Connection` object.
64
+
65
+ Here's a simple example that implements the `VERSION` command:
66
+
67
+ # Build the client
68
+ client = ClamAV::Client.new
69
+
70
+ # Create the command lambda
71
+ version_command = lambda { |conn| conn.send_request("VERSION") }
72
+ => #<Proc:0x007fc0d0c14b28>
73
+
74
+ # Execute the command
75
+ client.execute(version_command)
76
+ => "1: ClamAV 0.98.1/18489/Tue Feb 18 16:00:05 2014"
77
+
78
+
79
+ ## Defaults
80
+
81
+ The default values in use are:
82
+
83
+ * clamd socket: UNIX Socket, located at `/tmp/clamd/socket`;
84
+ * New-line terminated commands.
85
+
86
+ These defaults can be changed by injecting new defaults.
87
+
88
+ ## Injecting dependencies
89
+
90
+ ### Client
91
+
92
+ The main object is the `Client` object. It is responsible for executing the commands.
93
+ This object can receive a custom connection object.
94
+
95
+ ### Connection
96
+
97
+ The connection object is the bridge between the raw socket object and the
98
+ protocol being used between the client and the daemon.
99
+
100
+ `clamd` supports two kinds of delimiters:
101
+
102
+ * NULL terminated commands
103
+ * New-line terminated commands
104
+
105
+ The management of those delimiters is done with the wrapper argument.
106
+
107
+ ### Wrapper
108
+
109
+ The wrapper is responsible for taking the incoming request with the
110
+ `wrap_request` method, and parsing the response with the `read_response`
111
+ method.
112
+
113
+
114
+ ## Contributing
115
+
116
+ 1. Fork it ( https://github.com/franckverrot/clamav-client/fork )
117
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
118
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
119
+ 4. Push to the branch (`git push origin my-new-feature`)
120
+ 5. Create new Pull Request
@@ -0,0 +1,104 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'rubygems'
18
+ require 'rubygems/specification'
19
+
20
+ require 'bundler'
21
+ Bundler::GemHelper.install_tasks
22
+
23
+ $:<< 'lib'
24
+ require 'clamav/client'
25
+
26
+ $stdout.puts """
27
+ ClamAV::Client Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
28
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `rake license'.
29
+ This is free software, and you are welcome to redistribute it
30
+ under certain conditions; type `rake license' for details.
31
+
32
+ """
33
+
34
+ require 'rake/testtask'
35
+ Rake::TestTask.new do |t|
36
+ t.libs << "test"
37
+ t.pattern = "test/**/*_test.rb"
38
+ #t.verbose = true
39
+ #t.warning = true
40
+ end
41
+
42
+ Rake::TestTask.new(:unit_tests) do |t|
43
+ t.libs << "test"
44
+ t.pattern = "test/unit/**/*_test.rb"
45
+ #t.verbose = true
46
+ #t.warning = true
47
+ end
48
+
49
+ Rake::TestTask.new(:integration_tests) do |t|
50
+ t.libs << "test"
51
+ t.pattern = "test/integration/**/*_test.rb"
52
+ #t.verbose = true
53
+ #t.warning = true
54
+ end
55
+
56
+
57
+ def gemspec
58
+ @gemspec ||= begin
59
+ file = File.expand_path('../clamav-client.gemspec', __FILE__)
60
+ eval(File.read(file), binding, file)
61
+ end
62
+ end
63
+
64
+ desc "Clean the current directory"
65
+ task :clean do
66
+ rm_rf 'tmp'
67
+ rm_rf 'pkg'
68
+ end
69
+
70
+ desc "Run the full spec suite"
71
+ task :full => ["clean", "test"]
72
+
73
+ desc "install the gem locally"
74
+ task :install => :package do
75
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
76
+ end
77
+
78
+ desc "validate the gemspec"
79
+ task :gemspec do
80
+ gemspec.validate
81
+ end
82
+
83
+ desc "Build the gem"
84
+ task :gem => [:gemspec, :build] do
85
+ mkdir_p "pkg"
86
+ sh "gem build clamav-client.gemspec"
87
+ mv "#{gemspec.full_name}.gem", "pkg"
88
+ end
89
+
90
+ desc "Install ClamAV::Client"
91
+ task :install => :gem do
92
+ sh "gem install pkg/#{gemspec.full_name}.gem"
93
+ end
94
+
95
+ task :default => :full
96
+
97
+ task :license do
98
+ `open http://www.gnu.org/licenses/gpl.txt`
99
+ end
100
+
101
+ task :console do
102
+ require 'pry'
103
+ Pry.start
104
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ $:<< 'lib'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "clamav-client"
6
+ spec.version = "1.0.0"
7
+ spec.authors = ["Franck Verrot"]
8
+ spec.email = ["franck@verrot.fr"]
9
+ spec.summary = %q{ClamAV::Client connects to a Clam Anti-Virus clam daemon and send commands.}
10
+ spec.description = spec.summary
11
+ spec.homepage = "https://github.com/franckverrot/clamav-client"
12
+ spec.license = "GPLv3"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.5"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "pry"
22
+ end
@@ -0,0 +1,43 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require "clamav/connection"
18
+ require "clamav/commands/ping_command"
19
+ require "clamav/commands/quit_command"
20
+ require "clamav/commands/scan_command"
21
+ require "clamav/util"
22
+ require "clamav/wrappers/new_line_wrapper"
23
+ require "clamav/wrappers/null_termination_wrapper"
24
+
25
+ module ClamAV
26
+ class Client
27
+ def initialize(connection = default_connection)
28
+ @connection = connection
29
+ connection.establish_connection
30
+ end
31
+
32
+ def execute(command)
33
+ command.(@connection)
34
+ end
35
+
36
+ def default_connection
37
+ ClamAV::Connection.new(
38
+ socket: ::UNIXSocket.new('/tmp/clamd.socket'),
39
+ wrapper: ::ClamAV::Wrappers::NewLineWrapper.new
40
+ )
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ module ClamAV
17
+ module Commands
18
+ class Command
19
+ def call
20
+ raise NotImplementedError.new
21
+ end
22
+
23
+ protected
24
+ def execute
25
+ conn.puts data + "\n"
26
+ response = conn.gets.chomp
27
+ conn.close
28
+ response
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ require 'clamav/commands/command'
17
+
18
+ module ClamAV
19
+ module Commands
20
+ class PingCommand < Command
21
+ def call(conn)
22
+ !!(/\d+: PONG/.match(conn.send_request("PING")))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ require 'clamav/commands/command'
17
+
18
+ module ClamAV
19
+ module Commands
20
+ class QuitCommand < Command
21
+ def call(conn)
22
+ conn.send_request("QUIT").nil?
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,54 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'clamav/commands/command'
18
+ require 'clamav/responses/error_response'
19
+ require 'clamav/responses/success_response'
20
+ require 'clamav/responses/virus_response'
21
+ module ClamAV
22
+ module Commands
23
+ class ScanCommand < Command
24
+ Statuses = {
25
+ 'ERROR' => ClamAV::ErrorResponse,
26
+ 'OK' => ClamAV::SuccessResponse,
27
+ 'ClamAV-Test-Signature FOUND' => ClamAV::VirusResponse
28
+ }
29
+
30
+ def initialize(path, path_finder = Util)
31
+ @path, @path_finder = path, path_finder
32
+ end
33
+
34
+ def call(conn)
35
+ @path_finder.path_to_files(@path).map { |file| scan_file(conn, file) }
36
+ end
37
+
38
+ protected
39
+ def scan_file(conn, file)
40
+ get_status_from_response(conn.send_request("SCAN #{file}"))
41
+ end
42
+
43
+ def get_status_from_response(str)
44
+ case str
45
+ when 'Error processing command. ERROR'
46
+ ErrorResponse.new(str)
47
+ else
48
+ /(?<id>\d+): (?<filepath>.*): (?<status>.*)/ =~ str
49
+ Statuses[status].new(filepath)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'socket'
18
+
19
+ module ClamAV
20
+ class Connection
21
+ def initialize(socket:, wrapper:)
22
+ @socket = socket
23
+ @wrapper = wrapper
24
+ end
25
+
26
+ def establish_connection
27
+ wrapped_request = @wrapper.wrap_request("IDSESSION")
28
+ @socket.write wrapped_request
29
+ end
30
+
31
+ def send_request(str)
32
+ wrapped_request = @wrapper.wrap_request(str)
33
+ @socket.write wrapped_request
34
+ @wrapper.read_response(@socket)
35
+ end
36
+ end
37
+ end