Completed
Pull Request — master (#99)
by Roeland
12:26
created

AvirWrapper::fopen()   C

Complexity

Conditions 11
Paths 5

Size

Total Lines 77

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 66.4128

Importance

Changes 0
Metric Value
dl 0
loc 77
ccs 11
cts 48
cp 0.2292
rs 6.3551
c 0
b 0
f 0
cc 11
nc 5
nop 2
crap 66.4128

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 Victor 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 Icewind\Streams\CallbackWrapper;
12
use OC\Files\Storage\Wrapper\Wrapper;
13
use OCA\Files_Antivirus\Activity\Provider;
14
use OCA\Files_Antivirus\AppInfo\Application;
15
use OCA\Files_Antivirus\Event\ScanStateEvent;
16
use OCA\Files_Antivirus\Scanner\ScannerFactory;
17
use OCP\Activity\IManager as ActivityManager;
18
use OCP\App;
19
use OCP\Files\InvalidContentException;
20
use OCP\IL10N;
21
use OCP\ILogger;
22
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
23
24
class AvirWrapper extends Wrapper{
25
	
26
	/**
27
	 * Modes that are used for writing 
28
	 * @var array 
29
	 */
30
	private $writingModes = ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'];
31
	
32
	/** @var ScannerFactory */
33
	protected $scannerFactory;
34
	
35
	/** @var IL10N */
36
	protected $l10n;
37
	
38
	/** @var ILogger */
39
	protected $logger;
40
41
	/** @var ActivityManager */
42
	protected $activityManager;
43
44
	/** @var bool */
45
	protected $isHomeStorage;
46
47
	/** @var bool */
48
	private $shouldScan = true;
49 2
50 2
	/**
51 2
	 * @param array $parameters
52 2
	 */
53 2
	public function __construct($parameters) {
54 2
		parent::__construct($parameters);
55 2
		$this->scannerFactory = $parameters['scannerFactory'];
56 2
		$this->l10n = $parameters['l10n'];
57
		$this->logger = $parameters['logger'];
58
		$this->activityManager = $parameters['activityManager'];
59
		$this->isHomeStorage = $parameters['isHomeStorage'];
60
61
		/** @var EventDispatcherInterface $eventDispatcher */
62
		$eventDispatcher = $parameters['eventDispatcher'];
63
		$eventDispatcher->addListener(ScanStateEvent::class, function(ScanStateEvent $event) {
64 1
			$this->shouldScan = $event->getState();
65 1
		});
66
	}
67
	
68
	/**
69
	 * Asynchronously scan data that are written to the file
70
	 * @param string $path
71
	 * @param string $mode
72
	 * @return resource | bool
73
	 */
74 1
	public function fopen($path, $mode) {
75
		$stream = $this->storage->fopen($path, $mode);
76 1
77
		/*
78
		 * Only check when
79
		 *  - it is a resource
80
		 *  - it is a writing mode
81
		 *  - if it is a homestorage it starts with files/
82
		 *  - if it is not a homestorage we always wrap (external storages)
83
		 */
84
		if ($this->shouldScan && is_resource($stream) && $this->isWritingMode($mode) && (!$this->isHomeStorage || strpos($path, 'files/') === 0)) {
85
			try {
86
				$scanner = $this->scannerFactory->getScanner();
87
				$scanner->initScanner();
88
				return CallbackWrapper::wrap(
89
					$stream,
90
					null,
91
					function ($data) use ($scanner, $stream) {
92
						$params = stream_context_get_params($stream);
93
						if (isset($params['target_size'])) {
94
							$a = 'b';
0 ignored issues
show
Unused Code introduced by
$a is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
95
						}
96
						$scanner->onAsyncData($data);
97
					}, 
98
					function () use ($scanner, $path) {
99
						$status = $scanner->completeAsyncScan();
100
						if ((int)$status->getNumericStatus() === Status::SCANRESULT_INFECTED){
101
							//prevent from going to trashbin
102
							if (App::isEnabled('files_trashbin')) {
103
								\OCA\Files_Trashbin\Storage::preRenameHook([
104
									'oldpath' => '',
105
									'newpath' => ''
106
								]);
107
							}
108
							
109
							$owner = $this->getOwner($path);
110
							$this->unlink($path);
111
112
							if (App::isEnabled('files_trashbin')) {
113
								\OCA\Files_Trashbin\Storage::preRenameHook([
114
									'oldpath' => '',
115
									'newpath' => ''
116
								]);
117
							}
118
							$this->logger->warning(
119
								'Infected file deleted. ' . $status->getDetails()
120
								. ' Account: ' . $owner . ' Path: ' . $path,
121
								['app' => 'files_antivirus']
122
							);
123
124
							$activity = $this->activityManager->generateEvent();
125
							$activity->setApp(Application::APP_NAME)
126
								->setSubject(Provider::SUBJECT_VIRUS_DETECTED_UPLOAD, [$status->getDetails()])
127
								->setMessage(Provider::MESSAGE_FILE_DELETED)
128
								->setObject('', 0, $path)
129
								->setAffectedUser($owner)
130
								->setType(Provider::TYPE_VIRUS_DETECTED);
131 1
							$this->activityManager->publish($activity);
132 1
133
							$this->logger->error('Infected file deleted. ' . $status->getDetails() . 
134
							' File: ' . $path . ' Acccount: ' . $owner, ['app' => 'files_antivirus']);
135 1
136
							throw new InvalidContentException(
137
								$this->l10n->t(
138
									'Virus %s is detected in the file. Upload cannot be completed.',
139
									$status->getDetails()
140
								)
141
							);
142
						}
143 1
					}
144
				);
145 1
			} catch (\Exception $e){
146 1
				$this->logger->logException($e);
147 1
			}
148 1
		}
149
		return $stream;
150 1
	}
151
	
152
	/**
153
	 * Checks whether passed mode is suitable for writing 
154
	 * @param string $mode
155
	 * @return bool
156
	 */
157
	private function isWritingMode($mode){
158
		// Strip unessential binary/text flags
159
		$cleanMode = str_replace(
160
			['t', 'b'],
161
			['', ''],
162
			$mode
163
		);
164
		return in_array($cleanMode, $this->writingModes);
165
	}
166
}
167