From 6e8610c35801a6952875b09e2456c6e7d33e1843 Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Mon, 23 Dec 2024 13:35:36 +0500 Subject: [PATCH] core: compute `usesFallbackPWHash` instead of storing it this fixes the fallback logic for already logged in users --- packages/core/src/api/user-manager.ts | 36 +++++++++++++++++++-------- packages/core/src/database/kv.ts | 4 +-- packages/core/src/interfaces.ts | 4 +++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/packages/core/src/api/user-manager.ts b/packages/core/src/api/user-manager.ts index 2384ea033..b55736053 100644 --- a/packages/core/src/api/user-manager.ts +++ b/packages/core/src/api/user-manager.ts @@ -190,7 +190,6 @@ class UserManager { salt: user.salt }); } - await this.db.kv().write("usesFallbackPWHash", usesFallback); EV.publish(EVENTS.userLoggedIn, user); } catch (e) { await this.tokenManager.saveToken(token); @@ -333,7 +332,7 @@ class UserManager { `${constants.API_HOST}${ENDPOINTS.deleteUser}`, { password: await this.db.storage().hash(password, user.email, { - usesFallback: await this.db.kv().read("usesFallbackPWHash") + usesFallback: await this.usesFallbackPWHash(password) }) }, token @@ -485,17 +484,12 @@ class UserManager { type: "change_email", new_email: newEmail, password: await this.db.storage().hash(password, email, { - usesFallback: await this.db.kv().read("usesFallbackPWHash") + usesFallback: await this.usesFallbackPWHash(password) }), verification_code: code }, token ); - - await this.db.storage().deriveCryptoKey({ - password, - salt: user.salt - }); } recoverAccount(email: string) { @@ -566,7 +560,7 @@ class UserManager { if (old_password) old_password = await this.db.storage().hash(old_password, email, { - usesFallback: await this.db.kv().read("usesFallbackPWHash") + usesFallback: await this.usesFallbackPWHash(old_password) }); if (new_password) new_password = await this.db.storage().hash(new_password, email); @@ -580,10 +574,32 @@ class UserManager { }, token ); - await this.db.kv().write("usesFallbackPWHash", false); return true; } + + private async usesFallbackPWHash(password: string) { + const user = await this.getUser(); + const encryptionKey = await this.getEncryptionKey(); + if (!user || !encryptionKey) return false; + const fallbackCryptoKey = await this.db + .storage() + .generateCryptoKeyFallback(password, user.salt); + const cryptoKey = await this.db + .storage() + .generateCryptoKey(password, user.salt); + + if (!encryptionKey.key || !fallbackCryptoKey.key || !cryptoKey.key) + throw new Error("Failed to generate crypto keys."); + + if ( + fallbackCryptoKey.key !== encryptionKey.key && + cryptoKey.key !== encryptionKey.key + ) + throw new Error("Wrong password."); + + return fallbackCryptoKey.key === encryptionKey.key; + } } export default UserManager; diff --git a/packages/core/src/database/kv.ts b/packages/core/src/database/kv.ts index e09ab7346..7d9266d23 100644 --- a/packages/core/src/database/kv.ts +++ b/packages/core/src/database/kv.ts @@ -30,7 +30,6 @@ interface KV { deviceId: string; lastBackupTime: number; fullOfflineMode: boolean; - usesFallbackPWHash: boolean; } export const KEYS: (keyof KV)[] = [ @@ -41,8 +40,7 @@ export const KEYS: (keyof KV)[] = [ "monographs", "deviceId", "lastBackupTime", - "fullOfflineMode", - "usesFallbackPWHash" + "fullOfflineMode" ]; export class KVStorage { diff --git a/packages/core/src/interfaces.ts b/packages/core/src/interfaces.ts index f176f559c..177e2aa42 100644 --- a/packages/core/src/interfaces.ts +++ b/packages/core/src/interfaces.ts @@ -66,6 +66,10 @@ export interface IStorage { getCryptoKey(): Promise; generateCryptoKey(password: string, salt?: string): Promise; + generateCryptoKeyFallback( + password: string, + salt?: string + ): Promise; deriveCryptoKeyFallback(credentials: SerializedKey): Promise; // async generateRandomKey() {