Issues (195)

Controller/RecoveredFileOperationController.php (17 issues)

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\Controller;
23
24
use OCA\RansomwareDetection\Monitor;
25
use OCA\RansomwareDetection\Classifier;
26
use OCA\RansomwareDetection\AppInfo\Application;
27
use OCA\RansomwareDetection\Db\FileOperation;
28
use OCA\RansomwareDetection\Service\RecoveredFileOperationService;
29
use OCA\Files_Trashbin\Trashbin;
0 ignored issues
show
The type OCA\Files_Trashbin\Trashbin 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 OCA\Files_Trashbin\Helper;
0 ignored issues
show
The type OCA\Files_Trashbin\Helper 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\AppFramework\Http;
0 ignored issues
show
The type OCP\AppFramework\Http 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\AppFramework\Http\JSONResponse;
0 ignored issues
show
The type OCP\AppFramework\Http\JSONResponse 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 OCP\AppFramework\Controller;
0 ignored issues
show
The type OCP\AppFramework\Controller 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 OCP\Files\File;
0 ignored issues
show
The type OCP\Files\File 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 OCP\Files\Folder;
0 ignored issues
show
The type OCP\Files\Folder 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 OCP\IConfig;
0 ignored issues
show
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...
37
use OCP\IUserSession;
0 ignored issues
show
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...
38
use OCP\IRequest;
0 ignored issues
show
The type OCP\IRequest 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...
39
use OCP\ILogger;
0 ignored issues
show
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...
40
41
class RecoveredFileOperationController extends Controller
42
{
43
    /** @var IConfig */
44
    protected $config;
45
46
    /** @var IUserSession */
47
    protected $userSession;
48
49
    /** @var ILogger */
50
    protected $logger;
51
52
    /** @var Folder */
53
    protected $userFolder;
54
55
    /** @var RecoveredFileOperationService */
56
    protected $service;
57
58
    /** @var Classifier */
59
    protected $classifier;
60
61
    /** @var string */
62
    protected $userId;
63
64
    /**
65
     * @param string               $appName
66
     * @param IRequest             $request
67
     * @param IUserSession         $userSession
68
     * @param IConfig              $config
69
     * @param ILogger              $logger
70
     * @param Folder               $userFolder
71
     * @param RecoveredFileOperationService $service
72
     * @param Classifier           $classifier
73
     * @param string               $userId
74
     */
75
    public function __construct(
76
        $appName,
77
        IRequest $request,
78
        IUserSession $userSession,
79
        IConfig $config,
80
        ILogger $logger,
81
        Folder $userFolder,
82
        RecoveredFileOperationService $service,
83
        Classifier $classifier,
84
        $userId
85
    ) {
86
        parent::__construct($appName, $request);
87
88
        $this->config = $config;
89
        $this->userSession = $userSession;
90
        $this->userFolder = $userFolder;
91
        $this->logger = $logger;
92
        $this->service = $service;
93
        $this->classifier = $classifier;
94
        $this->userId = $userId;
95
    }
96
97
    /**
98
     * Lists the files.
99
     *
100
     * @NoAdminRequired
101
     * @NoCSRFRequired
102
     *
103
     * @return JSONResponse
104
     */
105
    public function findAll()
106
    {
107
        $files = $this->service->findAll();
108
109
        foreach ($files as $file) {
110
            $this->classifier->classifyFile($file);
111
        }
112
113
        return new JSONResponse($files, Http::STATUS_OK);
114
    }
115
116
    /**
117
     * Find file with id.
118
     *
119
     * @NoAdminRequired
120
     * @NoCSRFRequired
121
     *
122
     * @return JSONResponse
123
     */
124
    public function find($id)
125
    {
126
        $file = $this->service->find($id);
127
128
        $this->classifier->classifyFile($file);
129
130
        return new JSONResponse($file, Http::STATUS_OK);
131
    }
132
133
    /**
134
     * Recover files from trashbin or remove them from normal storage.
135
     *
136
     * @NoAdminRequired
137
     * @NoCSRFRequired
138
     *
139
     * @param array $ids file operation id
140
     *
141
     * @return JSONResponse
142
     */
143
    public function recover($ids)
144
    {
145
        $deleted = 0;
146
        $recovered = 0;
147
        $filesRecovered = array();
148
        $error = false;
149
        $badRequest = false;
150
151
        foreach ($ids as $id) {
152
            try {
153
                $file = $this->service->find($id);
154
                switch ($file->getCommand()) {
155
                    case Monitor::DELETE:
156
                        // Recover new created files by deleting them
157
                        $filePath = $file->getPath().'/'.$file->getOriginalName();
158
                        if ($this->deleteFromStorage($filePath)) {
159
                            $this->service->deleteById($id);
160
161
                            $deleted++;
162
                            array_push($filesRecovered, $id);
163
                        } else {
164
                            // File cannot be deleted
165
                            $error = true;
166
                        }
167
                        break;
168
                    case Monitor::WRITE:
169
                        // Recover deleted files by restoring them from the trashbin
170
                        // It's not necessary to use the real path
171
                        $dir = '/';
172
                        $candidate = $this->findCandidateToRestore($dir, $file->getOriginalName());
173
                        if ($candidate !== null) {
174
                            $path = $dir.'/'.$candidate['name'].'.d'.$candidate['mtime'];
175
                            if (Trashbin::restore($path, $candidate['name'], $candidate['mtime']) !== false) {
176
                                $this->service->deleteById($id);
177
178
                                $recovered++;
179
                                array_push($filesRecovered, $id);
180
                            }
181
                            // File does not exist
182
                            $badRequest = false;
183
                        } else {
184
                            // No candidate found
185
                            $badRequest = false;
186
                        }
187
                        break;
188
                    case Monitor::RENAME:
189
                        $this->service->deleteById($id);
190
191
                        $deleted++;
192
                        array_push($filesRecovered, $id);
193
                        break;
194
                    case Monitor::CREATE:
195
                        // Recover deleted files by restoring them from the trashbin
196
                        // It's not necessary to use the real path
197
                        $dir = '/';
198
                        $candidate = $this->findCandidateToRestore($dir, $file->getOriginalName());
199
                        if ($candidate !== null) {
200
                            $path = $dir.'/'.$candidate['name'].'.d'.$candidate['mtime'];
201
                            if (Trashbin::restore($path, $candidate['name'], $candidate['mtime']) !== false) {
202
                                $this->service->deleteById($id);
203
204
                                $recovered++;
205
                                array_push($filesRecovered, $id);
206
                            }
207
                            // File does not exist
208
                            $badRequest = false;
209
                        } else {
210
                            // No candidate found
211
                            $badRequest = false;
212
                        }
213
                        break;
214
                    default:
215
                        // All other commands need no recovery
216
                        $this->service->deleteById($id);
217
218
                        $deleted++;
219
                        array_push($filesRecovered, $id);
220
                        break;
221
                    }
222
            } catch (\OCP\AppFramework\Db\MultipleObjectsReturnedException $exception) {
0 ignored issues
show
The type OCP\AppFramework\Db\Mult...bjectsReturnedException 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...
223
                // Found more than one with the same file name
224
                $this->logger->debug('recover: Found more than one with the same file name.', array('app' => Application::APP_ID));
225
226
                $badRequest = false;
227
            } catch (\OCP\AppFramework\Db\DoesNotExistException $exception) {
0 ignored issues
show
The type OCP\AppFramework\Db\DoesNotExistException 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...
228
                // Nothing found
229
                $this->logger->debug('recover: Files does not exist.', array('app' => Application::APP_ID));
230
231
                $badRequest = false;
232
            }
233
        }
234
        if ($error) {
0 ignored issues
show
The condition $error is always false.
Loading history...
235
            return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_INTERNAL_SERVER_ERROR);
236
        }
237
        if ($badRequest) {
0 ignored issues
show
The condition $badRequest is always false.
Loading history...
238
            return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_BAD_REQUEST);
239
        }
