feat: add versioned backup export

This commit is contained in:
thecodrr
2020-11-24 12:53:52 +05:00
parent bae5c36bee
commit 141451a783

View File

@@ -1,4 +1,3 @@
import { sendCheckUserStatusEvent } from "../common.js";
import Hashes from "jshashes"; import Hashes from "jshashes";
const md5 = new Hashes.MD5(); const md5 = new Hashes.MD5();
@@ -26,34 +25,29 @@ export default class Backup {
if (encrypt && !(await sendCheckUserStatusEvent("backup:encrypt"))) return; if (encrypt && !(await sendCheckUserStatusEvent("backup:encrypt"))) return;
if (!validTypes.some((t) => t === type)) if (!validTypes.some((t) => t === type))
throw new Error( throw new Error("Invalid type. It must be one of 'mobile' or 'web'.");
"Invalid type. It must be one of 'mobile' or 'web' or 'node'."
);
const keys = (await this._db.context.getAllKeys()).filter( const keys = (await this._db.context.getAllKeys()).filter(
(key) => !invalidKeys.some((t) => t === key) (key) => !invalidKeys.some((t) => t === key)
); );
const db = Object.fromEntries(await this._db.context.readMulti(keys)); let data = Object.fromEntries(await this._db.context.readMulti(keys));
db.h = md5.hex(JSON.stringify(db));
db.ht = "md5";
if (encrypt) { if (encrypt) {
const key = await this._db.user.key(); const key = await this._db.user.key();
return JSON.stringify({ data = await this._db.context.encrypt(key, JSON.stringify(data));
type,
date: Date.now(),
data: await this._db.context.encrypt(key, JSON.stringify(db)),
});
} }
// save backup time // save backup time
await this._db.context.write("lastBackupTime", Date.now()); await this._db.context.write("lastBackupTime", Date.now());
return JSON.stringify({ return JSON.stringify({
version: 2,
type, type,
date: Date.now(), date: Date.now(),
data: db, data,
hash: md5.hex(JSON.stringify(data)),
hash_type: "md5",
}); });
} }
@@ -75,16 +69,26 @@ export default class Backup {
db = JSON.parse(await this._db.context.decrypt(key, db)); db = JSON.parse(await this._db.context.decrypt(key, db));
} }
if (!this._verify(db)) if (!this._verify(backup))
throw new Error("Backup file has been tempered, aborting..."); throw new Error("Backup file has been tempered, aborting...");
// TODO add a proper restoration system.
// for (let key in db) {
// let value = db[key];
// if (value && value.dateEdited) {
// value.dateEdited = Date.now();
// }
for (let key in db) { // const oldValue = await this._db.context.read(oldValue);
let value = db[key];
if (value && value.dateEdited) { // let finalValue = oldValue || value;
value.dateEdited = Date.now(); // if (typeof value === "object") {
} // finalValue = Array.isArray(value)
await this._db.context.write(key, value); // ? [...value, ...oldValue]
} // : { ...value, ...oldValue };
// }
// await this._db.context.write(key, finalValue);
// }
} }
_validate(backup) { _validate(backup) {
@@ -96,14 +100,11 @@ export default class Backup {
); );
} }
_verify(db) { _verify(backup) {
const hash = db.h; const { hash, hash_type, data: db } = backup;
const hash_type = db.ht;
delete db.h;
delete db.ht;
switch (hash_type) { switch (hash_type) {
case "md5": { case "md5": {
return hash == md5.hex(JSON.stringify(db)); return hash === md5.hex(JSON.stringify(db));
} }
default: { default: {
return false; return false;