Completed
Pull Request — master (#195)
by Victor
10:00 queued 08:41
created

AvirWrapper::fopen()   C

Complexity

Conditions 10
Paths 8

Size

Total Lines 75
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 32.013

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 75
ccs 21
cts 53
cp 0.3962
rs 5.7647
cc 10
eloc 53
nc 8
nop 2
crap 32.013

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (c) 2014 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 OC\Files\Filesystem;
12
use OC\Files\Storage\Wrapper\Wrapper;
13
use OCA\Files_Antivirus\Scanner\InitException;
14
use \OCP\App;
15
use \OCP\IL10N;
16
use \OCP\ILogger;
17
use \OCP\Files\InvalidContentException;
18
use \OCP\Files\ForbiddenException;
19
use Icewind\Streams\CallbackWrapper;
20
21
22
class AvirWrapper extends Wrapper{
23
	
24
	/**
25
	 * Modes that are used for writing 
26
	 * @var array 
27
	 */
28
	private $writingModes = array('r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+');
29
30
	/**
31
	 * @var AppConfig
32
	 */
33
	protected $appConfig;
34
35
	/**
36
	 * @var \OCA\Files_Antivirus\ScannerFactory
37
	 */
38
	protected $scannerFactory;
39
	
40
	/**
41
	 * @var IL10N 
42
	 */
43
	protected $l10n;
44
	
45
	/**
46
	 * @var ILogger;
47
	 */
48
	protected $logger;
49
50
	/**
51
	 * @param array $parameters
52
	 */
53 4
	public function __construct($parameters) {
54 4
		parent::__construct($parameters);
55 4
		$this->appConfig = $parameters['appConfig'];
56 4
		$this->scannerFactory = $parameters['scannerFactory'];
57 4
		$this->l10n = $parameters['l10n'];
58 4
		$this->logger = $parameters['logger'];
59 4
	}
60
	
61
	/**
62
	 * Asynchronously scan data that are written to the file
63
	 * @param string $path
64
	 * @param string $mode
65
	 * @return resource | bool
66
	 */
67 4
	public function fopen($path, $mode){
68 4
		$stream = $this->storage->fopen($path, $mode);
69 4
		if (is_resource($stream)
70 4
			&& $this->isWritingMode($mode)
71 4
			&& $this->isScannableSize(basename($path))
72 4
			&& strpos($path, 'uploads/') !== 0
73
		) {
74
			try {
75 2
				$scanner = $this->scannerFactory->getScanner();
76 2
				$scanner->initScanner();
77 2
				return CallBackWrapper::wrap(
78 2
					$stream,
79 2
					null,
80
					function ($data) use ($scanner) {
81
						$scanner->onAsyncData($data);
82 2
					},
83 2
					function () use ($scanner, $path) {
84
						$status = $scanner->completeAsyncScan();
85
						if (intval($status->getNumericStatus()) === \OCA\Files_Antivirus\Status::SCANRESULT_INFECTED) {
86
							//prevent from going to trashbin
87
							if (App::isEnabled('files_trashbin')) {
88
								\OCA\Files_Trashbin\Storage::preRenameHook([
89
									Filesystem::signal_param_oldpath => '',
90
									Filesystem::signal_param_newpath => ''
91
								]);
92
							}
93
94
							$owner = $this->getOwner($path);
95
							$this->unlink($path);
96
97
							if (App::isEnabled('files_trashbin')) {
98
								\OCA\Files_Trashbin\Storage::postRenameHook([]);
99
							}
100
							$this->logger->warning(
101
								'Infected file deleted. ' . $status->getDetails()
102
								. ' Account: ' . $owner . ' Path: ' . $path,
103
								['app' => 'files_antivirus']
104
							);
105
106
							\OC::$server->getActivityManager()->publishActivity(
107
								'files_antivirus',
108
								Activity::SUBJECT_VIRUS_DETECTED,
109
								[$path, $status->getDetails()],
110
								Activity::MESSAGE_FILE_DELETED,
111
								[],
112
								$path,
113
								'',
114
								$owner,
115
								Activity::TYPE_VIRUS_DETECTED,
116
								Activity::PRIORITY_HIGH
117
							);
118
119
							throw new InvalidContentException(
120
								$this->l10n->t(
121
									'Virus %s is detected in the file. Upload cannot be completed.',
122
									$status->getDetails()
123
								)
124
							);
125
						}
126 2
					}
127
				);
128 2
			} catch (InitException $e) {
129 2
				$message = sprintf(
130 2
					'Antivirus app is misconfigured or antivirus inaccessible. %s',
131 2
					$e->getMessage()
132
				);
133 2
				$this->logger->warning($message, ['app' => 'files_antivirus']);
134 2
				throw new ForbiddenException($message, false, $e);
135
			} catch (\Exception $e){
136
				$message = 	implode(' ', [ __CLASS__, __METHOD__, $e->getMessage()]);
137
				$this->logger->warning($message, ['app' => 'files_antivirus']);
138
			}
139
		}
140 2
		return $stream;
141
	}
142
	
143
	/**
144
	 * Checks whether passed mode is suitable for writing 
145
	 * @param string $mode
146
	 * @return bool
147
	 */
148 4
	private function isWritingMode($mode){
149
		// Strip unessential binary/text flags
150 4
		$cleanMode = str_replace(
151 4
			['t', 'b'],
152 4
			['', ''],
153 4
			$mode
154
		);
155 4
		return in_array($cleanMode, $this->writingModes);
156
	}
157
158
	/**
159
	 * checks the size for webdav PUT requests. defaults to true
160
	 * @param $filename
161
	 * @return bool
162
	 */
163 3
	private function isScannableSize($filename) {
164 3
		$scanSizeLimit = intval($this->appConfig->getAvMaxFileSize());
165 3
		$size = false;
166
		
167
		// PUT via webdav
168 3
		if (isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT'){
169
			$size = intval($_SERVER['CONTENT_LENGTH']);
170
		}
171
172 3
		return $scanSizeLimit === -1 || $size === false || $scanSizeLimit >= $size;
173
	}
174
}
175