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-04-13 16:08:50 +0300
committerMatthias <ilovemilk@wusa.io>2020-04-13 16:08:50 +0300
commit3fb91cdaae51b0096a1c21bc254e7b3e478b8509 (patch)
treeb9798e2f3e094b310a3776f3ee7e1cb5839ce6f6
parent158a1c41dd41fe6b602dc29aa31ab95beb8b6793 (diff)
add notification to history page
-rw-r--r--appinfo/routes.php2
-rw-r--r--lib/Controller/FileOperationController.php140
-rw-r--r--src/components/Notification.vue10
-rw-r--r--src/components/ProtectionStatus.vue2
-rw-r--r--src/views/History.vue72
5 files changed, 141 insertions, 85 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php
index e103b07..d2b1631 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -14,7 +14,7 @@ return [
// File operation controller
['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-operation/{id}/recover', 'verb' => 'PUT', 'requirements' => ['apiVersion' => 'v1']],
+ ['name' => 'fileOperation#recover', 'url' => '/api/{apiVersion}/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/Controller/FileOperationController.php b/lib/Controller/FileOperationController.php
index d38ff29..f47d301 100644
--- a/lib/Controller/FileOperationController.php
+++ b/lib/Controller/FileOperationController.php
@@ -123,81 +123,101 @@ class FileOperationController extends Controller
* @NoAdminRequired
* @NoCSRFRequired
*
- * @param int $id file operation id
+ * @param array $ids file operation id
*
* @return JSONResponse
*/
- public function recover($id)
+ public function recover($ids)
{
- 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)) {
+ $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);
- return new JSONResponse(null, Http::STATUS_NO_CONTENT);
- } else {
- // File cannot be deleted
- return new JSONResponse(null, Http::STATUS_INTERNAL_SERVER_ERROR);
- }
- 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) {
+ $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);
- return new JSONResponse(null, Http::STATUS_NO_CONTENT);
+ $deleted++;
+ array_push($filesRecovered, $id);
+ } else {
+ // File cannot be deleted
+ $error = true;
}
- // File does not exist
- return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
- } else {
- // No candidate found
- return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
- }
- break;
- case Monitor::RENAME:
- $this->service->deleteById($id);
-
- return new JSONResponse(null, Http::STATUS_NO_CONTENT);
- break;
- case Monitor::CREATE:
- // Recover new created folders
- $filePath = $file->getPath().'/'.$file->getOriginalName();
- if ($this->deleteFromStorage($filePath)) {
+ break;
+ default:
+ // All other commands need no recovery
$this->service->deleteById($id);
- return new JSONResponse(null, Http::STATUS_NO_CONTENT);
- } else {
- // File cannot be deleted
- return new JSONResponse(null, Http::STATUS_INTERNAL_SERVER_ERROR);
+ $deleted++;
+ array_push($filesRecovered, $id);
+ break;
}
- break;
- default:
- // All other commands need no recovery
- $this->service->deleteById($id);
-
- return new JSONResponse(null, Http::STATUS_NO_CONTENT);
- 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));
+ } 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));
- return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
- } catch (\OCP\AppFramework\Db\DoesNotExistException $exception) {
- // Nothing found
- $this->logger->debug('recover: Files does not exist.', 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));
- return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
+ $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);
}
/**
diff --git a/src/components/Notification.vue b/src/components/Notification.vue
index edc8095..9b691ba 100644
--- a/src/components/Notification.vue
+++ b/src/components/Notification.vue
@@ -19,14 +19,20 @@ export default {
required: true
},
visible: {
- type: Boolean, default: false
+ type: Boolean,
+ default: false
}
},
methods: {
onClickCloseButton: function() {
this.$emit('on-close');
}
- }
+ },
+ watch: {
+ visible (val) {
+ this.visible = val
+ }
+ }
}
</script>
diff --git a/src/components/ProtectionStatus.vue b/src/components/ProtectionStatus.vue
index e60220e..0a07e0b 100644
--- a/src/components/ProtectionStatus.vue
+++ b/src/components/ProtectionStatus.vue
@@ -75,7 +75,7 @@ export default {
height: 100%;
box-shadow: none;
color: #fff;
- padding: 0px 10px 0px 10px;
+ padding: 0px 10px 0px 30px;
&.good {
background-color: #18b977;
}
diff --git a/src/views/History.vue b/src/views/History.vue
index 6e6d2f1..4fd9610 100644
--- a/src/views/History.vue
+++ b/src/views/History.vue
@@ -6,7 +6,7 @@
</div>
<div class="page">
<div class="notification-wrapper">
- <Notification text="Test Notification" @on-close="visible = false" :visible="visible"></Notification>
+ <Notification :text.sync="notificationText" @on-close="closeNotification" :visible.sync="visible"></Notification>
</div>
<Header header="History">
<RecoverAction id="recover" label="Recover selected files" v-on:recover="onRecover" primary></RecoverAction>
@@ -35,32 +35,51 @@ export default {
RecoverAction,
Notification
},
- props: {
- visible: {
- type: Boolean, default: false
- }
- },
data() {
return {
fileOperations: [],
page: 0,
- visibile: true
+ visible: false,
+ notificationText: ""
};
},
mounted() {
this.page = 0;
this.fetchData();
- setInterval(() => this.fetchData(), 3000);
},
computed: {
recoverUrl() {
- return OC.generateUrl('/apps/ransomware_detection/api/v1/file-operation')
+ return OC.generateUrl('/apps/ransomware_detection/api/v1/file-operations')
},
fileOperationsUrl() {
return OC.generateUrl('/apps/ransomware_detection/api/v1/file-operation')
}
},
methods: {
+ closeNotification() {
+ this.visible = false
+ },
+ notice(text) {
+ this.notificationText = text;
+ this.visible = true;
+
+ },
+ buildNotification(deleted, recovered) {
+ var notificationText = "";
+ if (deleted > 0 && recovered > 0) {
+ notificationText = deleted + " files deleted, " + recovered + " files recovered from backup."
+ }
+ if (recovered > 0 && deleted == 0) {
+ notificationText = deleted + " files recovered from backup."
+ }
+ if (deleted > 0 && recovered == 0) {
+ notificationText = deleted + " files deleted."
+ }
+ if (deleted == 0 && recovered == 0) {
+ notificationText = "No files deleted or recovered."
+ }
+ this.notice(notificationText);
+ },
tableStateChanged() {
this.page = 1;
},
@@ -75,31 +94,42 @@ export default {
.catch( error => { console.error(error); });
},
onRecover() {
+ var itemsToRecover = [];
const items = document.querySelector('#ransomware-table').items;
const selected = document.querySelector('#ransomware-table').selectedItems;
for (var i = 0; i < selected.length; i++) {
- this.recover(selected[i].id);
- }
+ itemsToRecover.push(selected[i].id);
+ }
+ this.recover(itemsToRecover);
},
- remove(id) {
- for (var i = 0; i < this.fileOperations.length; i++) {
- if (this.fileOperations[i].id === id) {
- this.fileOperations.splice(i, 1);
+ remove(ids) {
+ ids.forEach(id => {
+ for (var i = 0; i < this.fileOperations.length; i++) {
+ if (this.fileOperations[i].id === id) {
+ this.fileOperations.splice(i, 1);
+ }
}
- }
+ });
},
- async recover(id) {
+ async recover(ids) {
await this.$axios({
method: 'PUT',
- url: this.recoverUrl + '/' + id + '/recover'
+ url: this.recoverUrl + '/recover',
+ data: {
+ ids: ids
+ }
})
.then(response => {
switch(response.status) {
- case 204:
- this.remove(id);
+ case 200:
+ this.buildNotification(response.data.deleted, response.data.recovered);
+ if(response.data.filesRecovered.length > 0)
+ this.remove(response.data.filesRecovered);
break;
default:
- console.log(response);
+ this.buildNotification(response.data.deleted, response.data.recovered);
+ if(response.data.filesRecovered.length > 0)
+ this.remove(response.data.filesRecovered);
break;
}
})