Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/undo-ransomware/ransomware_detection.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias <ilovemilk@wusa.io>2020-09-14 19:15:26 +0300
committerMatthias <ilovemilk@wusa.io>2020-09-14 19:15:26 +0300
commitdfeda8d4bdd88d5ec99a87610b47ade98a8065d7 (patch)
tree538b60cacac6e2e53f838e3d1d61702cbe47dd42
parent8981ac7f42307d3b56e76a3aae9a99d4c6f83200 (diff)
add recovered file operations
-rw-r--r--appinfo/database.xml99
-rw-r--r--appinfo/info.xml2
-rw-r--r--appinfo/routes.php4
-rw-r--r--lib/AppInfo/Application.php16
-rw-r--r--lib/Controller/FileOperationController.php10
-rw-r--r--lib/Controller/RecoveredFileOperationController.php296
-rw-r--r--lib/Db/FileOperation.php21
-rw-r--r--lib/Db/RecoveredFileOperation.php110
-rw-r--r--lib/Db/RecoveredFileOperationMapper.php156
-rw-r--r--lib/Service/FileOperationService.php22
-rw-r--r--lib/Service/RecoveredFileOperationService.php159
-rw-r--r--src/views/History.vue4
12 files changed, 890 insertions, 9 deletions
diff --git a/appinfo/database.xml b/appinfo/database.xml
index 261e631..12d4170 100644
--- a/appinfo/database.xml
+++ b/appinfo/database.xml
@@ -103,4 +103,103 @@
</field>
</declaration>
</table>
+ <table>
+ <name>*dbprefix*ransomware_detection_recovered</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <autoincrement>true</autoincrement>
+ </field>
+ <field>
+ <name>user_id</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>path</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>original_name</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>new_name</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>type</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>mime_type</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>size</name>
+ <type>integer</type>
+ <notnull>false</notnull>
+ <length>32</length>
+ </field>
+ <field>
+ <name>corrupted</name>
+ <type>integer</type>
+ <notnull>false</notnull>
+ <length>32</length>
+ </field>
+ <field>
+ <name>timestamp</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>12</length>
+ </field>
+ <field>
+ <name>command</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>12</length>
+ </field>
+ <field>
+ <name>sequence</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <length>255</length>
+ </field>
+ <field>
+ <name>entropy</name>
+ <type>float</type>
+ <notnull>false</notnull>
+ </field>
+ <field>
+ <name>standard_deviation</name>
+ <type>float</type>
+ <notnull>false</notnull>
+ </field>
+ <field>
+ <name>file_class</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+ <field>
+ <name>file_extension_class</name>
+ <type>text</type>
+ <notnull>false</notnull>
+ <length>64</length>
+ </field>
+ </declaration>
+ </table>
</database>
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 5095179..2e5762d 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -5,7 +5,7 @@
<name>Ransomware recovery</name>
<summary><![CDATA[This app offers synchronization monitoring and a file storage scanner for a guided user-controlled one-step ransomare recovery.]]></summary>
<description><![CDATA[This app monitors file operations during the synchronization to detect ransomware attacks and also offers a post infection file storage scanner, which works even if it happend that you didn't have this app installed during an attack. This is done by using generic indicators for a guided user-controlled one-step recovery utilizing the integrated file versioning methods. Sponsored by the German Federal Ministry of Education and Research, and Prototype Fund.]]></description>
- <version>0.8.0</version>
+ <version>0.8.2</version>
<licence>agpl</licence>
<author mail="matthias.held@uni-konstanz.de">Matthias Held</author>
<namespace>RansomwareDetection</namespace>
diff --git a/appinfo/routes.php b/appinfo/routes.php
index d2b1631..1cb9768 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -15,6 +15,10 @@ return [
['name' => 'fileOperation#findAll', 'url' => '/api/{apiVersion}/file-operation', 'verb' => 'GET', 'requirements' => ['apiVersion' => 'v1']],
['name' => 'fileOperation#find', 'url' => '/api/{apiVersion}/file-operation/{id}', 'verb' => 'GET', 'requirements' => ['apiVersion' => 'v1']],
['name' => 'fileOperation#recover', 'url' => '/api/{apiVersion}/file-operations/recover', 'verb' => 'PUT', 'requirements' => ['apiVersion' => 'v1']],
+ // Recovered file operation controller
+ ['name' => 'recoveredFileOperation#findAll', 'url' => '/api/{apiVersion}/recovered/file-operation', 'verb' => 'GET', 'requirements' => ['apiVersion' => 'v1']],
+ ['name' => 'recoveredFileOperation#find', 'url' => '/api/{apiVersion}/recovered/file-operation/{id}', 'verb' => 'GET', 'requirements' => ['apiVersion' => 'v1']],
+ ['name' => 'recoveredFileOperation#recover', 'url' => '/api/{apiVersion}/recovered/file-operations/recover', 'verb' => 'PUT', 'requirements' => ['apiVersion' => 'v1']],
// Settings controller
['name' => 'settings#update', 'url' => '/api/{apiVersion}/settings', 'verb' => 'PUT', 'requirements' => ['apiVersion' => 'v1']],
['name' => 'settings#findAll', 'url' => '/api/{apiVersion}/settings', 'verb' => 'GET', 'requirements' => ['apiVersion' => 'v1']],
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 5bdad38..82f724a 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -39,8 +39,10 @@ use OCA\RansomwareDetection\Notification\Notifier;
use OCA\RansomwareDetection\StorageWrapper;
use OCA\RansomwareDetection\Connector\Sabre\RequestPlugin;
use OCA\RansomwareDetection\Service\FileOperationService;
+use OCA\RansomwareDetection\Service\RecoveredFileOperationService;
use OCA\RansomwareDetection\Service\DetectionService;
use OCA\RansomwareDetection\Mapper\FileOperationMapper;
+use OCA\RansomwareDetection\Mapper\RecoveredFileOperationMapper;
use OCP\AppFramework\App;
use OCP\App\IAppManager;
use OCP\Files\IRootFolder;
@@ -72,6 +74,12 @@ class Application extends App
);
});
+ $container->registerService('RecoveredFileOperationMapper', function ($c) {
+ return new RecoveredFileOperationMapper(
+ $c->query('ServerContainer')->getDb()
+ );
+ });
+
$container->registerService('DetectionDeserializer', function ($c) {
return new DetectionDeserializer(
$c->query('FileOperationMapper')
@@ -86,6 +94,14 @@ class Application extends App
);
});
+ $container->registerService('RecoveredFileOperationService', function ($c) {
+ return new RecoveredFileOperationService(
+ $c->query(FileOperationMapper::class),
+ $c->query(RecoveredFileOperationMapper::class),
+ $c->query('ServerContainer')->getUserSession()->getUser()->getUID()
+ );
+ });
+
$container->registerService('DetectionService', function ($c) {
return new DetectionService(
$c->query(ILogger::class),
diff --git a/lib/Controller/FileOperationController.php b/lib/Controller/FileOperationController.php
index d09268e..1cfb281 100644
--- a/lib/Controller/FileOperationController.php
+++ b/lib/Controller/FileOperationController.php
@@ -156,7 +156,7 @@ class FileOperationController extends Controller
// Recover new created files by deleting them
$filePath = $file->getPath().'/'.$file->getOriginalName();
if ($this->deleteFromStorage($filePath)) {
- $this->service->deleteById($id);
+ $this->service->deleteById($id, true);
$deleted++;
array_push($filesRecovered, $id);
@@ -173,7 +173,7 @@ class FileOperationController extends Controller
if ($candidate !== null) {
$path = $dir.'/'.$candidate['name'].'.d'.$candidate['mtime'];
if (Trashbin::restore($path, $candidate['name'], $candidate['mtime']) !== false) {
- $this->service->deleteById($id);
+ $this->service->deleteById($id, true);
$recovered++;
array_push($filesRecovered, $id);
@@ -186,7 +186,7 @@ class FileOperationController extends Controller
}
break;
case Monitor::RENAME:
- $this->service->deleteById($id);
+ $this->service->deleteById($id, true);
$deleted++;
array_push($filesRecovered, $id);
@@ -195,7 +195,7 @@ class FileOperationController extends Controller
// Recover new created files/folders
$filePath = $file->getPath().'/'.$file->getOriginalName();
if ($this->deleteFromStorage($filePath)) {
- $this->service->deleteById($id);
+ $this->service->deleteById($id, true);
$deleted++;
array_push($filesRecovered, $id);
@@ -206,7 +206,7 @@ class FileOperationController extends Controller
break;
default:
// All other commands need no recovery
- $this->service->deleteById($id);
+ $this->service->deleteById($id, false);
$deleted++;
array_push($filesRecovered, $id);
diff --git a/lib/Controller/RecoveredFileOperationController.php b/lib/Controller/RecoveredFileOperationController.php
new file mode 100644
index 0000000..95a7cf1
--- /dev/null
+++ b/lib/Controller/RecoveredFileOperationController.php
@@ -0,0 +1,296 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2018 Matthias Held <matthias.held@uni-konstanz.de>
+ * @author Matthias Held <matthias.held@uni-konstanz.de>
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\RansomwareDetection\Controller;
+
+use OCA\RansomwareDetection\Monitor;
+use OCA\RansomwareDetection\Classifier;
+use OCA\RansomwareDetection\AppInfo\Application;
+use OCA\RansomwareDetection\Db\FileOperation;
+use OCA\RansomwareDetection\Service\RecoveredFileOperationService;
+use OCA\Files_Trashbin\Trashbin;
+use OCA\Files_Trashbin\Helper;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Controller;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\IConfig;
+use OCP\IUserSession;
+use OCP\IRequest;
+use OCP\ILogger;
+
+class RecoveredFileOperationController extends Controller
+{
+ /** @var IConfig */
+ protected $config;
+
+ /** @var IUserSession */
+ protected $userSession;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var Folder */
+ protected $userFolder;
+
+ /** @var RecoveredFileOperationService */
+ protected $service;
+
+ /** @var Classifier */
+ protected $classifier;
+
+ /** @var string */
+ protected $userId;
+
+ /**
+ * @param string $appName
+ * @param IRequest $request
+ * @param IUserSession $userSession
+ * @param IConfig $config
+ * @param ILogger $logger
+ * @param Folder $userFolder
+ * @param RecoveredFileOperationService $service
+ * @param Classifier $classifier
+ * @param string $userId
+ */
+ public function __construct(
+ $appName,
+ IRequest $request,
+ IUserSession $userSession,
+ IConfig $config,
+ ILogger $logger,
+ Folder $userFolder,
+ RecoveredFileOperationService $service,
+ Classifier $classifier,
+ $userId
+ ) {
+ parent::__construct($appName, $request);
+
+ $this->config = $config;
+ $this->userSession = $userSession;
+ $this->userFolder = $userFolder;
+ $this->logger = $logger;
+ $this->service = $service;
+ $this->classifier = $classifier;
+ $this->userId = $userId;
+ }
+
+ /**
+ * Lists the files.
+ *
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @return JSONResponse
+ */
+ public function findAll()
+ {
+ $files = $this->service->findAll();
+
+ foreach ($files as $file) {
+ $this->classifier->classifyFile($file);
+ }
+
+ return new JSONResponse($files, Http::STATUS_OK);
+ }
+
+ /**
+ * Find file with id.
+ *
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @return JSONResponse
+ */
+ public function find($id)
+ {
+ $file = $this->service->find($id);
+
+ $this->classifier->classifyFile($file);
+
+ return new JSONResponse($file, Http::STATUS_OK);
+ }
+
+ /**
+ * Recover files from trashbin or remove them from normal storage.
+ *
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @param array $ids file operation id
+ *
+ * @return JSONResponse
+ */
+ public function recover($ids)
+ {
+ $deleted = 0;
+ $recovered = 0;
+ $filesRecovered = array();
+ $error = false;
+ $badRequest = false;
+
+ foreach ($ids as $id) {
+ try {
+ $file = $this->service->find($id);
+ switch ($file->getCommand()) {
+ case Monitor::WRITE:
+ // Recover new created files by deleting them
+ $filePath = $file->getPath().'/'.$file->getOriginalName();
+ if ($this->deleteFromStorage($filePath)) {
+ $this->service->deleteById($id);
+
+ $deleted++;
+ array_push($filesRecovered, $id);
+ } else {
+ // File cannot be deleted
+ $error = true;
+ }
+ break;
+ case Monitor::DELETE:
+ // Recover deleted files by restoring them from the trashbin
+ // It's not necessary to use the real path
+ $dir = '/';
+ $candidate = $this->findCandidateToRestore($dir, $file->getOriginalName());
+ if ($candidate !== null) {
+ $path = $dir.'/'.$candidate['name'].'.d'.$candidate['mtime'];
+ if (Trashbin::restore($path, $candidate['name'], $candidate['mtime']) !== false) {
+ $this->service->deleteById($id);
+
+ $recovered++;
+ array_push($filesRecovered, $id);
+ }
+ // File does not exist
+ $badRequest = false;
+ } else {
+ // No candidate found
+ $badRequest = false;
+ }
+ break;
+ case Monitor::RENAME:
+ $this->service->deleteById($id);
+
+ $deleted++;
+ array_push($filesRecovered, $id);
+ break;
+ case Monitor::CREATE:
+ // Recover new created files/folders
+ $filePath = $file->getPath().'/'.$file->getOriginalName();
+ if ($this->deleteFromStorage($filePath)) {
+ $this->service->deleteById($id);
+
+ $deleted++;
+ array_push($filesRecovered, $id);
+ } else {
+ // File cannot be deleted
+ $error = true;
+ }
+ break;
+ default:
+ // All other commands need no recovery
+ $this->service->deleteById($id);
+
+ $deleted++;
+ array_push($filesRecovered, $id);
+ break;
+ }
+ } catch (\OCP\AppFramework\Db\MultipleObjectsReturnedException $exception) {
+ // Found more than one with the same file name
+ $this->logger->debug('recover: Found more than one with the same file name.', array('app' => Application::APP_ID));
+
+ $badRequest = false;
+ } catch (\OCP\AppFramework\Db\DoesNotExistException $exception) {
+ // Nothing found
+ $this->logger->debug('recover: Files does not exist.', array('app' => Application::APP_ID));
+
+ $badRequest = false;
+ }
+ }
+ if ($error) {
+ return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_INTERNAL_SERVER_ERROR);
+ }
+ if ($badRequest) {
+ return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_BAD_REQUEST);
+ }
+ return new JSONResponse(array('recovered' => $recovered, 'deleted' => $deleted, 'filesRecovered' => $filesRecovered), Http::STATUS_OK);
+ }
+
+ /**
+ * Deletes a file from the storage.
+ *
+ * @param string $path
+ *
+ * @return bool
+ */
+ private function deleteFromStorage($path)
+ {
+ try {
+ $node = $this->userFolder->get($path);
+ if ($node->isDeletable()) {
+ $node->delete();
+ } else {
+ return false;
+ }
+
+ return true;
+ } catch (\OCP\Files\NotFoundException $exception) {
+ // Nothing found
+ $this->logger->debug('deleteFromStorage: Not found exception.', array('app' => Application::APP_ID));
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds a candidate to restore if a file with the specific does not exist.
+ *
+ * @param string $dir
+ * @param string $fileName
+ *
+ * @return FileInfo
+ */
+ private function findCandidateToRestore($dir, $fileName)
+ {
+ $files = array();
+ $trashBinFiles = $this->getTrashFiles($dir);
+
+ foreach ($trashBinFiles as $trashBinFile) {
+ if (strcmp($trashBinFile['name'], $fileName) === 0) {
+ $files[] = $trashBinFile;
+ }
+ }
+
+ return array_pop($files);
+ }
+
+ /**
+ * Workaround for testing.
+ *
+ * @param string $dir
+ *
+ * @return array
+ */
+ private function getTrashFiles($dir)
+ {
+ return Helper::getTrashFiles($dir, $this->userId, 'mtime', false);
+ }
+
+} \ No newline at end of file
diff --git a/lib/Db/FileOperation.php b/lib/Db/FileOperation.php
index 09bcedc..18d400b 100644
--- a/lib/Db/FileOperation.php
+++ b/lib/Db/FileOperation.php
@@ -22,6 +22,7 @@
namespace OCA\RansomwareDetection\Db;
use OCP\AppFramework\Db\Entity;
+use OCA\RansomwareDetection\Db\RecoveredFileOperation;
class FileOperation extends Entity
{
@@ -86,4 +87,24 @@ class FileOperation extends Entity
$this->addType('fileExtensionClass', 'integer');
$this->addType('fileClass', 'integer');
}
+
+ public function toRecoveredFileOperation() {
+ $recoveredFileOperation = new RecoveredFileOperation();
+ $recoveredFileOperation->setUserId($this->getUserId());
+ $recoveredFileOperation->setPath($this->getPath());
+ $recoveredFileOperation->setOriginalName($this->getOriginalName());
+ $recoveredFileOperation->setNewName($this->getNewName());
+ $recoveredFileOperation->setType($this->getType());
+ $recoveredFileOperation->setMimeType($this->getMimeType());
+ $recoveredFileOperation->setSize($this->getSize());
+ $recoveredFileOperation->setTimestamp($this->getTimestamp());
+ $recoveredFileOperation->setCorrupted($this->getCorrupted());
+ $recoveredFileOperation->setCommand($this->getCommand());
+ $recoveredFileOperation->setSequence($this->getSequence());
+ $recoveredFileOperation->setEntropy($this->getEntropy());
+ $recoveredFileOperation->setStandardDeviation($this->getStandardDeviation());
+ $recoveredFileOperation->setFileClass($this->getFileClass());
+ $recoveredFileOperation->setFileExtensionClass($this->getFileExtensionClass());
+ return $recoveredFileOperation;
+ }
}
diff --git a/lib/Db/RecoveredFileOperation.php b/lib/Db/RecoveredFileOperation.php
new file mode 100644
index 0000000..74dbce7
--- /dev/null
+++ b/lib/Db/RecoveredFileOperation.php
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2020 Matthias Held <matthias.held@uni-konstanz.de>
+ * @author Matthias Held <matthias.held@uni-konstanz.de>
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\RansomwareDetection\Db;
+
+use OCP\AppFramework\Db\Entity;
+use OCA\RansomwareDetection\Db\FileOperation;
+
+class RecoveredFileOperation extends Entity
+{
+ /** @var string */
+ public $userId;
+
+ /** @var string */
+ public $path;
+
+ /** @var string */
+ public $originalName;
+
+ /** @var string */
+ public $newName;
+
+ /** @var string */
+ public $type;
+
+ /** @var string */
+ public $mimeType;
+
+ /** @var int */
+ public $size;
+
+ /** @var int */
+ public $corrupted;
+
+ /** @var string */
+ public $timestamp;
+
+ /** @var int */
+ public $command;
+
+ /** @var int */
+ public $sequence;
+
+ /** @var float */
+ public $entropy;
+
+ /** @var float */
+ public $standardDeviation;
+
+ /** @var string */
+ public $fileClass;
+
+ /** @var string */
+ public $fileExtensionClass;
+
+ /** @var int */
+ public $suspicionClass;
+
+ public function __construct()
+ {
+ // Add types in constructor
+ $this->addType('size', 'integer');
+ $this->addType('corrupted', 'integer');
+ $this->addType('command', 'integer');
+ $this->addType('sequence', 'integer');
+ $this->addType('entropy', 'float');
+ $this->addType('standardDeviation', 'float');
+ $this->addType('suspicionClass', 'integer');
+ $this->addType('fileExtensionClass', 'integer');
+ $this->addType('fileClass', 'integer');
+ }
+
+ public function toFileOperation() {
+ $fileOperation = new FileOperation();
+ $fileOperation->setUserId($this->getUserId());
+ $fileOperation->setPath($this->getPath());
+ $fileOperation->setOriginalName($this->getOriginalName());
+ $fileOperation->setNewName($this->getNewName());
+ $fileOperation->setType($this->getType());
+ $fileOperation->setMimeType($this->getMimeType());
+ $fileOperation->setSize($this->getSize());
+ $fileOperation->setTimestamp($this->getTimestamp());
+ $fileOperation->setCorrupted($this->getCorrupted());
+ $fileOperation->setCommand($this->getCommand());
+ $fileOperation->setSequence($this->getSequence());
+ $fileOperation->setEntropy($this->getEntropy());
+ $fileOperation->setStandardDeviation($this->getStandardDeviation());
+ $fileOperation->setFileClass($this->getFileClass());
+ $fileOperation->setFileExtensionClass($this->getFileExtensionClass());
+ return $fileOperation;
+ }
+}
diff --git a/lib/Db/RecoveredFileOperationMapper.php b/lib/Db/RecoveredFileOperationMapper.php
new file mode 100644
index 0000000..ed6e442
--- /dev/null
+++ b/lib/Db/RecoveredFileOperationMapper.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2020 Matthias Held <matthias.held@uni-konstanz.de>
+ * @author Matthias Held <matthias.held@uni-konstanz.de>
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\RansomwareDetection\Db;
+
+use OCP\IDBConnection;
+use OCP\AppFramework\Db\Mapper;
+
+class RecoveredFileOperationMapper extends Mapper
+{
+ /**
+ * @param IDBConnection $db
+ */
+ public function __construct(
+ IDBConnection $db
+ ) {
+ parent::__construct($db, 'ransomware_detection_recovered');
+ }
+
+ /**
+ * Find one by id.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @param int $id
+ *
+ * @return Entity
+ */
+ public function find($id, $userId)
+ {
+ $sql = 'SELECT * FROM `*PREFIX*ransomware_detection_recovered` '.
+ 'WHERE `id` = ? AND `user_id` = ?';
+
+ return $this->findEntity($sql, [$id, $userId]);
+ }
+
+ /**
+ * Find one by file name.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @param string $name
+ *
+ * @return Entity
+ */
+ public function findOneByFileName($name, $userId)
+ {
+ $sql = 'SELECT * FROM `*PREFIX*ransomware_detection_recovered` '.
+ 'WHERE `original_name` = ? AND `user_id` = ?';
+
+ return $this->findEntity($sql, [$name, $userId]);
+ }
+
+ /**
+ * Find the one with the highest id.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @return Entity
+ */
+ public function findOneWithHighestId($userId)
+ {
+ $sql = 'SELECT * FROM `*PREFIX*ransomware_detection_recovered` WHERE `user_id` = ?'.
+ 'ORDER BY id DESC LIMIT 1';
+
+ return $this->findEntity($sql, [$userId]);
+ }
+
+ /**
+ * Find all.
+ *
+ * @param int $limit
+ * @param int $offset
+ *
+ * @return array
+ */
+ public function findAll(array $params = [], $limit = null, $offset = null)
+ {
+ $sql = 'SELECT * FROM `*PREFIX*ransomware_detection_recovered` WHERE `user_id` = ?';
+
+ return $this->findEntities($sql, $params, $limit, $offset);
+ }
+
+ /**
+ * Find a sequence by its id.
+ *
+ * @param array $params
+ * @param int $limit
+ * @param int $offset
+ *
+ * @return array
+ */
+ public function findSequenceById(array $params = [], $limit = null, $offset = null)
+ {
+ $sql = 'SELECT * FROM `*PREFIX*ransomware_detection_recovered` WHERE `sequence` = ? AND `user_id` = ?';
+
+ return $this->findEntities($sql, $params, $limit, $offset);
+ }
+
+ /**
+ * Delete entity by id.
+ *
+ * @param int $id
+ */
+ public function deleteById($id, $userId)
+ {
+ $sql = 'DELETE FROM `*PREFIX*ransomware_detection_recovered` WHERE `id` = ? AND `user_id` = ?';
+ $stmt = $this->execute($sql, [$id, $userId]);
+ $stmt->closeCursor();
+ }
+
+ /**
+ * Deletes a sequence of file operations.
+ *
+ * @param int $sequence
+ */
+ public function deleteSequenceById($sequence, $userId)
+ {
+ $sql = 'DELETE FROM `*PREFIX*ransomware_detection_recovered` WHERE `sequence` = ? AND `user_id` = ?';
+ $stmt = $this->execute($sql, [$sequence, $userId]);
+ $stmt->closeCursor();
+ }
+
+ /**
+ * Delete all entries before $timestamp.
+ *
+ * @param int $timestamp
+ */
+ public function deleteFileOperationsBefore($timestamp)
+ {
+ $sql = 'DELETE FROM `*PREFIX*ransomware_detection_recovered` WHERE `timestamp` < ?';
+ $stmt = $this->execute($sql, [$timestamp]);
+ $stmt->closeCursor();
+ }
+}
diff --git a/lib/Service/FileOperationService.php b/lib/Service/FileOperationService.php
index 049de93..6412b63 100644
--- a/lib/Service/FileOperationService.php
+++ b/lib/Service/FileOperationService.php
@@ -22,24 +22,31 @@
namespace OCA\RansomwareDetection\Service;
use OCA\RansomwareDetection\Db\FileOperationMapper;
+use OCA\RansomwareDetection\Db\RecoveredFileOperationMapper;
class FileOperationService
{
/** @var FileOperationMapper */
protected $mapper;
+ /** @var RecoveredFileOperationMapper */
+ protected $recoveredMapper;
+
/** @var string */
protected $userId;
/**
* @param FileOperationMapper $mapper
+ * @param RecoveredFileOperationMapper $recoveredMapper
* @param string $userId
*/
public function __construct(
FileOperationMapper $mapper,
+ RecoveredFileOperationMapper $recoveredMapper,
$userId
) {
$this->mapper = $mapper;
+ $this->recoveredMapper = $recoveredMapper;
$this->userId = $userId;
}
@@ -123,9 +130,14 @@ class FileOperationService
*
* @param int $id
*/
- public function deleteById($id)
+ public function deleteById($id, $addToHistory = false)
{
+ $fileOperation = $this->mapper->find($id, $this->userId);
$this->mapper->deleteById($id, $this->userId);
+ if ($addToHistory) {
+ $this->recoveredMapper->insert($fileOperation->toRecoveredFileOperation());
+ }
+
}
/**
@@ -135,7 +147,15 @@ class FileOperationService
*/
public function deleteSequenceById($sequence)
{
+ $params = [];
+ array_push($params, $sequence);
+ array_push($params, $this->userId);
+
+ $fileOperations = $this->mapper->findSequenceById($params, null, null);
$this->mapper->deleteSequenceById($sequence, $this->userId);
+ foreach ($fileOperations as $fileOperation) {
+ $this->recoveredMapper->insert($fileOperation->toRecoveredFileOperation());
+ }
}
/**
diff --git a/lib/Service/RecoveredFileOperationService.php b/lib/Service/RecoveredFileOperationService.php
new file mode 100644
index 0000000..c983bf4
--- /dev/null
+++ b/lib/Service/RecoveredFileOperationService.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * @copyright Copyright (c) 2020 Matthias Held <matthias.held@uni-konstanz.de>
+ * @author Matthias Held <matthias.held@uni-konstanz.de>
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\RansomwareDetection\Service;
+
+use OCA\RansomwareDetection\Db\RecoveredFileOperationMapper;
+use OCA\RansomwareDetection\Db\FileOperationMapper;
+
+class RecoveredFileOperationService
+{
+ /** @var RecoveredFileOperationMapper */
+ protected $recoveredMapper;
+
+ /** @var FileOperationMapper */
+ protected $mapper;
+
+ /** @var string */
+ protected $userId;
+
+ /**
+ * @param RecoveredFileOperationMapper $recoveredMapper
+ * @param FileOperationMapper $mapper
+ * @param string $userId
+ */
+ public function __construct(
+ RecoveredFileOperationMapper $recoveredMapper,
+ FileOperationMapper $mapper,
+ $userId
+ ) {
+ $this->recoveredMapper = $recoveredMapper;
+ $this->mapper = $mapper;
+ $this->userId = $userId;
+ }
+
+ /**
+ * Find one by the id.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @param int $id
+ *
+ * @return Entity
+ */
+ public function find($id)
+ {
+ return $this->recoveredMapper->find($id, $this->userId);
+ }
+
+ /**
+ * Find one by the file name.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @param string $name
+ *
+ * @return Entity
+ */
+ public function findOneByFileName($name)
+ {
+ return $this->recoveredMapper->findOneByFileName($name, $this->userId);
+ }
+
+ /**
+ * Find one with the highest id.
+ *
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
+ *
+ * @return Entity
+ */
+ public function findOneWithHighestId()
+ {
+ return $this->recoveredMapper->findOneWithHighestId($this->userId);
+ }
+
+ /**
+ * Find all.
+ *
+ * @param array $params
+ * @param int $limit
+ * @param int $offset
+ *
+ * @return array
+ */
+ public function findAll(array $params = [], $limit = null, $offset = null)
+ {
+ array_push($params, $this->userId);
+
+ return $this->recoveredMapper->findAll($params, $limit, $offset);
+ }
+
+ /**
+ * Find sequence by id.
+ *
+ * @param array $params
+ * @param int $limit
+ * @param int $offset
+ *
+ * @return array
+ */
+ public function findSequenceById(array $params = [], $limit = null, $offset = null)
+ {
+ array_push($params, $this->userId);
+
+ return $this->recoveredMapper->findSequenceById($params, $limit, $offset);
+ }
+
+ /**
+ * Delete one by id.
+ *
+ * @param int $id
+ */
+ public function deleteById($id)
+ {
+ $fileOperation = $this->recoveredMapper->find($id, $this->userId);
+ $this->recoveredMapper->deleteById($id, $this->userId);
+ $this->mapper->insert($fileOperation->toFileOperation());
+ }
+
+ /**
+ * Delete sequence by id.
+ *
+ * @param int $sequence
+ */
+ public function deleteSequenceById($sequence)
+ {
+ $this->recoveredMapper->deleteSequenceById($sequence, $this->userId);
+ }
+
+ /**
+ * Delete all entries before $timestamp.
+ *
+ * @param int $timestamp
+ */
+ public function deleteFileOperationsBefore($timestamp)
+ {
+ $this->recoveredMapper->deleteFileOperationsBefore($timestamp);
+ }
+}
diff --git a/src/views/History.vue b/src/views/History.vue
index b973b57..808245b 100644
--- a/src/views/History.vue
+++ b/src/views/History.vue
@@ -49,10 +49,10 @@ export default {
},
computed: {
recoverUrl() {
- return OC.generateUrl('/apps/ransomware_detection/api/v1/file-operations')
+ return OC.generateUrl('/apps/ransomware_detection/api/v1/recovered/file-operations')
},
fileOperationsUrl() {
- return OC.generateUrl('/apps/ransomware_detection/api/v1/file-operation')
+ return OC.generateUrl('/apps/ransomware_detection/api/v1/recovered/file-operation')
}
},
methods: {