Completed
Pull Request — master (#50)
by Roeland
01:32
created

Status::getResponseRules()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

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