feat: implement database backup

This commit is contained in:
thecodrr
2020-09-13 13:24:24 +05:00
parent 842e851ee3
commit 06707669dd
5 changed files with 95 additions and 1 deletions

View File

@@ -23,6 +23,9 @@ function remove(key) {
function clear() {
storage = {};
}
function getAllKeys() {
return Object.keys(storage);
}
function encrypt(password, data) {
return new Promise((resolve, reject) => {
@@ -39,7 +42,7 @@ function encrypt(password, data) {
function decrypt(key, data) {
return new Promise((resolve, reject) => {
if (key.password === data.key.password) resolve(data.cipher);
if (!key || key.password === data.key.password) resolve(data.cipher);
else reject("Wrong password");
});
}
@@ -59,4 +62,5 @@ module.exports = {
encrypt,
decrypt,
deriveKey,
getAllKeys,
};

View File

@@ -0,0 +1,51 @@
import {
StorageInterface,
databaseTest,
noteTest,
groupedTest,
LONG_TEXT,
TEST_NOTE,
TEST_NOTEBOOK,
notebookTest,
TEST_NOTEBOOK2,
} from "./utils";
beforeEach(async () => {
StorageInterface.clear();
});
test("export backup", () =>
noteTest().then(() =>
notebookTest().then(async ({ db }) => {
const exp = await db.backup.export();
expect(JSON.parse(exp).t).toBeGreaterThan(0);
})
));
test("export encrypted backup", () =>
noteTest().then(() =>
notebookTest().then(async ({ db }) => {
const exp = await db.backup.export(true);
expect(JSON.parse(exp).iv).toBe("some iv");
})
));
test("import backup", () =>
noteTest().then(() =>
notebookTest().then(async ({ db, id }) => {
const exp = await db.backup.export();
await db.context.clear();
await db.backup.import(exp);
expect(db.notebooks.notebook(id).data.id).toBe(id);
})
));
test("import encrypted backup", () =>
noteTest().then(() =>
notebookTest().then(async ({ db, id }) => {
const exp = await db.backup.export(true);
await db.context.clear();
await db.backup.import(exp);
expect(db.notebooks.notebook(id).data.id).toBe(id);
})
));

View File

@@ -8,6 +8,7 @@ import Sync from "./sync";
import Vault from "./vault";
import Lookup from "./lookup";
import Content from "../collections/content";
import Backup from "../database/backup";
import Conflicts from "./sync/conflicts";
import EventManager from "../utils/event-manager";
import Session from "./session";
@@ -44,6 +45,7 @@ class Database {
this.vault = new Vault(this);
this.conflicts = new Conflicts(this);
this.lookup = new Lookup(this);
this.backup = new Backup(this);
// collections
/** @type {Notes} */

View File

@@ -0,0 +1,34 @@
export default class Backup {
/**
*
* @param {import("../api/index.js").default} db
*/
constructor(db) {
this._db = db;
}
async export(encrypt = false) {
const keys = await this._db.context.getAllKeys();
const db = Object.fromEntries(await this._db.context.readMulti(keys));
if (encrypt) {
const key = await this._db.user.key();
return JSON.stringify(
await this._db.context.encrypt(key, JSON.stringify(db))
);
}
return JSON.stringify(db);
}
async import(data) {
let backup = JSON.parse(data);
//check if we have encrypted data
if (backup.salt && backup.iv) {
const key = await this._db.user.key();
backup = JSON.parse(await this._db.context.decrypt(key, backup));
}
for (let key in backup) {
let value = backup[key];
await this._db.context.write(key, value);
}
}
}

View File

@@ -17,6 +17,9 @@ export default class Storage {
remove(key) {
return this.storage.remove(key);
}
getAllKeys() {
return this.storage.getAllKeys();
}
encrypt(password, data) {
return this.storage.encrypt(password, data);
}