Adds backup functionality

This commit is contained in:
Alicia Sykes
2021-05-24 17:25:16 +01:00
parent 8ffbfb8123
commit 44b2594dfa
9 changed files with 150 additions and 16 deletions

View File

@@ -14,21 +14,30 @@
</p>
</div>
<div class="section backup-section">
<h3>Backup</h3>
<h3 v-if="backupId">Update Backup</h3>
<h3 v-else>Make a Backup</h3>
<Input
v-model="backupPassword"
name="backup-password"
label="Choose a Password"
:label="backupId ? 'Enter your Password' : 'Choose a Password'"
layout="vertical"
type="password"
/>
<Button>
<template v-slot:text>Backup</template>
<Button :click="checkPass">
<template v-slot:text>{{backupId ? 'Update Backup' : 'Backup'}}</template>
<template v-slot:icon><IconBackup /></template>
</Button>
<div class="results-view" v-if="backupId">
<span class="backup-id-label">Your Backup ID: </span>
<pre class="backup-id-value">{{ backupId }}</pre>
<span class="backup-id-note">
This is used to restore from backups later.
So keep it, along with your password somewhere safe.
</span>
</div>
</div>
<div class="section restore-section">
<h3>Restore</h3>
<h3>Restore a Backup</h3>
<Input
v-model="restoreCode"
name="restore-code"
@@ -50,10 +59,13 @@
<script>
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();
},
},
};
</script>
@@ -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;

View File

@@ -1,5 +1,5 @@
<template>
<button>
<button @click="click()">
<slot name="text"></slot>
<slot name="icon"></slot>
</button>
@@ -11,6 +11,7 @@ export default {
name: 'Button',
props: {
text: String,
click: Function,
},
};
</script>

View File

@@ -14,7 +14,7 @@
</modal>
<!-- Modal for cloud backup and restore options -->
<modal :name="modalNames.CLOUD_BACKUP" :resizable="true" width="60%" height="60%"
<modal :name="modalNames.CLOUD_BACKUP" :resizable="true" width="65%" height="60%"
@closed="$emit('modalChanged', false)">
<CloudBackupRestore :config="combineConfig()" />
</modal>

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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),
// });
};

View File

@@ -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',