Completed
Pull Request — master (#225)
by Victor
05:30 queued 04:01
created

Item::logDebug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Copyright (c) 2015 Viktar Dubiniuk <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file.
7
 */
8
9
namespace OCA\Files_Antivirus;
10
11
use OCP\IL10N;
12
use OCA\Files_Antivirus\Status;
13
use OCA\Files_Antivirus\Activity;
14
15
class Item implements IScannable{
16
	/**
17
	 * Scanned fileid (optional)
18
	 *
19
	 * @var int
20
	 */
21
	protected $id;
22
	
23
	/**
24
	 * File view
25
	 *
26
	 * @var \OC\Files\View
27
	 */
28
	protected $view;
29
	
30
	/**
31
	 * Path relative to the view
32
	 *
33
	 * @var string
34
	 */
35
	protected $path;
36
	
37
	/**
38
	 * file handle, user to read from the file
39
	 *
40
	 * @var resource
41
	 */
42
	protected $fileHandle;
43
	
44
	/**
45
	 * Portion size
46
	 *
47
	 * @var int
48
	 */
49
	protected $chunkSize;
50
	
51
	/**
52
	 * Is filesize match the size conditions
53
	 *
54
	 * @var bool
55
	 */
56
	protected $isValidSize;
57
	
58
	/**
59
	 * @var IL10N
60
	 */
61
	private $l10n;
62
	
63 5
	public function __construct(IL10N $l10n, $view, $path, $id = null) {
64 5
		$this->l10n = $l10n;
65
		
66 5
		if (!is_object($view)) {
67
			$this->logError('Can\'t init filesystem view.', $id, $path);
68
			throw new \RuntimeException();
69
		}
70
		
71 5
		if (!$view->file_exists($path)) {
72 1
			$this->logError('File does not exist.', $id, $path);
73 1
			throw new \RuntimeException();
74
		}
75
		
76 5
		if (is_null($id)) {
77 1
			$this->id = $view->getFileInfo($path)->getId();
78
		} else {
79 4
			$this->id = $id;
80
		}
81
		
82 5
		$this->view = $view;
83 5
		$this->path = $path;
84
		
85 5
		$this->isValidSize = $view->filesize($path) > 0;
86
		
87 5
		$application = new AppInfo\Application();
88 5
		$config = $application->getContainer()->query('AppConfig');
89 5
		$this->chunkSize = $config->getAvChunkSize();
90 5
	}
91
	
92
	/**
93
	 * Is this file good for scanning?
94
	 *
95
	 * @return boolean
96
	 */
97 3
	public function isValid() {
98 3
		$isValid = !$this->view->is_dir($this->path) && $this->isValidSize;
99 3
		return $isValid;
100
	}
101
	
102
	/**
103
	 * Reads a file portion by portion until the very end
104
	 *
105
	 * @return string|boolean
106
	 */
107 3
	public function fread() {
108 3
		if (!$this->isValid()) {
109
			return;
110
		}
111 3
		if (is_null($this->fileHandle)) {
112 3
			$this->getFileHandle();
113
		}
114
		
115 3
		if (!is_null($this->fileHandle) && !$this->feof()) {
116 3
			$chunk = fread($this->fileHandle, $this->chunkSize);
117 3
			return $chunk;
118
		}
119 2
		return false;
120
	}
121
	
122
	/**
123
	 * Action to take if this item is infected
124
	 *
125
	 * @param Status $status
126
	 * @param boolean $isBackground
127
	 */
128
	public function processInfected(Status $status, $isBackground) {
129
		$application = new AppInfo\Application();
130
		$appConfig = $application->getContainer()->query('AppConfig');
131
		$infectedAction = $appConfig->getAvInfectedAction();
132
		
133
		$shouldDelete = !$isBackground || ($isBackground && $infectedAction === 'delete');
134
		
135
		$message = $shouldDelete ? Activity::MESSAGE_FILE_DELETED : '';
136
		
137
		\OC::$server->getActivityManager()->publishActivity(
138
			'files_antivirus',
139
			Activity::SUBJECT_VIRUS_DETECTED,
140
			[$this->path, $status->getDetails()],
141
			$message,
142
			[],
143
			$this->path,
144
			'',
145
			$this->view->getOwner($this->path),
146
			Activity::TYPE_VIRUS_DETECTED,
147
			Activity::PRIORITY_HIGH
148
		);
149
		if ($isBackground) {
150
			if ($shouldDelete) {
151
				$this->logError('Infected file deleted. ' . $status->getDetails());
152
				$this->view->unlink($this->path);
153
			} else {
154
				$this->logError('File is infected. ' . $status->getDetails());
155
			}
156
		} else {
157
			$this->logError('Virus(es) found: ' . $status->getDetails());
158
			//remove file
159
			$this->view->unlink($this->path);
160
			Notification::sendMail($this->path);
161
			$message = $this->l10n->t(
162
				"Virus detected! Can't upload the file %s",
163
				[basename($this->path)]
164
			);
165
			\OCP\JSON::error(["data" => ["message" => $message]]);
166
			exit();
167
		}
168
	}
169
170
	/**
171
	 * Action to take if this item status is unclear
172
	 *
173
	 * @param Status $status
174
	 * @param boolean $isBackground
175
	 */
176
	public function processUnchecked(Status $status, $isBackground) {
0 ignored issues
show
Unused Code introduced by
The parameter $isBackground is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
177
		//TODO: Show warning to the user: The file can not be checked
178
		$this->logError('Not Checked. ' . $status->getDetails());
179
	}
180
	
181
	/**
182
	 * Action to take if this item status is not infected
183
	 *
184
	 * @param Status $status
185
	 * @param boolean $isBackground
186
	 */
187
	public function processClean(Status $status, $isBackground) {
0 ignored issues
show
Unused Code introduced by
The parameter $status is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
188
		if (!$isBackground) {
189
			return;
190
		}
191
		try {
192
			$stmt = \OCP\DB::prepare('DELETE FROM `*PREFIX*files_antivirus` WHERE `fileid` = ?');
193
			$result = $stmt->execute(array($this->id));
194
			if (\OCP\DB::isError($result)) {
195
				//TODO: Use logger
196
				$this->logError(__METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage());
197
			}
198
			$stmt = \OCP\DB::prepare(
199
				'INSERT INTO `*PREFIX*files_antivirus` (`fileid`, `check_time`) VALUES (?, ?)'
200
			);
201
			$result = $stmt->execute(array($this->id, time()));
202
			if (\OCP\DB::isError($result)) {
203
				$this->logError(__METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage());
204
			}
205
		} catch(\Exception $e) {
206
			\OCP\Util::writeLog(
207
				'files_antivirus',
208
				__METHOD__ . ', exception: ' . $e->getMessage(),
209
				\OCP\Util::ERROR
210
			);
211
		}
212
	}
213
214
	/**
215
	 * Check if the end of file is reached
216
	 *
217
	 * @return boolean
218
	 */
219 3
	private function feof() {
220 3
		$isDone = feof($this->fileHandle);
221 3
		if ($isDone) {
222 2
			$this->logDebug('Scan is done');
223 2
			fclose($this->fileHandle);
224 2
			$this->fileHandle = null;
225
		}
226 3
		return $isDone;
227
	}
228
	
229
	/**
230
	 * Opens a file for reading
231
	 *
232
	 * @throws \RuntimeException
233
	 */
234 3
	private function getFileHandle() {
235 3
		$fileHandle = $this->view->fopen($this->path, "r");
236 3
		if ($fileHandle === false) {
237
			$this->logError('Can not open for reading.', $this->id, $this->path);
238
			throw new \RuntimeException();
239
		} else {
240 3
			$this->logDebug('Scan started');
241 3
			$this->fileHandle = $fileHandle;
242
		}
243 3
	}
244
	
245
	/**
246
	 * @param string $message
247
	 */
248 3
	public function logDebug($message) {
249 3
		$extra = ' File: ' . $this->id 
250 3
				. ' Account: ' . $this->view->getOwner($this->path) 
251 3
				. ' Path: ' . $this->path;
252 3
		\OCP\Util::writeLog('files_antivirus', $message . $extra, \OCP\Util::DEBUG);
253 3
	}
254
	
255
	/**
256
	 * @param string $message
257
	 * @param int $id optional
258
	 * @param string $path optional
259
	 */
260 1
	public function logError($message, $id=null, $path=null) {
261 1
		$ownerInfo = is_null($this->view) ? '' : 'Account: ' . $this->view->getOwner($path);
262 1
		$extra = ' File: ' . (is_null($id) ? $this->id : $id)
263 1
				. $ownerInfo 
264 1
				. ' Path: ' . (is_null($path) ? $this->path : $path);
265 1
		\OCP\Util::writeLog(
266 1
			'files_antivirus',
267 1
			$message . $extra,
268 1
			\OCP\Util::ERROR
269
		);
270 1
	}
271
}
272