Completed
Pull Request — master (#76)
by
unknown
01:53
created

Status   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 75%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 26
lcom 1
cbo 2
dl 0
loc 152
ccs 48
cts 64
cp 0.75
rs 10
c 2
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getNumericStatus() 0 3 1
A getDetails() 0 3 1
C parseResponse() 0 57 15
A getResponseRules() 0 12 4
A dispatch() 0 13 4
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 OCA\Files_Antivirus\Db\Rule;
12
use OCA\Files_Antivirus\Db\RuleMapper;
13
use OCP\ILogger;
14
15
class Status {
16
	
17
	/*
18
	 *  The file was not checked (e.g. because the AV daemon wasn't running).
19
	 */
20
	const SCANRESULT_UNCHECKED = -1;
21
22
	/*
23
	 *  The file was checked and found to be clean.
24
	 */
25
	const SCANRESULT_CLEAN = 0;
26
27
	/*
28
	 *  The file was checked and found to be infected.
29
	 */
30
	const SCANRESULT_INFECTED = 1;
31
	
32
	/*
33
	 * Should be SCANRESULT_UNCHECKED | SCANRESULT_INFECTED | SCANRESULT_CLEAN
34
	 */
35
	protected $numericStatus = self::SCANRESULT_UNCHECKED;
36
	
37
	/*
38
	 * Virus name or error message
39
	 */
40
	protected $details = '';
41
42
	/** @var RuleMapper */
43
	protected $ruleMapper;
44
45
	/** @var ILogger */
46
	protected $logger;
47
48
	/**
49
	 * Status constructor.
50
	 *
51
	 * @param RuleMapper $ruleMapper
52
	 * @param ILogger $logger
53
	 */
54 1
	public function __construct(RuleMapper $ruleMapper, ILogger $logger){
55 1
		$this->ruleMapper = $ruleMapper;
56 1
		$this->logger = $logger;
57 1
	}
58
	
59
	/**
60
	 * Get scan status as integer
61
	 * @return int
62
	 */
63 1
	public function getNumericStatus(){
64 1
		return $this->numericStatus;
65
	}
66
	
67
	/**
68
	 * Get scan status as string
69
	 * @return string
70
	 */
71 1
	public function getDetails(){
72 1
		return $this->details;
73
	}
74
	
75
	/**
76
	 * @param string $rawResponse
77
	 * @param integer $result
78
	 */
79 1
	public function parseResponse($rawResponse, $result = null){
80 1
		$matches = [];
81
82 1
		if (is_null($result)){ // Daemon or socket mode
83
			try{
84 1
				$allRules = $this->getResponseRules();
85
			} catch (\Exception $e){
86
				$this->logger->error(__METHOD__.', exception: '.$e->getMessage(), ['app' => 'files_antivirus']);
87
				return;
88
			}
89
			
90 1
			$isMatched = false;
91 1
			foreach ($allRules as $rule){
92 1
				if (preg_match($rule->getMatch(), $rawResponse, $matches)){
93 1
					$isMatched = true;
94 1
					$this->numericStatus = (int)$rule->getStatus();
95 1
					if ((int)$rule->getStatus() ===self::SCANRESULT_CLEAN){
96 1
						$this->details = '';
97
					} else {
98 1
						$this->details = isset($matches[1]) ? $matches[1] : 'unknown';
99
					}
100 1
					break;
101
				}
102
			}
103
			
104 1
			if (!$isMatched){
105 1
				$this->numericStatus = self::SCANRESULT_UNCHECKED;
106 1
				$this->details = 'No matching rules. Please check antivirus rules.';
107
			}
108
			
109
		} else { // Executable mode
110 1
			$scanStatus = $this->ruleMapper->findByResult($result);
111 1
			if (is_array($scanStatus) && count($scanStatus)){
112 1
				$this->numericStatus = (int)$scanStatus[0]->getStatus();
113 1
				$this->details = $scanStatus[0]->getDescription();
114
			}
115
			
116 1
			switch($this->numericStatus) {
117 1
				case self::SCANRESULT_INFECTED:
118 1
					$report = [];
119 1
					$rawResponse = explode("\n", $rawResponse);
120
					
121 1
					foreach ($rawResponse as $line){	
122 1
						if (preg_match('/.*: (.*) FOUND\s*$/', $line, $matches)) {
123 1
							$report[] = $matches[1];
124
						}
125
					}
126 1
					$this->details = implode(', ', $report);
127
					
128 1
					break;
129 1
				case self::SCANRESULT_UNCHECKED:
130 1
					if (!$this->details) {
131
						$this->details = 'No matching rule for exit code ' .  $this->numericStatus .'. Please check antivirus rules configuration.' ;
132
					}
133
			}
134
		}
135 1
	}
136
137
	/**
138
	 * @return Rule[]
139
	 */
140 1
	protected function getResponseRules(){
141 1
		$infectedRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_INFECTED);
142 1
		$uncheckedRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_UNCHECKED);
143 1
		$cleanRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_CLEAN);
144
		
145 1
		$infectedRules = $infectedRules ? $infectedRules : [];
146 1
		$uncheckedRules = $uncheckedRules ? $uncheckedRules : [];
147 1
		$cleanRules = $cleanRules ? $cleanRules : [];
148
		
149
		// order: clean, infected, try to guess error
150 1
		return array_merge($cleanRules, $infectedRules, $uncheckedRules);
151
	}
152
	
153
	public function dispatch(Item $item){
154
		switch($this->getNumericStatus()) {
155
			case self::SCANRESULT_UNCHECKED:
156
				$item->processUnchecked($this);
157
				break;
158
			case self::SCANRESULT_INFECTED:
159
				$item->processInfected($this);
160
				break;
161
			case self::SCANRESULT_CLEAN:
162
				$item->processClean();
163
				break;
164
		}
165
	}
166
}
167