diff --git a/apps/web/src/common/index.ts b/apps/web/src/common/index.ts index f58402b61..076274b34 100644 --- a/apps/web/src/common/index.ts +++ b/apps/web/src/common/index.ts @@ -231,15 +231,40 @@ export async function restoreBackupFile(backupFile: File) { } await db.initCollections(); } else { + const { createUnzipIterator } = await import( + "../utils/streams/unzip-stream" + ); + + let skipAttachments = false; + if (!useUserStore.getState().isLoggedIn) { + let hasAttachments = false; + for await (const entry of createUnzipIterator(backupFile)) { + if ( + entry.name.startsWith("attachments/") && + entry.name !== "attachments/.attachments_key" + ) { + hasAttachments = true; + break; + } + } + + if (hasAttachments) { + const result = await ConfirmDialog.show({ + title: strings.loginToRestoreAttachments(), + message: strings.loginToRestoreAttachmentsDesc(), + positiveButtonText: strings.yes(), + negativeButtonText: strings.no() + }); + if (!result) return; + skipAttachments = true; + } + } + const error = await TaskManager.startTask({ title: strings.restoringBackup(), subtitle: strings.restoringBackupDesc(), type: "modal", action: async (report) => { - const { createUnzipIterator } = await import( - "../utils/streams/unzip-stream" - ); - let cachedPassword: string | undefined = undefined; let cachedKey: string | undefined = undefined; // const { read, totalFiles } = await Reader(backupFile); @@ -254,13 +279,13 @@ export async function restoreBackupFile(backupFile: File) { isValid = true; continue; } - if (entry.name === "attachments/.attachments_key") + if (!skipAttachments && entry.name === "attachments/.attachments_key") attachmentsKey = JSON.parse(await entry.text()) as | SerializedKey | Cipher<"base64">; - else if (entry.name.startsWith("attachments/")) + else if (!skipAttachments && entry.name.startsWith("attachments/")) attachments.push(entry); - else entries.push(entry); + else if (!entry.name.startsWith("attachments/")) entries.push(entry); } if (!isValid) console.warn( @@ -339,6 +364,8 @@ export async function restoreBackupFile(backupFile: File) { if (error) { console.error(error); showToast("error", `${strings.restoreFailed()}: ${error.message}`); + } else { + showToast("success", strings.backupRestored()); } } } diff --git a/apps/web/src/interfaces/fs.ts b/apps/web/src/interfaces/fs.ts index 7bc5cb340..fda669c2e 100644 --- a/apps/web/src/interfaces/fs.ts +++ b/apps/web/src/interfaces/fs.ts @@ -49,6 +49,7 @@ import { } from "@notesnook/core"; import { logger } from "../utils/logger"; import { newQueue } from "@henrygd/queue"; +import { strings } from "@notesnook/intl"; export const ABYTES = 17; const CHUNK_SIZE = 512 * 1024; @@ -499,12 +500,20 @@ async function downloadFile( { type: "download", hash: filename } ); - const signedUrl = ( - await axios.get(url, { - headers, - responseType: "text" - }) - ).data; + const signedUrlResponse = await axios + .get(url, { headers, responseType: "text" }) + .catch((e) => { + if (e.response?.status === 401) { + showToast("error", strings.pleaseLoginToDownloadAttachments()); + return null; + } + throw e; + }); + if (!signedUrlResponse) { + reportProgress(undefined, { type: "download", hash: filename }); + return false; + } + const signedUrl = signedUrlResponse.data; logger.debug("Got attachment signed url", { filename }); diff --git a/docs/help/contents/faqs/login-to-restore-attachments-in-backup.md b/docs/help/contents/faqs/login-to-restore-attachments-in-backup.md new file mode 100644 index 000000000..13bddecfb --- /dev/null +++ b/docs/help/contents/faqs/login-to-restore-attachments-in-backup.md @@ -0,0 +1,8 @@ +--- +title: Login to restore attachments in backup. +description: We require users to be logged in to restore attachments in backup. +--- + +# Login to restore attachments in backup. + +We require users to be logged in to restore attachments in backup. This is because attachments are encrypted using a sub-key derived from your database encryption key. Without a login, we cannot encrypt/upload/sync attachments. diff --git a/docs/help/docgen.yaml b/docs/help/docgen.yaml index 4f0c76900..1f0e647ac 100644 --- a/docs/help/docgen.yaml +++ b/docs/help/docgen.yaml @@ -87,3 +87,4 @@ navigation: - path: faqs/what-are-merge-conflicts.md - path: faqs/is-there-an-eta.md - path: faqs/login-to-upload-attachments.md + - path: faqs/login-to-restore-attachments-in-backup.md diff --git a/packages/intl/locale/en.po b/packages/intl/locale/en.po index 3bc3c0f7e..2f6857a76 100644 --- a/packages/intl/locale/en.po +++ b/packages/intl/locale/en.po @@ -3789,6 +3789,10 @@ msgstr "Login failed" msgid "Login required" msgstr "Login required" +#: src/strings.ts:2671 +msgid "Login required to restore attachments" +msgstr "Login required to restore attachments" + #: src/strings.ts:779 msgid "Login successful" msgstr "Login successful" @@ -4736,6 +4740,10 @@ msgstr "Please fill all the fields to continue." msgid "Please grant notifications permission to add new reminders." msgstr "Please grant notifications permission to add new reminders." +#: src/strings.ts:2666 +msgid "Please login to download attachments." +msgstr "Please login to download attachments." + #: src/strings.ts:873 msgid "Please make sure you have saved the recovery key. Tap one more time to confirm." msgstr "Please make sure you have saved the recovery key. Tap one more time to confirm." @@ -7490,6 +7498,16 @@ msgstr "You have unsynced notes. Take a backup or sync your notes to avoid losin msgid "You must log out in order to change/reset server URLs." msgstr "You must log out in order to change/reset server URLs." +#: src/strings.ts:2673 +msgid "" +"You need to login to restore attachments from a backup file. [Read more](https://help.notesnook.com/faqs/login-to-restore-attachments-in-backup).\n" +" \n" +"Continue without attachments?" +msgstr "" +"You need to login to restore attachments from a backup file. [Read more](https://help.notesnook.com/faqs/login-to-restore-attachments-in-backup).\n" +" \n" +"Continue without attachments?" + #: src/strings.ts:836 msgid "You simply cannot get any better of a note taking app than @notesnook. The UI is clean and slick, it is feature rich, encrypted, reasonably priced (esp. for students & educators) & open source" msgstr "You simply cannot get any better of a note taking app than @notesnook. The UI is clean and slick, it is feature rich, encrypted, reasonably priced (esp. for students & educators) & open source" diff --git a/packages/intl/locale/pseudo-LOCALE.po b/packages/intl/locale/pseudo-LOCALE.po index 0ca7eae41..31f2f27ba 100644 --- a/packages/intl/locale/pseudo-LOCALE.po +++ b/packages/intl/locale/pseudo-LOCALE.po @@ -3769,6 +3769,10 @@ msgstr "" msgid "Login required" msgstr "" +#: src/strings.ts:2671 +msgid "Login required to restore attachments" +msgstr "" + #: src/strings.ts:779 msgid "Login successful" msgstr "" @@ -4710,6 +4714,10 @@ msgstr "" msgid "Please grant notifications permission to add new reminders." msgstr "" +#: src/strings.ts:2666 +msgid "Please login to download attachments." +msgstr "" + #: src/strings.ts:873 msgid "Please make sure you have saved the recovery key. Tap one more time to confirm." msgstr "" @@ -7432,6 +7440,13 @@ msgstr "" msgid "You must log out in order to change/reset server URLs." msgstr "" +#: src/strings.ts:2673 +msgid "" +"You need to login to restore attachments from a backup file. [Read more](https://help.notesnook.com/faqs/login-to-restore-attachments-in-backup).\n" +" \n" +"Continue without attachments?" +msgstr "" + #: src/strings.ts:836 msgid "You simply cannot get any better of a note taking app than @notesnook. The UI is clean and slick, it is feature rich, encrypted, reasonably priced (esp. for students & educators) & open source" msgstr "" diff --git a/packages/intl/src/strings.ts b/packages/intl/src/strings.ts index 92e750d0c..e318c1a76 100644 --- a/packages/intl/src/strings.ts +++ b/packages/intl/src/strings.ts @@ -2667,5 +2667,12 @@ Use this if changes from other devices are not appearing on this device. This wi attachmentDeleted: () => t`Attachment deleted`, titleIsRequired: () => t`Title is required`, nameIsRequired: () => t`Name is required.`, - currentPasswordRequired: () => t`Current password required` + currentPasswordRequired: () => t`Current password required`, + loginToRestoreAttachments: () => t`Login required to restore attachments`, + loginToRestoreAttachmentsDesc: () => + t`You need to login to restore attachments from a backup file. [Read more](https://help.notesnook.com/faqs/login-to-restore-attachments-in-backup). + +Continue without attachments?`, + pleaseLoginToDownloadAttachments: () => + t`Please login to download attachments.` };