From 44b2594dfa0a4ebb7a193ae31a0d119c638de724 Mon Sep 17 00:00:00 2001
From: Alicia Sykes
Date: Mon, 24 May 2021 17:25:16 +0100
Subject: [PATCH] Adds backup functionality
---
package.json | 2 +
.../Configuration/CloudBackupRestore.vue | 84 +++++++++++++++++--
src/components/FormElements/Button.vue | 3 +-
src/components/Settings/ConfigLauncher.vue | 2 +-
src/styles/color-palette.scss | 15 ++++
src/styles/global-styles.scss | 19 +++++
src/utils/CloudBackup.js | 20 +++--
src/utils/defaults.js | 4 +-
yarn.lock | 17 ++++
9 files changed, 150 insertions(+), 16 deletions(-)
diff --git a/package.json b/package.json
index 316dfcee..4293e0e8 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,9 @@
"lint": "vue-cli-service lint --fix"
},
"dependencies": {
+ "axios": "^0.21.1",
"connect": "^3.7.0",
+ "crypto-js": "^4.0.0",
"register-service-worker": "^1.6.2",
"remedial": "^1.0.8",
"serve-static": "^1.14.1",
diff --git a/src/components/Configuration/CloudBackupRestore.vue b/src/components/Configuration/CloudBackupRestore.vue
index 79625c63..0ba3d3d6 100644
--- a/src/components/Configuration/CloudBackupRestore.vue
+++ b/src/components/Configuration/CloudBackupRestore.vue
@@ -14,21 +14,30 @@
-
Backup
+
Update Backup
+
Make a Backup
-
-
Restore
+ Restore a Backup
+import sha256 from 'crypto-js/sha256';
import Button from '@/components/FormElements/Button';
import Input from '@/components/FormElements/Input';
import IconBackup from '@/assets/interface-icons/config-backup.svg';
import IconRestore from '@/assets/interface-icons/config-restore.svg';
+import { backup } from '@/utils/CloudBackup';
+import { localStorageKeys } from '@/utils/defaults';
export default {
name: 'CloudBackupRestore',
@@ -65,6 +77,7 @@ export default {
backupPassword: '',
restorePassword: '',
restoreCode: '',
+ backupId: localStorage[localStorageKeys.BACKUP_ID] || '',
};
},
components: {
@@ -73,6 +86,44 @@ export default {
IconBackup,
IconRestore,
},
+ methods: {
+ checkPass() {
+ const savedHash = localStorage[localStorageKeys.BACKUP_HASH] || undefined;
+ if (!savedHash || savedHash === this.makeHash(this.backupPassword)) {
+ this.makeBackup();
+ } else {
+ this.showErrorMsg('Incorrect password. Please enter the password you used last time.');
+ }
+ },
+ makeBackup() {
+ backup(this.config, this.backupPassword)
+ .then((response) => {
+ if (!response.data || response.data.errorMsg || !response.data.backupId) {
+ this.showErrorMsg(response.data.errorMsg || 'Error');
+ } else { // All clear, no error
+ this.updateAfterBackup(response.data.backupId);
+ }
+ }).catch(() => {
+ this.showErrorMsg('Unable to process request');
+ });
+ },
+ updateAfterBackup(backupId) {
+ const hash = this.makeHash(this.backupPassword);
+ localStorage.setItem(localStorageKeys.BACKUP_ID, backupId);
+ localStorage.setItem(localStorageKeys.BACKUP_HASH, hash);
+ this.showSuccessMsg('Backup Completed Succesfully');
+ this.backupPassword = '';
+ },
+ showErrorMsg(errorMsg) {
+ this.$toasted.show(errorMsg, { className: 'toast-error' });
+ },
+ showSuccessMsg(msg) {
+ this.$toasted.show(msg, { className: 'toast-success' });
+ },
+ makeHash(pass) {
+ return sha256(pass).toString();
+ },
+ },
};
@@ -112,8 +163,29 @@ export default {
}
}
+ div.results-view {
+ width: 16rem;
+ margin: 0.5rem auto;
+ padding: 0.5rem 0.75rem;
+ box-sizing: border-box;
+ border: 1px dashed var(--config-settings-color);
+ border-radius: var(--curve-factor);
+ text-align: left;
+ .backup-id-label, .backup-id-value {
+ display: inline;
+ font-size: 1rem;
+ margin-right: 0.5rem;
+ }
+ .backup-id-note {
+ font-size: 0.8rem;
+ display: block;
+ opacity: 0.8;
+ margin-top: 0.5rem;
+ }
+ }
+
/* Overide form element colors, so that config menu can be themed by user */
- input, button {
+ input, button, {
color: var(--config-settings-color);
border: 1px solid var(--config-settings-color);
background: none;
diff --git a/src/components/FormElements/Button.vue b/src/components/FormElements/Button.vue
index c249ca25..4ea452d1 100644
--- a/src/components/FormElements/Button.vue
+++ b/src/components/FormElements/Button.vue
@@ -1,5 +1,5 @@
-
+
@@ -11,6 +11,7 @@ export default {
name: 'Button',
props: {
text: String,
+ click: Function,
},
};
diff --git a/src/components/Settings/ConfigLauncher.vue b/src/components/Settings/ConfigLauncher.vue
index d9e82118..3a458dfe 100644
--- a/src/components/Settings/ConfigLauncher.vue
+++ b/src/components/Settings/ConfigLauncher.vue
@@ -14,7 +14,7 @@
-
diff --git a/src/styles/color-palette.scss b/src/styles/color-palette.scss
index 6e65c3a6..0f0c9f60 100644
--- a/src/styles/color-palette.scss
+++ b/src/styles/color-palette.scss
@@ -5,6 +5,16 @@
--background: #0b1021; // Page background
--background-darker: #05070e; // Used for navigation bar, footer and fills
+ /* Action Colors */
+ --info: #04e4f4;
+ --success: #20e253;
+ --warning: #f6f000;
+ --danger: #f80363;
+ --neutral: #272f4d;
+
+ --white: #fff;
+ --black: #000;
+
/* Modified Colors */
--item-group-background: #0b1021cc;
--medium-grey: #5e6474;
@@ -16,6 +26,11 @@
--transparent-50: #00000080;
--transparent-30: #0000004d;
+ /* Semi-Transparent White*/
+ --transparent-white-70: #ffffffb3;
+ --transparent-white-50: #ffffff80;
+ --transparent-white-30: #ffffff4d;
+
/* Other Variables */
--outline-color: none;
--curve-factor: 5px; // Border radius for most components
diff --git a/src/styles/global-styles.scss b/src/styles/global-styles.scss
index eff1b415..122893e3 100644
--- a/src/styles/global-styles.scss
+++ b/src/styles/global-styles.scss
@@ -20,6 +20,14 @@ h1, h2, h3, h4, h5 {
font-family: 'Inconsolata', sans-serif;
}
+.bold { font-weight: bold; }
+.light { font-weight: lighter; }
+.text-left { text-align: left;}
+.text-right { text-align: right;}
+.text-center { text-align: center;}
+.horizontal-center { margin: 0 auto; }
+.border-box { box-sizing: border-box; }
+
/* Overiding styles for the global toast component */
.toast-message {
background: var(--toast-background) !important;
@@ -29,4 +37,15 @@ h1, h2, h3, h4, h5 {
font-size: 1.25rem !important;
}
+.toast-error {
+ background: var(--danger) !important;
+ color: var(--white) !important;
+ font-size: 1.25rem !important;
+}
+.toast-success {
+ background: var(--success) !important;
+ color: var(--white) !important;
+ font-size: 1.25rem !important;
+}
+
diff --git a/src/utils/CloudBackup.js b/src/utils/CloudBackup.js
index 41067407..17e24400 100644
--- a/src/utils/CloudBackup.js
+++ b/src/utils/CloudBackup.js
@@ -1,9 +1,10 @@
/* eslint-disable */
import sha256 from 'crypto-js/sha256';
import aes from 'crypto-js/aes';
-import Base64 from 'crypto-js/enc-base64';
-import Hex from 'crypto-js/enc-hex';
import Utf8 from 'crypto-js/enc-utf8';
+import axios from 'axios';
+
+const ENDPOINT = 'https://dashy-sync-service.as93.net/';
/* Stringify, encrypt and encode data for transmission */
const encryptData = (data, password) => {
@@ -22,11 +23,16 @@ const makeSubHash = (pass) => sha256(pass).toString().slice(0, 14);
/* Makes the backup */
export const backup = (data, password) => {
- // const subHash = makeSubHash(password);
- const encryptedData = encryptData(data, password);
- console.log(encryptedData);
- console.log(decryptData(encryptedData, password));
+ return axios.post(ENDPOINT, {
+ userData: encryptData(data, password),
+ subHash: makeSubHash(password),
+ });
};
/* Restores the backup */
-export const restore = (backupId, password) => { };
+export const restore = (backupId, password) => {
+ // return axios.get(ENDPOINT, {
+ // backupId,
+ // subHash: makeSubHash(password),
+ // });
+};
diff --git a/src/utils/defaults.js b/src/utils/defaults.js
index 6d134854..f79904d8 100644
--- a/src/utils/defaults.js
+++ b/src/utils/defaults.js
@@ -47,6 +47,8 @@ module.exports = {
CONF_SECTIONS: 'confSections',
PAGE_INFO: 'pageInfo',
APP_CONFIG: 'appConfig',
+ BACKUP_ID: 'backupId',
+ BACKUP_HASH: 'backupHash',
},
topLevelConfKeys: {
PAGE_INFO: 'pageInfo',
@@ -55,7 +57,7 @@ module.exports = {
},
toastedOptions: {
position: 'bottom-center',
- duration: 2000,
+ duration: 2500,
keepOnHover: true,
className: 'toast-message',
iconPack: 'fontawesome',
diff --git a/yarn.lock b/yarn.lock
index 603f1a5e..07b81c7f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1904,6 +1904,13 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+axios@^0.21.1:
+ version "0.21.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+ integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+ dependencies:
+ follow-redirects "^1.10.0"
+
babel-eslint@^10.0.1:
version "10.1.0"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@@ -2956,6 +2963,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
+crypto-js@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
+ integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
+
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -4167,6 +4179,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
+follow-redirects@^1.10.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
+ integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
+
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"