RequestPlugin   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 52
c 2
b 1
f 0
dl 0
loc 153
rs 10
wmc 16

9 Methods

Rating   Name   Duplication   Size   Complexity  
A beforeHttpGet() 0 2 1
A triggerNotification() 0 9 1
A initialize() 0 8 1
A beforeHttpDelete() 0 2 1
A beforeHttpPropFind() 0 18 5
A __construct() 0 18 1
A beforeHttpPut() 0 2 1
A classifySequence() 0 19 4
A beforeHttpPost() 0 2 1
1
<?php
2
3
/**
4
 * @copyright Copyright (c) 2018 Matthias Held <[email protected]>
5
 * @author Matthias Held <[email protected]>
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace OCA\RansomwareDetection\Connector\Sabre;
23
24
use OCA\RansomwareDetection\Classifier;
25
use OCA\RansomwareDetection\AppInfo\Application;
26
use OCA\RansomwareDetection\Analyzer\SequenceAnalyzer;
27
use OCA\RansomwareDetection\Service\FileOperationService;
28
use OCP\Notification\IManager;
0 ignored issues
show
Bug introduced by
The type OCP\Notification\IManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use OCP\IUserSession;
0 ignored issues
show
Bug introduced by
The type OCP\IUserSession was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use OCP\ISession;
0 ignored issues
show
Bug introduced by
The type OCP\ISession was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use OCP\ILogger;
0 ignored issues
show
Bug introduced by
The type OCP\ILogger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
use OCP\IConfig;
0 ignored issues
show
Bug introduced by
The type OCP\IConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use Sabre\DAV\Server;
0 ignored issues
show
Bug introduced by
The type Sabre\DAV\Server was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use Sabre\DAV\ServerPlugin;
0 ignored issues
show
Bug introduced by
The type Sabre\DAV\ServerPlugin was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
35
use Sabre\HTTP\RequestInterface;
0 ignored issues
show
Bug introduced by
The type Sabre\HTTP\RequestInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
36
use Sabre\HTTP\ResponseInterface;
0 ignored issues
show
Bug introduced by
The type Sabre\HTTP\ResponseInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
38
class RequestPlugin extends ServerPlugin
39
{
40
    /** @var Server */
41
    protected $server;
42
43
    /** @var ILogger */
44
    protected $logger;
45
46
    /** @var IConfig */
47
    protected $config;
48
49
    /** @var IUserSession */
50
    protected $userSession;
51
52
    /** @var ISession */
53
    protected $session;
54
55
    /** @var FileOperationService */
56
    protected $service;
57
58
    /** @var IManager */
59
    protected $notifications;
60
61
    /** @var Classifier */
62
    protected $classifier;
63
64
    /** @var SequenceAnalyzer */
65
    protected $sequenceAnalyzer;
66
67
    const PROPFIND_COUNT = 6;
68
69
    /**
70
     * @param ILogger              $logger
71
     * @param IConfig              $config
72
     * @param IUserSession         $userSession
73
     * @param ISession             $session
74
     * @param FileOperationService $service
75
     * @param IManager             $notifications
76
     * @param Classifier           $classifer
77
     * @param SequenceAnalyzer     $sequenceAnalyzer
78
     */
79
    public function __construct(
80
        ILogger $logger,
81
        IConfig $config,
82
        IUserSession $userSession,
83
        ISession $session,
84
        FileOperationService $service,
85
        IManager $notifications,
86
        Classifier $classifier,
87
        SequenceAnalyzer $sequenceAnalyzer
88
    ) {
89
        $this->logger = $logger;
90
        $this->config = $config;
91
        $this->userSession = $userSession;
92
        $this->session = $session;
93
        $this->service = $service;
94
        $this->notifications = $notifications;
95
        $this->classifier = $classifier;
96
        $this->sequenceAnalyzer = $sequenceAnalyzer;
97
    }
98
99
    public function initialize(Server $server)
100
    {
101
        $this->server = $server;
102
        $server->on('method:PROPFIND', [$this, 'beforeHttpPropFind'], 100);
103
        $server->on('method:PUT', [$this, 'beforeHttpPut'], 100);
104
        $server->on('method:DELETE', [$this, 'beforeHttpDelete'], 100);
105
        $server->on('method:GET', [$this, 'beforeHttpGet'], 100);
106
        $server->on('method:POST', [$this, 'beforeHttpPost'], 100);
107
    }
108
109
    public function beforeHttpPropFind(RequestInterface $request, ResponseInterface $response)
110
    {
111
        if ($this->userSession !== null && $this->userSession->getUser() !== null) {
112
            // only process the propfind request if there is a active user session
113
            $propfindCount = $this->config->getUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'propfind_count:'.$this->session->getId(), 0);
114
            if ($propfindCount + 1 < self::PROPFIND_COUNT) {
115
                // less than PROPFIND_COUNT + 1 PROPFIND requests
116
                $this->config->setUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'propfind_count:'.$this->session->getId(), $propfindCount + 1);
117
            } else {
118
                // more than PROPFIND_COUNT PROPFIND requests and no file is uploading
119
                $sequenceId = $this->config->getUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'sequence_id', 0);
120
                $sequence = $this->service->findSequenceById([$sequenceId]);
121
                if (sizeof($sequence) > 0) {
122
                    // get old sequence id
123
                    // start a new sequence by increasing the sequence id
124
                    $this->config->setUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'sequence_id', $sequenceId + 1);
125
                    $this->config->setUserValue($this->userSession->getUser()->getUID(), Application::APP_ID, 'propfind_count:'.$this->session->getId(), 0);
126
                    $this->classifySequence($sequence);
127
                }
128
            }
129
        }
130
    }
131
132
    public function beforeHttpPut(RequestInterface $request, ResponseInterface $response)
133
    {
134
        // extend if necessary
135
    }
136
137
    public function beforeHttpDelete(RequestInterface $request, ResponseInterface $response)
138
    {
139
        // extend if necessary
140
    }
141
142
    public function beforeHttpGet(RequestInterface $request, ResponseInterface $response)
143
    {
144
        // extend if necessary
145
    }
146
147
    public function beforeHttpPost(RequestInterface $request, ResponseInterface $response)
148
    {
149
        // extend if necessary
150
    }
151
152
    /**
153
     * Triggers a notification.
154
     */
155
    private function triggerNotification($notification)
156
    {
157
        $notification->setApp(Application::APP_ID);
158
        $notification->setDateTime(new \DateTime());
159
        $notification->setObject('ransomware', 'ransomware');
160
        $notification->setSubject('ransomware_attack_detected', []);
161
        $notification->setUser($this->userSession->getUser()->getUID());
162
163
        $this->notifications->notify($notification);
164
    }
165
166
    /**
167
     * Classify sequence and if suspicion level is reached
168
     * trigger a notification.
169
     *
170
     * @param array $sequence
171
     */
172
    private function classifySequence($sequence)
173
    {
174
        $sequenceSuspicionLevel = $this->config->getAppValue(Application::APP_ID, 'suspicion_level', 2);
175
176
        foreach ($sequence as $file) {
177
            $this->classifier->classifyFile($file);
178
        }
179
180
        // sequence suspicion level
181
        if ($sequenceSuspicionLevel === 1) {
182
            $level = 2;
183
        } else {
184
            $level = 4;
185
        }
186
187
        // sequence id is irrelevant so we use 0
188
        $sequenceResult = $this->sequenceAnalyzer->analyze(0, $sequence);
189
        if ($sequenceResult->getSuspicionScore() >= $level) {
190
            $this->triggerNotification($this->notifications->createNotification());
191
        }
192
    }
193
}
194