Completed
Pull Request — master (#87)
by Roeland
07:10
created

AvirWrapper::fopen()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 43.5723

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 67
ccs 8
cts 45
cp 0.1778
rs 7.4755
cc 8
nc 5
nop 2
crap 43.5723

How to fix   Long Method   

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\Scanner\ScannerFactory;
16
use OCP\Activity\IManager as ActivityManager;
17
use OCP\App;
18
use OCP\Files\InvalidContentException;
19
use OCP\IL10N;
20
use OCP\ILogger;
21
22
class AvirWrapper extends Wrapper{
23
	
24
	/**
25
	 * Modes that are used for writing 
26
	 * @var array 
27
	 */
28
	private $writingModes = ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'];
29
	
30
	/** @var ScannerFactory */
31
	protected $scannerFactory;
32
	
33
	/** @var IL10N */
34
	protected $l10n;
35
	
36
	/** @var ILogger */
37
	protected $logger;
38
39
	/** @var ActivityManager */
40
	protected $activityManager;
41
42
	/**
43
	 * @param array $parameters
44
	 */
45 2
	public function __construct($parameters) {
46 2
		parent::__construct($parameters);
47 2
		$this->scannerFactory = $parameters['scannerFactory'];
48 2
		$this->l10n = $parameters['l10n'];
49 2
		$this->logger = $parameters['logger'];
50 2
		$this->activityManager = $parameters['activityManager'];
51 2
	}
52
	
53
	/**
54
	 * Asynchronously scan data that are written to the file
55
	 * @param string $path
56
	 * @param string $mode
57
	 * @return resource | bool
58
	 */
59 1
	public function fopen($path, $mode) {
60 1
		$isChunked = preg_match('/^uploads.*\.ocTransferId\d+\.part$/', $path);
61
62 1
		$stream = $this->storage->fopen($path, $mode);
63 1
		if ($isChunked === 0 && is_resource($stream) && $this->isWritingMode($mode)) {
64
			try {
65 1
				$scanner = $this->scannerFactory->getScanner();
66
				$scanner->initScanner();
67
				return CallbackWrapper::wrap(
68
					$stream,
69
					null,
70
					function ($data) use ($scanner){
71
						$scanner->onAsyncData($data);
72
					}, 
73
					function () use ($scanner, $path) {
74
						$status = $scanner->completeAsyncScan();
75
						if ((int)$status->getNumericStatus() === Status::SCANRESULT_INFECTED){
76
							//prevent from going to trashbin
77
							if (App::isEnabled('files_trashbin')) {
78
								\OCA\Files_Trashbin\Storage::preRenameHook([
79
									'oldpath' => '',
80
									'newpath' => ''
81
								]);
82
							}
83
							
84
							$owner = $this->getOwner($path);
85
							$this->unlink($path);
86
87
							if (App::isEnabled('files_trashbin')) {
88
								\OCA\Files_Trashbin\Storage::preRenameHook([
89
									'oldpath' => '',
90
									'newpath' => ''
91
								]);
92
							}
93
							$this->logger->warning(
94
								'Infected file deleted. ' . $status->getDetails()
95
								. ' Account: ' . $owner . ' Path: ' . $path,
96
								['app' => 'files_antivirus']
97
							);
98
99
							$activity = $this->activityManager->generateEvent();
100
							$activity->setApp(Application::APP_NAME)
101
								->setSubject(Provider::SUBJECT_VIRUS_DETECTED_UPLOAD, [$status->getDetails()])
102
								->setMessage(Provider::MESSAGE_FILE_DELETED)
103
								->setObject('', 0, $path)
104
								->setAffectedUser($owner)
105
								->setType(Provider::TYPE_VIRUS_DETECTED);
106
							$this->activityManager->publish($activity);
107
108
							$this->logger->error('Infected file deleted. ' . $status->getDetails() . 
109
							' File: ' . $path . ' Acccount: ' . $owner, ['app' => 'files_antivirus']);
110
111
							throw new InvalidContentException(
112
								$this->l10n->t(
113
									'Virus %s is detected in the file. Upload cannot be completed.',
114
									$status->getDetails()
115
								)
116
							);
117
						}
118
					}
119
				);
120 1
			} catch (\Exception $e){
121 1
				$this->logger->logException($e);
122
			}
123
		}
124 1
		return $stream;
125
	}
126
	
127
	/**
128
	 * Checks whether passed mode is suitable for writing 
129
	 * @param string $mode
130
	 * @return bool
131
	 */
132 1
	private function isWritingMode($mode){
133
		// Strip unessential binary/text flags
134 1
		$cleanMode = str_replace(
135 1
			['t', 'b'],
136 1
			['', ''],
137 1
			$mode
138
		);
139 1
		return in_array($cleanMode, $this->writingModes);
140
	}
141
}
142