Current section
Files
Jump to
Current section
Files
lib/clamxir.ex
defmodule Clamxir do
defstruct check: false,
daemonize: false,
stream: false
@moduledoc """
Clamxir is a wrapper for clamav. It requires to have installed clamav in order to work. As a suggestion, run the config with the daemonize flag as it will use the daemon instance of clamav. Also if you run on permission issues, adding stream flag with help you with it.
"""
@doc """
Returns a tuple with the result of the function.
## Examples
iex> Clamxir.file_exists?("README.md")
{:ok, "README.md"}
iex> Clamxir.file_exists?("NO_FILE.md")
{:error, "NO_FILE.md not found."}
"""
def file_exists?(path) do
case File.exists?(path) do
true -> {:ok, path}
false -> {:error, "#{path} not found."}
end
end
@doc """
Returns true if the check flag of config isn't set. Otherwise will
return a boolean if the scanner has been found.
## Examples
iex> Clamxir.scanner_exists?(%Clamxir{})
true
iex> Clamxir.scanner_exists?(%Clamxir{check: true})
true
"""
def scanner_exists?(%Clamxir{check: check} = clamxir_config) do
case check do
false ->
true
_ ->
check_scanner(clamxir_config)
end
end
@doc """
Return boolean with the result if succeded. Otherwise, a tuple with {:error, message}
## Examples
iex> Clamxir.virus?(%Clamxir{}, "README.md")
false
iex> Clamxir.virus?(%Clamxir{stream: true, daemonize: true}, "README.md")
false
iex> Clamxir.virus?(%Clamxir{stream: true, daemonize: true}, "NOT_FOUND.md")
{:error, "NOT_FOUND.md not found."}
"""
def virus?(%Clamxir{} = clamxir_config, path) do
%{clamxir_config: clamxir_config, path: path}
|> check_file_presence
|> check_scanner_presence
|> check_virus
end
@doc """
The oppossite of `virus?/2`.
## Examples
iex> Clamxir.safe?(%Clamxir{stream: true, daemonize: true}, "README.md")
true
iex> Clamxir.safe?(%Clamxir{stream: true, daemonize: true}, "NOT_FOUND.md")
{:error, "NOT_FOUND.md not found."}
"""
def safe?(%Clamxir{} = clamxir_config, path) do
case virus?(clamxir_config, path) do
result when is_boolean(result) -> !result
error -> error
end
end
defp check_file_presence(%{clamxir_config: clamxir_config, path: path}) do
case file_exists?(path) do
{:error, message} -> {:error, message}
{:ok, path} -> %{clamxir_config: clamxir_config, path: path}
end
end
defp check_scanner_presence({:error, _} = status), do: status
defp check_scanner_presence(%{clamxir_config: clamxir_config, path: path}) do
case check_scanner(clamxir_config) do
true -> %{clamxir_config: clamxir_config, path: path}
false -> {:error, "Scanner not found."}
end
end
defp check_virus({:error, _} = status), do: status
defp check_virus(%{clamxir_config: clamxir_config, path: path}) do
run_command(clamxir_config, path)
end
defp run_command(clamxir_config, path) do
clamxir_config.daemonize
|> clamd_executable_name()
|> System.cmd(create_args(clamxir_config, path))
|> check_virus_scann_results()
end
defp create_args(clamxir_config, path) do
command_args =
[]
|> add_stream(clamxir_config)
command_args ++ [path, "--no-summary"]
end
defp add_stream(command, %Clamxir{stream: stream, daemonize: daemonize})
when stream == true and daemonize == true,
do: command ++ ["--stream"]
defp add_stream(command, _), do: command
defp check_scanner(%Clamxir{daemonize: daemonize}) do
daemonize
|> clamd_executable_name()
|> System.find_executable()
|> check_system_results
end
defp check_system_results(nil), do: false
defp check_system_results(path) when is_binary(path), do: true
defp check_virus_scann_results({_, 0}), do: false
defp check_virus_scann_results({message, 2}), do: {:error, message}
defp check_virus_scann_results(_), do: true
defp clamd_executable_name(daemonize) when daemonize == true, do: "clamdscan"
defp clamd_executable_name(_), do: "clamscan"
end