2020-03-07 12:29:55 +05:00
|
|
|
import Database from "./index";
|
|
|
|
|
|
|
|
|
|
const ERRORS = {
|
|
|
|
|
noVault: "ERR_NO_VAULT",
|
|
|
|
|
vaultLocked: "ERR_VAULT_LOCKED"
|
|
|
|
|
};
|
|
|
|
|
export default class Vault {
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {Database} database
|
|
|
|
|
*/
|
|
|
|
|
constructor(database, context) {
|
2020-03-08 11:33:55 +05:00
|
|
|
this._db = database;
|
|
|
|
|
this._context = context;
|
|
|
|
|
this._key = "Notesnook";
|
|
|
|
|
this._password = "";
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async create(password) {
|
2020-03-08 11:33:55 +05:00
|
|
|
const lockKey = await this._context.read("lockKey");
|
2020-03-07 12:29:55 +05:00
|
|
|
if (!lockKey || !lockKey.cipher || !lockKey.iv) {
|
2020-03-08 11:33:55 +05:00
|
|
|
const encryptedData = await this._context.encrypt(password, this._key);
|
|
|
|
|
await this._context.write("lockKey", encryptedData);
|
|
|
|
|
this._password = password;
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async unlock(password) {
|
2020-03-08 11:33:55 +05:00
|
|
|
const lockKey = await this._context.read("lockKey");
|
2020-03-09 10:43:32 +05:00
|
|
|
if (!(await this._exists(lockKey))) throw new Error("ERR_NO_VAULT");
|
2020-03-07 12:29:55 +05:00
|
|
|
var data;
|
|
|
|
|
try {
|
2020-03-08 11:33:55 +05:00
|
|
|
data = await this._context.decrypt(password, lockKey);
|
2020-03-07 12:29:55 +05:00
|
|
|
} catch (e) {
|
|
|
|
|
throw new Error("ERR_WRNG_PWD");
|
|
|
|
|
}
|
2020-03-08 11:33:55 +05:00
|
|
|
if (data !== this._key) {
|
2020-03-07 12:29:55 +05:00
|
|
|
throw new Error("ERR_WRNG_PWD");
|
|
|
|
|
}
|
2020-03-08 11:33:55 +05:00
|
|
|
this._password = password;
|
2020-03-07 12:29:55 +05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _exists(lockKey) {
|
2020-03-08 11:33:55 +05:00
|
|
|
if (!lockKey) lockKey = await this._context.read("lockKey");
|
2020-03-07 12:29:55 +05:00
|
|
|
return lockKey && lockKey.cipher && lockKey.iv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _locked() {
|
2020-03-08 11:33:55 +05:00
|
|
|
return !this._password || !this._password.length;
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _check() {
|
|
|
|
|
if (!(await this._exists())) {
|
|
|
|
|
throw new Error(ERRORS.noVault);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (await this._locked()) {
|
|
|
|
|
throw new Error(ERRORS.vaultLocked);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async add(id) {
|
|
|
|
|
await this._check();
|
2020-03-08 11:33:55 +05:00
|
|
|
const note = this._db.notes.note(id).data;
|
|
|
|
|
await this._lockNote(id, note);
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async remove(id, password) {
|
|
|
|
|
if (await this.unlock(password)) {
|
2020-03-08 11:33:55 +05:00
|
|
|
const note = this._db.notes.note(id).data;
|
|
|
|
|
await this._unlockNote(note, true);
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async open(id, password) {
|
|
|
|
|
if (await this.unlock(password)) {
|
2020-03-08 11:33:55 +05:00
|
|
|
const note = this._db.notes.note(id).data;
|
|
|
|
|
return this._unlockNote(note, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async save(note) {
|
|
|
|
|
if (!note) return;
|
|
|
|
|
await this._check();
|
|
|
|
|
let id = note.id || Date.now().toString() + "_note";
|
|
|
|
|
return await this._lockNote(id, note);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_encryptText(text) {
|
|
|
|
|
return this._context.encrypt(this._password, JSON.stringify({ text }));
|
|
|
|
|
}
|
|
|
|
|
async _decryptText(text) {
|
|
|
|
|
const decrypted = await this._context.decrypt(this._password, text);
|
|
|
|
|
return JSON.parse(decrypted);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _encryptDelta(id, deltaArg) {
|
|
|
|
|
if (!deltaArg) return;
|
|
|
|
|
const delta = await this._context.encrypt(
|
|
|
|
|
this._password,
|
|
|
|
|
JSON.stringify(deltaArg)
|
|
|
|
|
);
|
|
|
|
|
await this._context.write(this._deltaId(id), delta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _decryptDelta(id) {
|
|
|
|
|
const delta = await this._context.read(this._deltaId(id));
|
|
|
|
|
const decrypted = await this._context.decrypt(this._password, delta);
|
|
|
|
|
return JSON.parse(decrypted);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_deltaId(id) {
|
|
|
|
|
return id + "_delta";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _lockNote(id, note) {
|
|
|
|
|
if (!note) return;
|
|
|
|
|
|
|
|
|
|
let delta = note.content.delta;
|
|
|
|
|
if (!delta) delta = await this._context.read(this._deltaId(id));
|
|
|
|
|
await this._encryptDelta(id, delta);
|
|
|
|
|
|
|
|
|
|
const content = await this._encryptText(note.content.text);
|
|
|
|
|
|
|
|
|
|
return await this._db.notes.add({
|
|
|
|
|
id,
|
|
|
|
|
content,
|
|
|
|
|
locked: true
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _unlockNote(note, perm = false) {
|
|
|
|
|
if (!note.locked) return;
|
|
|
|
|
|
|
|
|
|
let decrypted = await this._decryptText(note.content);
|
|
|
|
|
let delta = await this._decryptDelta(note.id);
|
|
|
|
|
|
|
|
|
|
if (perm) {
|
|
|
|
|
await this._db.notes.add({
|
|
|
|
|
id: note.id,
|
|
|
|
|
content: decrypted,
|
|
|
|
|
locked: false
|
|
|
|
|
});
|
|
|
|
|
return await this._context.write(this._deltaId(note.id), delta);
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
2020-03-08 11:33:55 +05:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...note,
|
|
|
|
|
content: { ...decrypted, delta }
|
|
|
|
|
};
|
2020-03-07 12:29:55 +05:00
|
|
|
}
|
|
|
|
|
}
|