Completed
Push — master ( b32497...b91e8b )
by Roeland
16s queued 12s
created

Status::getNumericStatus()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
	public function setNumericStatus(int $numericStatus): void {
76
		$this->numericStatus = $numericStatus;
77
	}
78
79
	public function setDetails(string $details): void {
80
		$this->details = $details;
81
	}
82
	
83
	/**
84
	 * @param string $rawResponse
85
	 * @param integer $result
86
	 */
87 1
	public function parseResponse($rawResponse, $result = null){
88 1
		$matches = [];
89
90 1
		if (is_null($result)){ // Daemon or socket mode
91
			try{
92 1
				$allRules = $this->getResponseRules();
93
			} catch (\Exception $e){
94
				$this->logger->error(__METHOD__.', exception: '.$e->getMessage(), ['app' => 'files_antivirus']);
95
				return;
96
			}
97
			
98 1
			$isMatched = false;
99 1
			foreach ($allRules as $rule){
100 1
				if (preg_match($rule->getMatch(), $rawResponse, $matches)){
101 1
					$isMatched = true;
102 1
					$this->numericStatus = (int)$rule->getStatus();
103 1
					if ((int)$rule->getStatus() ===self::SCANRESULT_CLEAN){
104 1
						$this->details = '';
105
					} else {
106 1
						$this->details = isset($matches[1]) ? $matches[1] : 'unknown';
107
					}
108 1
					break;
109
				}
110
			}
111
			
112 1
			if (!$isMatched){
113 1
				$this->numericStatus = self::SCANRESULT_UNCHECKED;
114 1
				$this->details = 'No matching rules. Please check antivirus rules.';
115
			}
116
			
117
		} else { // Executable mode
118 1
			$scanStatus = $this->ruleMapper->findByResult($result);
119 1
			if (is_array($scanStatus) && count($scanStatus)){
120 1
				$this->numericStatus = (int)$scanStatus[0]->getStatus();
121 1
				$this->details = $scanStatus[0]->getDescription();
122
			}
123
			
124 1
			switch($this->numericStatus) {
125 1
				case self::SCANRESULT_INFECTED:
126 1
					$report = [];
127 1
					$rawResponse = explode("\n", $rawResponse);
128
					
129 1
					foreach ($rawResponse as $line){	
130 1
						if (preg_match('/.*: (.*) FOUND\s*$/', $line, $matches)) {
131 1
							$report[] = $matches[1];
132
						}
133
					}
134 1
					$this->details = implode(', ', $report);
135
					
136 1
					break;
137 1
				case self::SCANRESULT_UNCHECKED:
138 1
					if (!$this->details) {
139
						$this->details = 'No matching rule for exit code ' .  $this->numericStatus .'. Please check antivirus rules configuration.' ;
140
					}
141
			}
142
		}
143 1
	}
144
145
	/**
146
	 * @return Rule[]
147
	 */
148 1
	protected function getResponseRules(){
149 1
		$infectedRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_INFECTED);
150 1
		$uncheckedRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_UNCHECKED);
151 1
		$cleanRules = $this->ruleMapper->findAllMatchedByStatus(self::SCANRESULT_CLEAN);
152
		
153 1
		$infectedRules = $infectedRules ? $infectedRules : [];
154 1
		$uncheckedRules = $uncheckedRules ? $uncheckedRules : [];
155 1
		$cleanRules = $cleanRules ? $cleanRules : [];
156
		
157
		// order: clean, infected, try to guess error
158 1
		return array_merge($cleanRules, $infectedRules, $uncheckedRules);
159
	}
160
	
161
	public function dispatch(Item $item){
162
		switch($this->getNumericStatus()) {
163
			case self::SCANRESULT_UNCHECKED:
164
				$item->processUnchecked($this);
165
				break;
166
			case self::SCANRESULT_INFECTED:
167
				$item->processInfected($this);
168
				break;
169
			case self::SCANRESULT_CLEAN:
170
				$item->processClean();
171
				break;
172
		}
173
	}
174
}
175