files_antivirus/lib/Item.php

249 строки
6.0 KiB
PHP

<?php
/**
* Copyright (c) 2015 Victor Dubiniuk <victor.dubiniuk@gmail.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Antivirus;
use OCA\Files_Antivirus\Activity\Provider;
use OCA\Files_Antivirus\AppInfo\Application;
use OCA\Files_Antivirus\Db\ItemMapper;
use OCP\Activity\IManager as ActivityManager;
use OCP\App;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\Files\File;
use OCP\Files\IRootFolder;
use OCA\Files_Trashbin\Trash\ITrashManager;
use OCP\ILogger;
class Item {
/**
* file handle, user to read from the file
* @var resource
*/
protected $fileHandle;
/** @var AppConfig */
private $config;
/** @var ActivityManager */
private $activityManager;
/** @var ItemMapper */
private $itemMapper;
/** @var ILogger */
private $logger;
/** @var IRootFolder */
private $rootFolder;
/** @var File */
private $file;
private $isCron;
/**
* Item constructor.
*
* @param AppConfig $appConfig
* @param ActivityManager $activityManager
* @param ItemMapper $itemMapper
* @param ILogger $logger
* @param IRootFolder $rootFolder
* @param File $file
* @param bool $isCron
*/
public function __construct(AppConfig $appConfig,
ActivityManager $activityManager,
ItemMapper $itemMapper,
ILogger $logger,
IRootFolder $rootFolder,
File $file,
$isCron) {
$this->config = $appConfig;
$this->activityManager = $activityManager;
$this->itemMapper = $itemMapper;
$this->logger = $logger;
$this->rootFolder = $rootFolder;
$this->file = $file;
$this->isCron = $isCron;
}
/**
* Reads a file portion by portion until the very end
* @return string|boolean
*/
public function fread() {
if (!($this->file->getSize() > 0)) {
return false;
}
if (is_null($this->fileHandle)) {
$this->getFileHandle();
}
if (!is_null($this->fileHandle) && !$this->feof()) {
return fread($this->fileHandle, $this->config->getAvChunkSize());
}
return false;
}
/**
* Action to take if this item is infected
*/
public function processInfected(Status $status) {
$infectedAction = $this->config->getAvInfectedAction();
$shouldDelete = $infectedAction === 'delete';
$message = $shouldDelete ? Provider::MESSAGE_FILE_DELETED : '';
$userFolder = $this->rootFolder->getUserFolder($this->file->getOwner()->getUID());
$path = $userFolder->getRelativePath($this->file->getPath());
$activity = $this->activityManager->generateEvent();
$activity->setApp(Application::APP_NAME)
->setSubject(Provider::SUBJECT_VIRUS_DETECTED_SCAN, [$status->getDetails()])
->setMessage($message)
->setObject('file', $this->file->getId(), $path)
->setAffectedUser($this->file->getOwner()->getUID())
->setType(Provider::TYPE_VIRUS_DETECTED);
$this->activityManager->publish($activity);
if ($shouldDelete) {
if ($this->isCron) {
$msg = 'Infected file deleted (during background scan)';
} else {
$msg = 'Infected file deleted.';
}
$this->logError($msg . ' ' . $status->getDetails());
$this->deleteFile();
} else {
if ($this->isCron) {
$msg = 'Infected file found (during background scan)';
} else {
$msg = 'Infected file found.';
}
$this->logError($msg . ' ' . $status->getDetails());
$this->updateCheckTime();
}
}
/**
* Action to take if this item status is unclear
* @param Status $status
*/
public function processUnchecked(Status $status) {
//TODO: Show warning to the user: The file can not be checked
$this->logError('Not Checked. ' . $status->getDetails());
}
/**
* Action to take if this item status is not infected
*/
public function processClean() {
$this->updateCheckTime();
}
/**
* Update the check-time of this item to current time
*/
private function updateCheckTime() {
try {
try {
$item = $this->itemMapper->findByFileId($this->file->getId());
$this->itemMapper->delete($item);
} catch (DoesNotExistException $e) {
//Just ignore
}
$item = new \OCA\Files_Antivirus\Db\Item();
$item->setFileid($this->file->getId());
$item->setCheckTime(time());
$this->itemMapper->insert($item);
} catch (\Exception $e) {
$this->logger->error(__METHOD__.', exception: '.$e->getMessage(), ['app' => 'files_antivirus']);
}
}
/**
* Check if the end of file is reached
* @return boolean
*/
private function feof() {
$isDone = feof($this->fileHandle);
if ($isDone) {
$this->logDebug('Scan is done');
fclose($this->fileHandle);
$this->fileHandle = null;
}
return $isDone;
}
/**
* Opens a file for reading
* @throws \RuntimeException
*/
private function getFileHandle() {
$fileHandle = $this->file->fopen('r');
if ($fileHandle === false) {
$this->logError('Can not open for reading.');
throw new \RuntimeException();
}
$this->logDebug('Scan started');
$this->fileHandle = $fileHandle;
}
/**
* Delete infected file
*/
private function deleteFile() {
//prevent from going to trashbin
if (App::isEnabled('files_trashbin')) {
/** @var ITrashManager $trashManager */
$trashManager = \OC::$server->query(ITrashManager::class);
$trashManager->pauseTrash();
}
$this->file->delete();
if (App::isEnabled('files_trashbin')) {
/** @var ITrashManager $trashManager */
$trashManager = \OC::$server->query(ITrashManager::class);
$trashManager->resumeTrash();
}
}
private function generateExtraInfo() {
$owner = $this->file->getOwner();
if ($owner === null) {
$ownerInfo = ' Account: NO OWNER FOUND';
} else {
$ownerInfo = ' Account: ' . $owner->getUID();
}
$extra = ' File: ' . $this->file->getId()
. $ownerInfo
. ' Path: ' . $this->file->getPath();
return $extra;
}
/**
* @param string $message
*/
public function logDebug($message) {
$this->logger->debug($message . $this->generateExtraInfo(), ['app' => 'files_antivirus']);
}
/**
* @param string $message
*/
public function logError($message) {
$this->logger->error($message . $this->generateExtraInfo(), ['app' => 'files_antivirus']);
}
}