Custom
To create a custom scanner, you are required to create two components:
- A driver-specific scan status.
- The actual scanner (aka. the driver).
Scan Status
The scan Status
component is responsible for parsing / resolving the output or response from an antivirus software or service. For instance, for an online antivirus service, e.g. like VirusTotal, the API response must be evaluated. Whereas for a CLI command, the return code must be checked, and so on.
You can create a status component by inheriting from the BaseStatus
abstraction.
use Aedart\Antivirus\Exceptions\UnsupportedStatusValue;
use Aedart\Antivirus\Results\BaseStatus;
use Illuminate\Contracts\Process\ProcessResult;
class MalwareScanStatus extends BaseStatus
{
public function resolveValue(mixed $value): ProcessResult
{
if (!($value instanceof ProcessResult)) {
throw new UnsupportedStatusValue('Invalid value type...');
}
return $value;
}
public function isOk(): bool
{
return $this->value()->successful();
}
public function __toString()
{
$value = $this->value();
return match(true) {
$value->successful() => $this->valueWithReason('Clean'),
default => $this->valueWithReason('Infected'),
};
}
}
The status component may also hold other antivirus software- or service-specific status related methods.
Scanner (driver)
A scanner (or driver) is responsible for passing the file stream on to an actual antivirus scanner, and return an an appropriate ScanResult
instance. Consider the following example:
use Aedart\Antivirus\Scanners\BaseScanner;
use Aedart\Contracts\Antivirus\Results\ScanResult;
use Aedart\Contracts\Streams\FileStream;
use Illuminate\Process\Factory;
use Illuminate\Support\Facades\Process;
use Acme\Antivirus\MalwareScanStatus;
class MalwareScanner extends BaseScanner
{
public function scanStream(FileStream $stream): ScanResult
{
// Obtain profile specific options (if needed)
$command = $this->get('command', '/var/lib/anti_malware');
// Scan the file...
$nativeResult = $this
->driver()
->run($command . ' -file ' . $stream->uri());
// Parse native result into status and return scan result
return $this->makeScanResult(
status: $this->makeScanStatus($nativeResult),
file: $stream,
);
}
protected function statusClass(): string
{
return MalwareScanStatus::class;
}
protected function makeDriver(): Factory
{
return Process::getFacadeRoot();
}
}
Options
Once you have a status and a scanner component completed, you can add it to your configuration of available antivirus scanner profiles.
return [
// ...previous not shown...
/*
|--------------------------------------------------------------------------
| Scanner Profiles
|--------------------------------------------------------------------------
*/
'profiles' => [
'virus_total' => [
'driver' => \Acme\Antivirus\Scanners\VirusTotal::class,
'options' => [
'command' => '/var/lib/anti_malware',
// ...etc
],
],
// ... other profiles not shown...
]
];