mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 02:58:34 +02:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d1119cf0 | ||
|
|
3f11b76811 | ||
|
|
d912c93f81 | ||
|
|
e635bf628a | ||
|
|
8048c90a89 | ||
|
|
8093f44a70 | ||
|
|
f67f90cecd | ||
|
|
ff4e2631cb | ||
|
|
d3f1690dca |
4
apps/desktop/package-lock.json
generated
4
apps/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
|
||||
@@ -29,6 +29,10 @@ import ImagePicker from "react-native-image-crop-picker";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../common/database";
|
||||
import { presentDialog } from "../../components/dialog/functions";
|
||||
import {
|
||||
createFormRef,
|
||||
validators
|
||||
} from "../../components/ui/input/form-input";
|
||||
import { PlanLimits } from "../../components/sheets/plan-limits";
|
||||
import AppIcon from "../../components/ui/AppIcon";
|
||||
import { Button } from "../../components/ui/button";
|
||||
@@ -197,27 +201,34 @@ const SettingsUserSection = ({ item }) => {
|
||||
title: strings.setFullName(),
|
||||
paragraph: strings.setFullNameDesc(),
|
||||
positiveText: strings.save(),
|
||||
input: true,
|
||||
inputPlaceholder: strings.enterFullName(),
|
||||
defaultValue: userProfile?.fullName,
|
||||
positivePress: async (value) => {
|
||||
if (!value || !value.trim()) {
|
||||
ToastManager.error(
|
||||
new Error(strings.nameIsRequired()),
|
||||
undefined,
|
||||
"local"
|
||||
);
|
||||
return;
|
||||
}
|
||||
db.settings
|
||||
.setProfile({
|
||||
fullName: value
|
||||
})
|
||||
.then(async () => {
|
||||
form: {
|
||||
formRef: createFormRef({
|
||||
fullName: userProfile?.fullName || ""
|
||||
}),
|
||||
items: [
|
||||
{
|
||||
name: "fullName",
|
||||
placeholder: strings.enterFullName(),
|
||||
defaultValue: userProfile?.fullName,
|
||||
validators: [
|
||||
validators.required(strings.nameIsRequired())
|
||||
]
|
||||
}
|
||||
],
|
||||
onFormSubmit: async (form) => {
|
||||
try {
|
||||
await db.settings.setProfile({
|
||||
fullName: form.getValue("fullName")
|
||||
});
|
||||
useUserStore.setState({
|
||||
profile: db.settings.getProfile()
|
||||
});
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
form.setError("fullName", e.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -2235,14 +2235,35 @@ PODS:
|
||||
- ReactCommon/turbomodule/core
|
||||
- SocketRocket
|
||||
- Yoga
|
||||
- react-native-screenguard (1.0.0):
|
||||
- react-native-screenguard (2.0.0-beta5):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
- fast_float
|
||||
- fmt
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly
|
||||
- RCT-Folly/Fabric
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Codegen
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- React-jsi
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-renderercss
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCodegen
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- SDWebImage (~> 5.11.1)
|
||||
- SDWebImage (~> 5.11)
|
||||
- SocketRocket
|
||||
- Yoga
|
||||
- react-native-share-extension (2.9.5):
|
||||
- React
|
||||
- react-native-sodium (1.6.8):
|
||||
@@ -3097,8 +3118,6 @@ PODS:
|
||||
- RNNotifee/NotifeeCore (= 7.4.12)
|
||||
- RNNotifee/NotifeeCore (7.4.12):
|
||||
- React-Core
|
||||
- RNPrivacySnapshot (1.0.0):
|
||||
- React-Core
|
||||
- RNReanimated (4.2.0):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
@@ -3573,7 +3592,6 @@ DEPENDENCIES:
|
||||
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
|
||||
- RNKeychain (from `../node_modules/react-native-keychain`)
|
||||
- "RNNotifee (from `../node_modules/@ammarahmed/notifee-react-native`)"
|
||||
- RNPrivacySnapshot (from `../node_modules/react-native-privacy-snapshot`)
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
||||
@@ -3839,8 +3857,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-keychain"
|
||||
RNNotifee:
|
||||
:path: "../node_modules/@ammarahmed/notifee-react-native"
|
||||
RNPrivacySnapshot:
|
||||
:path: "../node_modules/react-native-privacy-snapshot"
|
||||
RNReanimated:
|
||||
:path: "../node_modules/react-native-reanimated"
|
||||
RNScreens:
|
||||
@@ -3942,7 +3958,7 @@ SPEC CHECKSUMS:
|
||||
react-native-pdf: edc236298f13f1609e42d41e45b8b6ea88ed10f9
|
||||
react-native-quick-sqlite: 1ed8d3db1e22a8604d006be69f06053382e93bb0
|
||||
react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616
|
||||
react-native-screenguard: 9fc3b4ad5b97783fc0832638fae0dce51272c661
|
||||
react-native-screenguard: 975d4612dce0c348b19b08a48aa23e9b68584d98
|
||||
react-native-share-extension: fdc6aaab51591a2d445df239c446aaa3a99658ec
|
||||
react-native-sodium: 066f76e46c9be13e9260521e3fa994937c4cdab4
|
||||
react-native-theme-switch-animation: 449d6db7a760f55740505e7403ae8061debc9a7e
|
||||
@@ -3995,7 +4011,6 @@ SPEC CHECKSUMS:
|
||||
RNImageCropPicker: 5fd4ceaead64d8c53c787e4e559004f97bc76df7
|
||||
RNKeychain: ffd0513e676445c637410b47249460cbf56bc9cb
|
||||
RNNotifee: dea82c9ec44684eeeac9da85deb5eeb8ebe5937f
|
||||
RNPrivacySnapshot: ccad3a548338c2f526bb7b1789af3fb0618b7d1d
|
||||
RNReanimated: f1868b36f4b2b52a0ed00062cfda69506f75eaee
|
||||
RNScreens: ffbb0296608eb3560de641a711bbdb663ed1f6b4
|
||||
RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc
|
||||
|
||||
4
apps/web/package-lock.json
generated
4
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.17",
|
||||
"version": "3.3.18",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||
@@ -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<Error | void>({
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ export function DayPicker(props: DayPickerProps) {
|
||||
key={month.month + year}
|
||||
value={month.month}
|
||||
data-date={month.$date.toDateString()}
|
||||
disabled={month.disabled}
|
||||
>
|
||||
{month.month}
|
||||
</option>
|
||||
@@ -121,6 +122,7 @@ export function DayPicker(props: DayPickerProps) {
|
||||
key={year.year}
|
||||
value={year.year}
|
||||
data-date={year.$date.toDateString()}
|
||||
disabled={year.disabled}
|
||||
>
|
||||
{year.year}
|
||||
</option>
|
||||
|
||||
@@ -104,6 +104,7 @@ import ListItem from "../list-item";
|
||||
import { PublishDialog } from "../publish-view";
|
||||
import TimeAgo from "../time-ago";
|
||||
import { NoteExpiryDateDialog } from "../../dialogs/note-expiry-date-dialog";
|
||||
import { withFeatureCheck } from "../../common";
|
||||
|
||||
type NoteProps = NoteResolvedData & {
|
||||
item: NoteType;
|
||||
@@ -665,11 +666,11 @@ export const noteMenuItems: (
|
||||
title: strings.setExpiry(),
|
||||
icon: Destruct.path,
|
||||
premium: !features.expiringNotes.isAllowed,
|
||||
onClick: async () => {
|
||||
onClick: withFeatureCheck(features.expiringNotes, async () => {
|
||||
await NoteExpiryDateDialog.show({
|
||||
noteId: note.id
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
|
||||
@@ -44,7 +44,7 @@ export const AddNotebookDialog = DialogManager.register(
|
||||
|
||||
const onSubmit = useCallback(async () => {
|
||||
if (!title.current.trim())
|
||||
return showToast("error", strings.allFieldsRequired());
|
||||
return showToast("error", strings.titleIsRequired());
|
||||
|
||||
const id = await db.notebooks.add({
|
||||
id: props.notebook?.id,
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2026-05-08 10:43+0500\n"
|
||||
"POT-Creation-Date: 2026-05-11 12:10+0500\n"
|
||||
"POT-Creation-Date: 2026-05-11 12:10+0500\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -3789,6 +3790,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 +4741,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:2677
|
||||
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 +7499,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"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2026-05-08 10:43+0500\n"
|
||||
"POT-Creation-Date: 2026-05-11 12:10+0500\n"
|
||||
"POT-Creation-Date: 2026-05-11 12:10+0500\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -3769,6 +3770,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 +4715,10 @@ msgstr ""
|
||||
msgid "Please grant notifications permission to add new reminders."
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2677
|
||||
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 +7441,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 ""
|
||||
|
||||
@@ -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.`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user