From c5716718bfa73a9196dabb6e7e7f45b2a5c269a9 Mon Sep 17 00:00:00 2001 From: Shibo Lyu Date: Mon, 28 Apr 2025 00:54:54 +0800 Subject: [PATCH] feat[wip]: Add password change functionality Add method to update ID key pair encoding for password changes and create privacy-security page with password change dialog. --- src/lib/accounts/accountKeyDB.ts | 15 +++++++ src/lib/accounts/index.ts | 3 ++ src/lib/accounts/manager.svelte.ts | 18 ++++++++ src/lib/idURL.ts | 6 +-- src/routes/(app)/settings/SettingsList.svelte | 4 +- .../settings/account/profile/+page.svelte | 16 +++---- .../settings/privacy-security/+page.svelte | 28 ++++++++++++ .../ChangePasswordDialog.svelte | 45 +++++++++++++++++++ 8 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 src/lib/accounts/index.ts create mode 100644 src/routes/(app)/settings/privacy-security/+page.svelte create mode 100644 src/routes/(app)/settings/privacy-security/ChangePasswordDialog.svelte diff --git a/src/lib/accounts/accountKeyDB.ts b/src/lib/accounts/accountKeyDB.ts index eddb6a7..6b47730 100644 --- a/src/lib/accounts/accountKeyDB.ts +++ b/src/lib/accounts/accountKeyDB.ts @@ -76,6 +76,21 @@ class AccountKeyDB { return { idKeyId, encodedIdKeyPair, actKeyPair }; } + async updateEncodedIdKeyPair( + idKeyId: string, + encodedIdKeyPair: EncodedBlahKeyPair + ): Promise { + const tx = this.db.transaction(IDB_OBJECT_STORE_NAME, 'readwrite'); + const currentObject = await tx.store.get(idKeyId); + if (!currentObject) { + await tx.done; + return; + } + currentObject.encodedIdKeyPair = encodedIdKeyPair; + await tx.store.put(currentObject); + await tx.done; + } + async remove(idKeyId: string): Promise { await this.db.delete(IDB_OBJECT_STORE_NAME, idKeyId); } diff --git a/src/lib/accounts/index.ts b/src/lib/accounts/index.ts new file mode 100644 index 0000000..ecdf775 --- /dev/null +++ b/src/lib/accounts/index.ts @@ -0,0 +1,3 @@ +import accountManager from './manager.svelte'; + +export { accountManager }; diff --git a/src/lib/accounts/manager.svelte.ts b/src/lib/accounts/manager.svelte.ts index 714a122..63099e8 100644 --- a/src/lib/accounts/manager.svelte.ts +++ b/src/lib/accounts/manager.svelte.ts @@ -106,6 +106,24 @@ class AccountManager { await this.loadAccounts(); } + async changePassword( + accountOrIdKeyId: Account | string, + oldPassword: string, + newPassword: string + ) { + if (!this.keyDB) throw new Error('Account manager not initialized'); + + const idKeyId = + typeof accountOrIdKeyId === 'string' ? accountOrIdKeyId : accountOrIdKeyId.id_key; + const accountCreds = await this.keyDB.fetchAccount(idKeyId); + const encodedIdKeyPair = accountCreds?.encodedIdKeyPair; + if (!encodedIdKeyPair) throw new Error('No encoded ID key pair found'); + + const idKeyPair = await BlahKeyPair.fromEncoded(encodedIdKeyPair, oldPassword); + const newEncodedIdKeyPair = await idKeyPair.encode(newPassword); + await this.keyDB.updateEncodedIdKeyPair(idKeyId, newEncodedIdKeyPair); + } + async createAccount(profile: BlahProfile, password: string): Promise { if (!this.keyDB) throw new Error('Account manager not initialized'); diff --git a/src/lib/idURL.ts b/src/lib/idURL.ts index 354a9bb..d692c0c 100644 --- a/src/lib/idURL.ts +++ b/src/lib/idURL.ts @@ -1,8 +1,4 @@ -import { - BlahIdentity, - blahIdentityDescriptionSchema, - type BlahIdentityDescription -} from '@blah-im/core/identity'; +import { BlahIdentity, blahIdentityDescriptionSchema } from '@blah-im/core/identity'; export function idURLToUsername(idURL: string): string { const url = new URL(idURL); diff --git a/src/routes/(app)/settings/SettingsList.svelte b/src/routes/(app)/settings/SettingsList.svelte index 85f9da9..ed6c738 100644 --- a/src/routes/(app)/settings/SettingsList.svelte +++ b/src/routes/(app)/settings/SettingsList.svelte @@ -41,7 +41,9 @@ Notifications - Privacy and Security + + Privacy and Security + diff --git a/src/routes/(app)/settings/account/profile/+page.svelte b/src/routes/(app)/settings/account/profile/+page.svelte index 1afdfe3..a7477d5 100644 --- a/src/routes/(app)/settings/account/profile/+page.svelte +++ b/src/routes/(app)/settings/account/profile/+page.svelte @@ -1,12 +1,10 @@ @@ -67,7 +65,7 @@ profile && (profile.bio = doc.textContent)} placeholder="a 25 yo. artist from Paris." diff --git a/src/routes/(app)/settings/privacy-security/+page.svelte b/src/routes/(app)/settings/privacy-security/+page.svelte new file mode 100644 index 0000000..912ff8e --- /dev/null +++ b/src/routes/(app)/settings/privacy-security/+page.svelte @@ -0,0 +1,28 @@ + + + +

Privacy & Security

+
+ + + + (showChangePasswordDialog = true)}> + Change Password + + + + + Backup Account + + + + diff --git a/src/routes/(app)/settings/privacy-security/ChangePasswordDialog.svelte b/src/routes/(app)/settings/privacy-security/ChangePasswordDialog.svelte new file mode 100644 index 0000000..bc72336 --- /dev/null +++ b/src/routes/(app)/settings/privacy-security/ChangePasswordDialog.svelte @@ -0,0 +1,45 @@ + + + + +

Change Password

+ +
+ + +
+

+ On this device, anyone who knows this password have full access to your account. +

+

To change your password, enter your current password first.

+
+ + + + Current Password + + + {#snippet footer()} +

+ Note: password is per device. If you granted other devices full access, you need + to change password on these devices too. +

+ {/snippet} +
+
+