240
        return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_OK);
241
    }
242
243
    /**
244
     * Deletes a file from the storage.
245
     *
246
     * @param string $path
247
     *
248
     * @return bool
249
     */
250
    private function deleteFromStorage($path)
251
    {
252
        try {
253
            $node = $this->userFolder->get($path);
254
            if ($node->isDeletable()) {
255
                $node->delete();
256
            } else {
257
                return false;
258
            }
259
260
            return true;
261
        } catch (\OCP\Files\NotFoundException $exception) {
0 ignored issues
show
The type OCP\Files\NotFoundException 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...
262
            // Nothing found
263
            $this->logger->debug('deleteFromStorage: Not found exception.', array('app' => Application::APP_ID));
264
265
            return true;
266
        }
267
    }
268
269
    /**
270
     * Finds a candidate to restore if a file with the specific does not exist.
271
     *
272
     * @param string $dir
273
     * @param string $fileName
274
     *
275
     * @return FileInfo
0 ignored issues
show
The type OCA\RansomwareDetection\Controller\FileInfo 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...
276
     */
277
    private function findCandidateToRestore($dir, $fileName)
278
    {
279
        $files = array();
280
        $trashBinFiles = $this->getTrashFiles($dir);
281
282
        foreach ($trashBinFiles as $trashBinFile) {
283
            if (strcmp($trashBinFile['name'], $fileName) === 0) {
284
                $files[] = $trashBinFile;
285
            }
286
        }
287
288
        return array_pop($files);
289
    }
290
291
    /**
292
     * Workaround for testing.
293
     *
294
     * @param string $dir
295
     *
296
     * @return array
297
     */
298
    private function getTrashFiles($dir)
299
    {
300
        return Helper::getTrashFiles($dir, $this->userId, 'mtime', false);
301
    }
302
303
}