mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 15:09:33 +01:00
core: minor updates and fixes
This commit is contained in:
@@ -24,7 +24,7 @@ import v56BackupCopy from "./__fixtures__/backup.v5.6.json";
|
|||||||
import v58BackupCopy from "./__fixtures__/backup.v5.8.json";
|
import v58BackupCopy from "./__fixtures__/backup.v5.8.json";
|
||||||
import qclone from "qclone";
|
import qclone from "qclone";
|
||||||
import { test, expect, describe } from "vitest";
|
import { test, expect, describe } from "vitest";
|
||||||
import { makeId } from "../src/utils/id";
|
import { getId, makeId } from "../src/utils/id";
|
||||||
|
|
||||||
test("export backup", () =>
|
test("export backup", () =>
|
||||||
notebookTest().then(async ({ db }) => {
|
notebookTest().then(async ({ db }) => {
|
||||||
@@ -79,7 +79,7 @@ test("import backup", () =>
|
|||||||
exp.push(file);
|
exp.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.storage.clear();
|
await db.storage().clear();
|
||||||
await db.backup.import(JSON.parse(exp[1].data));
|
await db.backup.import(JSON.parse(exp[1].data));
|
||||||
expect(db.notebooks.notebook(id).data.id).toBe(id);
|
expect(db.notebooks.notebook(id).data.id).toBe(id);
|
||||||
}));
|
}));
|
||||||
@@ -94,7 +94,7 @@ test("import encrypted backup", () =>
|
|||||||
exp.push(file);
|
exp.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.storage.clear();
|
await db.storage().clear();
|
||||||
await db.backup.import(JSON.parse(exp[1].data), "password");
|
await db.backup.import(JSON.parse(exp[1].data), "password");
|
||||||
expect(db.notebooks.notebook(id).data.id).toBe(id);
|
expect(db.notebooks.notebook(id).data.id).toBe(id);
|
||||||
}));
|
}));
|
||||||
@@ -108,7 +108,7 @@ test("import tempered backup", () =>
|
|||||||
exp.push(file);
|
exp.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.storage.clear();
|
await db.storage().clear();
|
||||||
const backup = JSON.parse(exp[1].data);
|
const backup = JSON.parse(exp[1].data);
|
||||||
backup.data += "hello";
|
backup.data += "hello";
|
||||||
await expect(db.backup.import(backup)).rejects.toThrow(/tempered/);
|
await expect(db.backup.import(backup)).rejects.toThrow(/tempered/);
|
||||||
@@ -198,7 +198,7 @@ describe.each([
|
|||||||
return databaseTest().then(async (db) => {
|
return databaseTest().then(async (db) => {
|
||||||
await db.backup.import(qclone(data));
|
await db.backup.import(qclone(data));
|
||||||
|
|
||||||
const keys = await db.storage.getAllKeys();
|
const keys = await db.storage().getAllKeys();
|
||||||
for (let key in data.data) {
|
for (let key in data.data) {
|
||||||
const item = data.data[key];
|
const item = data.data[key];
|
||||||
if (item && !item.type && item.deleted) continue;
|
if (item && !item.type && item.deleted) continue;
|
||||||
@@ -209,7 +209,6 @@ describe.each([
|
|||||||
key === "token"
|
key === "token"
|
||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
expect(keys.some((k) => k.startsWith(key))).toBeTruthy();
|
expect(keys.some((k) => k.startsWith(key))).toBeTruthy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ export class Tags implements ICollection {
|
|||||||
return this.collection.get(id);
|
return this.collection.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
find(idOrTitle: string) {
|
||||||
|
return this.all.find(
|
||||||
|
(tag) => tag.title === idOrTitle || tag.id === idOrTitle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async merge(remoteTag: MaybeDeletedItem<Tag>) {
|
async merge(remoteTag: MaybeDeletedItem<Tag>) {
|
||||||
if (!remoteTag) return;
|
if (!remoteTag) return;
|
||||||
|
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ export default class Backup {
|
|||||||
|
|
||||||
while (chunks.length > 0) {
|
while (chunks.length > 0) {
|
||||||
const chunk = chunks.pop();
|
const chunk = chunks.pop();
|
||||||
|
if (!chunk) break;
|
||||||
|
|
||||||
const items = await this.db.storage().readMulti(chunk);
|
const items = await this.db.storage().readMulti(chunk);
|
||||||
items.forEach(([id, item]) => {
|
items.forEach(([id, item]) => {
|
||||||
@@ -282,7 +283,7 @@ export default class Backup {
|
|||||||
|
|
||||||
if (!decryptedData) return;
|
if (!decryptedData) return;
|
||||||
|
|
||||||
if ("hash" in backup && !this.verify(backup))
|
if ("hash" in backup && !this.verify(backup, decryptedData))
|
||||||
throw new Error("Backup file has been tempered, aborting...");
|
throw new Error("Backup file has been tempered, aborting...");
|
||||||
|
|
||||||
if ("compressed" in backup && typeof decryptedData === "string")
|
if ("compressed" in backup && typeof decryptedData === "string")
|
||||||
@@ -342,10 +343,6 @@ export default class Backup {
|
|||||||
if ("sessionContentId" in item && item.type !== "session")
|
if ("sessionContentId" in item && item.type !== "session")
|
||||||
(item as any).type = "notehistory";
|
(item as any).type = "notehistory";
|
||||||
|
|
||||||
// colors are naively of type "tag" instead of "color" so we have to fix that.
|
|
||||||
if (item.type === "tag" && COLORS.includes(item.title.toLowerCase()))
|
|
||||||
(item as any).type = "color";
|
|
||||||
|
|
||||||
await migrateItem(item, version, item.type, this.db, "backup");
|
await migrateItem(item, version, item.type, this.db, "backup");
|
||||||
// since items in trash can have their own set of migrations,
|
// since items in trash can have their own set of migrations,
|
||||||
// we have to run the migration again to account for that.
|
// we have to run the migration again to account for that.
|
||||||
@@ -395,7 +392,13 @@ export default class Backup {
|
|||||||
if (item.type === "settings")
|
if (item.type === "settings")
|
||||||
await this.db.storage().write("settings", item);
|
await this.db.storage().write("settings", item);
|
||||||
else {
|
else {
|
||||||
const itemType = "itemType" in item ? item.itemType : item.type;
|
const itemType =
|
||||||
|
// colors are naively of type "tag" instead of "color" so we have to fix that.
|
||||||
|
item.type === "tag" && COLORS.includes(item.title.toLowerCase())
|
||||||
|
? "color"
|
||||||
|
: "itemType" in item
|
||||||
|
? item.itemType
|
||||||
|
: item.type;
|
||||||
const collectionKey = itemTypeToCollectionKey[itemType];
|
const collectionKey = itemTypeToCollectionKey[itemType];
|
||||||
if (collectionKey) {
|
if (collectionKey) {
|
||||||
toAdd[collectionKey] = toAdd[collectionKey] || [];
|
toAdd[collectionKey] = toAdd[collectionKey] || [];
|
||||||
@@ -423,17 +426,16 @@ export default class Backup {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private verify(backup: BackupFile | LegacyUnencryptedBackupFile) {
|
private verify(
|
||||||
const { hash, hash_type, data } = backup;
|
backup: BackupFile | LegacyUnencryptedBackupFile,
|
||||||
|
data: string | Record<string, BackupDataItem>
|
||||||
|
) {
|
||||||
|
const { hash, hash_type } = backup;
|
||||||
switch (hash_type) {
|
switch (hash_type) {
|
||||||
case "md5": {
|
case "md5": {
|
||||||
return (
|
return (
|
||||||
hash ===
|
hash ===
|
||||||
SparkMD5.hash(
|
SparkMD5.hash(typeof data === "string" ? data : JSON.stringify(data))
|
||||||
"compressed" in backup && backup.compressed
|
|
||||||
? data
|
|
||||||
: JSON.stringify(data)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import SparkMD5 from "spark-md5";
|
|||||||
import ObjectID from "./object-id";
|
import ObjectID from "./object-id";
|
||||||
|
|
||||||
export function getId(time?: number) {
|
export function getId(time?: number) {
|
||||||
if (time) return ObjectID.createFromTime(time).toHexString();
|
if (time)
|
||||||
|
return new ObjectID(new ObjectID().generate(time / 1000)).toHexString();
|
||||||
return new ObjectID().toHexString();
|
return new ObjectID().toHexString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user