mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
mobile: fix backup failed on iOS
This commit is contained in:
committed by
Abdullah Atta
parent
6a2734acff
commit
c8ccd31fe0
2
apps/desktop/package-lock.json
generated
2
apps/desktop/package-lock.json
generated
@@ -6,7 +6,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.1-beta",
|
||||
"version": "3.0.2-beta",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -42,8 +42,11 @@ export const CipherStorage = new MMKVLoader()
|
||||
const IOS_KEYCHAIN_ACCESS_GROUP = "group.org.streetwriters.notesnook";
|
||||
const IOS_KEYCHAIN_SERVICE_NAME = "org.streetwriters.notesnook";
|
||||
const KEYCHAIN_SERVER_DBKEY = "notesnook:db";
|
||||
const NOTESNOOK_APPLOCK_KEY_SALT = "notesnook_applock_key_salt";
|
||||
const NOTESNOOK_DB_KEY_SALT = "notesnook_database_key";
|
||||
|
||||
const NOTESNOOK_APPLOCK_KEY_SALT = "3dqclWbOYllfk9kk";
|
||||
const NOTESNOOK_DB_KEY_SALT = "2rcgSprDmRvZ1AAa";
|
||||
const NOTESNOOK_USER_KEY_SALT = "7qO4qeoM6PbsAJ0Q";
|
||||
|
||||
const DB_KEY_CIPHER = "databaseKeyCipher";
|
||||
const USER_KEY_CIPHER = "userKeyCipher";
|
||||
const APPLOCK_CIPHER = "applockCipher";
|
||||
@@ -167,54 +170,65 @@ export async function getDatabaseKey(appLockPassword) {
|
||||
);
|
||||
DatabaseLogger.info("Getting database key from cipher");
|
||||
DB_KEY = databaseKey;
|
||||
return databaseKey;
|
||||
}
|
||||
|
||||
const hasKey = await Keychain.hasInternetCredentials(KEYCHAIN_SERVER_DBKEY);
|
||||
if (hasKey) {
|
||||
let credentials = await Keychain.getInternetCredentials(
|
||||
if (!DB_KEY) {
|
||||
const hasKey = await Keychain.hasInternetCredentials(
|
||||
KEYCHAIN_SERVER_DBKEY
|
||||
);
|
||||
if (hasKey) {
|
||||
let credentials = await Keychain.getInternetCredentials(
|
||||
KEYCHAIN_SERVER_DBKEY,
|
||||
KEYSTORE_CONFIG
|
||||
);
|
||||
|
||||
DatabaseLogger.info("Getting database key from Keychain");
|
||||
DB_KEY = credentials.password;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DB_KEY) {
|
||||
DatabaseLogger.info("Generating new database key");
|
||||
const password = generatePassword();
|
||||
const derivedDatabaseKey = await Sodium.deriveKey(
|
||||
password,
|
||||
NOTESNOOK_DB_KEY_SALT
|
||||
);
|
||||
|
||||
DB_KEY = derivedDatabaseKey.key;
|
||||
|
||||
await Keychain.setInternetCredentials(
|
||||
KEYCHAIN_SERVER_DBKEY,
|
||||
"notesnook",
|
||||
DB_KEY,
|
||||
KEYSTORE_CONFIG
|
||||
);
|
||||
DatabaseLogger.info("Getting database key from Keychain");
|
||||
DB_KEY = credentials.password;
|
||||
return credentials.password;
|
||||
}
|
||||
DatabaseLogger.info("Generating new database key");
|
||||
const password = generatePassword();
|
||||
const derivedDatabaseKey = await Sodium.deriveKey(
|
||||
password,
|
||||
NOTESNOOK_DB_KEY_SALT
|
||||
);
|
||||
await Keychain.setInternetCredentials(
|
||||
KEYCHAIN_SERVER_DBKEY,
|
||||
"notesnook",
|
||||
derivedDatabaseKey.key,
|
||||
KEYSTORE_CONFIG
|
||||
);
|
||||
|
||||
const userKeyCredentials = await Keychain.getInternetCredentials(
|
||||
"notesnook",
|
||||
KEYSTORE_CONFIG
|
||||
);
|
||||
|
||||
if (userKeyCredentials) {
|
||||
const userKeyCipher = await encrypt(
|
||||
{
|
||||
key: derivedDatabaseKey.key
|
||||
},
|
||||
userKeyCredentials.password
|
||||
if (await Keychain.hasInternetCredentials("notesnook")) {
|
||||
const userKeyCredentials = await Keychain.getInternetCredentials(
|
||||
"notesnook",
|
||||
KEYSTORE_CONFIG
|
||||
);
|
||||
// Store encrypted user key in MMKV
|
||||
MMKV.setMap(USER_KEY_CIPHER, userKeyCipher);
|
||||
await Keychain.resetInternetCredentials("notesnook");
|
||||
|
||||
if (userKeyCredentials) {
|
||||
const userKeyCipher = await encrypt(
|
||||
{
|
||||
key: DB_KEY,
|
||||
salt: NOTESNOOK_USER_KEY_SALT
|
||||
},
|
||||
userKeyCredentials.password
|
||||
);
|
||||
// Store encrypted user key in MMKV
|
||||
MMKV.setMap(USER_KEY_CIPHER, userKeyCipher);
|
||||
await Keychain.resetInternetCredentials("notesnook");
|
||||
}
|
||||
DatabaseLogger.info("Migrated user credentials to cipher storage");
|
||||
}
|
||||
|
||||
DB_KEY = derivedDatabaseKey.key;
|
||||
|
||||
return derivedDatabaseKey.key;
|
||||
return DB_KEY;
|
||||
} catch (e) {
|
||||
console.log(e, "error");
|
||||
DatabaseLogger.error(e);
|
||||
return null;
|
||||
}
|
||||
@@ -225,11 +239,12 @@ export async function deriveCryptoKey(data) {
|
||||
let credentials = await Sodium.deriveKey(data.password, data.salt);
|
||||
const userKeyCipher = await encrypt(
|
||||
{
|
||||
key: await getDatabaseKey()
|
||||
key: await getDatabaseKey(),
|
||||
salt: NOTESNOOK_USER_KEY_SALT
|
||||
},
|
||||
credentials.key
|
||||
);
|
||||
DatabaseLogger.info("User key stored: ", !!userKeyCipher, credentials);
|
||||
DatabaseLogger.info("User key stored: ", !!userKeyCipher);
|
||||
|
||||
// Store encrypted user key in MMKV
|
||||
MMKV.setMap(USER_KEY_CIPHER, userKeyCipher);
|
||||
@@ -259,6 +274,7 @@ export async function getCryptoKey(_name) {
|
||||
|
||||
return key;
|
||||
} catch (e) {
|
||||
console.log("getCryptoKey", e);
|
||||
DatabaseLogger.error(e);
|
||||
}
|
||||
}
|
||||
@@ -301,6 +317,9 @@ export async function decrypt(password, data) {
|
||||
return undefined;
|
||||
let _data = { ...data };
|
||||
_data.output = "plain";
|
||||
|
||||
if (!password.salt) password.salt = data.salt;
|
||||
|
||||
return await Sodium.decrypt(password, _data);
|
||||
}
|
||||
|
||||
@@ -313,6 +332,11 @@ export async function decryptMulti(password, data) {
|
||||
d.output = "plain";
|
||||
return d;
|
||||
});
|
||||
|
||||
if (data.length && !password.salt) {
|
||||
password.salt = data[0].salt;
|
||||
}
|
||||
|
||||
return await Sodium.decryptMulti(password, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ function ReorderableList<T extends { id: string }>({
|
||||
onPress={() => {
|
||||
const _hiddenItems = hiddenItemsState.slice();
|
||||
const index = _hiddenItems.indexOf(info.item.id);
|
||||
|
||||
if (index === -1) {
|
||||
_hiddenItems.push(info.item?.id);
|
||||
} else {
|
||||
|
||||
@@ -96,17 +96,13 @@ export default function Migrate() {
|
||||
});
|
||||
setLoading(true);
|
||||
await sleep(1);
|
||||
const backupSaved = await BackupService.run(false, "local");
|
||||
if (!backupSaved) {
|
||||
ToastManager.show({
|
||||
heading: "Migration failed",
|
||||
message: "You must download a backup of your data before migrating.",
|
||||
context: "local",
|
||||
type: "error"
|
||||
});
|
||||
const { error } = await BackupService.run(false, "local");
|
||||
if (error) {
|
||||
ToastManager.error(error, "Backup failed");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await db.migrations?.migrate();
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
|
||||
@@ -160,6 +160,7 @@ export const SideMenu = React.memo(
|
||||
dragging: false
|
||||
});
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
customStyle={{
|
||||
width: 35,
|
||||
height: 35
|
||||
|
||||
@@ -148,10 +148,18 @@ async function updateNextBackupTime() {
|
||||
lastBackupDate: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} progress
|
||||
* @param {string} context
|
||||
* @returns {Promise<{path?: string, error?: Error}}>
|
||||
*/
|
||||
async function run(progress, context) {
|
||||
let androidBackupDirectory = await checkBackupDirExists(false, context);
|
||||
if (!androidBackupDirectory) return;
|
||||
if (!androidBackupDirectory)
|
||||
return {
|
||||
error: new Error("Backup directory not selected")
|
||||
};
|
||||
|
||||
if (progress) {
|
||||
presentSheet({
|
||||
@@ -216,7 +224,11 @@ async function run(progress, context) {
|
||||
let showBackupCompleteSheet =
|
||||
progress && SettingsService.get().showBackupCompleteSheet;
|
||||
|
||||
if (context) return path;
|
||||
if (context)
|
||||
return {
|
||||
path: path
|
||||
};
|
||||
|
||||
await sleep(300);
|
||||
|
||||
if (showBackupCompleteSheet) {
|
||||
@@ -232,12 +244,17 @@ async function run(progress, context) {
|
||||
context: "global"
|
||||
});
|
||||
|
||||
return path;
|
||||
return {
|
||||
path: path
|
||||
};
|
||||
} catch (e) {
|
||||
ToastManager.error(e, "Backup failed", context || "global");
|
||||
DatabaseLogger.error("Backup failed", e);
|
||||
await sleep(300);
|
||||
progress && eSendEvent(eCloseSheet);
|
||||
ToastManager.error(e, "Backup failed!");
|
||||
return null;
|
||||
return {
|
||||
error: e
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -946,6 +946,6 @@ SPEC CHECKSUMS:
|
||||
toolbar-android: 2a73856e98b750d7e71ce4644d3f41cc98211719
|
||||
Yoga: 1d6727ed193122f6adaf435c3de1a768326ff83b
|
||||
|
||||
PODFILE CHECKSUM: c859ca7e037c52f80a95e3483c6ee99525c62cd9
|
||||
PODFILE CHECKSUM: 2b8b28a341b202bf3ca5f231b75bb05893486ed8
|
||||
|
||||
COCOAPODS: 1.14.2
|
||||
|
||||
798
apps/mobile/package-lock.json
generated
798
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2
apps/theme-builder/package-lock.json
generated
2
apps/theme-builder/package-lock.json
generated
@@ -977,7 +977,7 @@
|
||||
},
|
||||
"../web": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.0.1-beta",
|
||||
"version": "3.0.2-beta",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -191,7 +191,7 @@ const DataMappers: Partial<Record<ItemType, (row: any) => void>> = {
|
||||
(row.key.startsWith("groupOptions") ||
|
||||
row.key.startsWith("toolbarConfig") ||
|
||||
row.key.startsWith("sideBarOrder") ||
|
||||
row.key.startsWith("sideBarHidenItems"))
|
||||
row.key.startsWith("sideBarHiddenItems"))
|
||||
)
|
||||
row.value = JSON.parse(row.value);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user