From 95d0969ac9c42be7cd9459ae611197eb96f86fa7 Mon Sep 17 00:00:00 2001 From: 0xZensh Date: Thu, 26 Sep 2024 12:17:27 +0800 Subject: [PATCH] chore: improve ECDH --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- src/ic_message_profile/ic_message_profile.did | 1 + src/ic_message_profile/src/api_admin.rs | 2 +- src/ic_message_profile/src/api_update.rs | 8 ++++++++ src/ic_message_profile/src/store.rs | 2 +- .../ic_message_profile/ic_message_profile.did | 1 + .../ic_message_profile.did.d.ts | 1 + .../ic_message_profile.did.js | 1 + .../src/lib/canisters/messageprofile.ts | 5 +++++ .../components/messages/ChannelDetail.svelte | 3 +-- .../components/messages/ChannelSetting.svelte | 16 +++++++++++++++- .../src/lib/components/messages/Chat.svelte | 2 +- .../messages/UserSelectModel.svelte | 6 ------ .../src/lib/stores/message.ts | 19 +++++++++++++++---- src/ic_panda_frontend/src/lib/utils/auth.ts | 3 +-- 16 files changed, 59 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c87825..875d012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,7 +1791,7 @@ dependencies = [ [[package]] name = "ic_message" -version = "2.2.2" +version = "2.2.3" dependencies = [ "candid", "ciborium", @@ -1811,7 +1811,7 @@ dependencies = [ [[package]] name = "ic_message_channel" -version = "2.2.2" +version = "2.2.3" dependencies = [ "candid", "ciborium", @@ -1826,7 +1826,7 @@ dependencies = [ [[package]] name = "ic_message_profile" -version = "2.2.2" +version = "2.2.3" dependencies = [ "candid", "ciborium", @@ -1841,7 +1841,7 @@ dependencies = [ [[package]] name = "ic_message_types" -version = "2.2.2" +version = "2.2.3" dependencies = [ "candid", "ciborium", @@ -1888,7 +1888,7 @@ dependencies = [ [[package]] name = "ic_panda_luckypool" -version = "2.2.2" +version = "2.2.3" dependencies = [ "base64 0.21.7", "candid", @@ -4069,7 +4069,7 @@ dependencies = [ [[package]] name = "x-auth" -version = "2.2.2" +version = "2.2.3" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 946b7eb..ee1b28a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ opt-level = 's' [workspace.package] edition = "2021" -version = "2.2.2" +version = "2.2.3" repository = "https://github.com/ldclabs/ic-panda" keywords = ["canister", "icp", "panda"] categories = ["web-programming"] diff --git a/src/ic_message_profile/ic_message_profile.did b/src/ic_message_profile/ic_message_profile.did index a9c85a4..4b53ee1 100644 --- a/src/ic_message_profile/ic_message_profile.did +++ b/src/ic_message_profile/ic_message_profile.did @@ -66,6 +66,7 @@ service : (opt ChainArgs) -> { get_profile : (opt principal) -> (Result_2) query; get_state : () -> (Result_3) query; update_profile : (UpdateProfileInput) -> (Result_2); + update_profile_ecdh_pub : (blob) -> (Result); validate_admin_add_managers : (vec principal) -> (Result); validate_admin_remove_managers : (vec principal) -> (Result); } diff --git a/src/ic_message_profile/src/api_admin.rs b/src/ic_message_profile/src/api_admin.rs index 8e29c70..20102db 100644 --- a/src/ic_message_profile/src/api_admin.rs +++ b/src/ic_message_profile/src/api_admin.rs @@ -36,7 +36,7 @@ fn admin_update_profile_ecdh_pub(user: Principal, ecdh_pub: ByteArray<32>) -> Re let caller = ic_cdk::caller(); let now_ms = ic_cdk::api::time() / MILLISECONDS; store::state::is_manager(&caller)?; - store::profile::admin_update_profile_ecdh_pub(user, now_ms, ecdh_pub) + store::profile::update_profile_ecdh_pub(user, now_ms, ecdh_pub) } #[ic_cdk::update] diff --git a/src/ic_message_profile/src/api_update.rs b/src/ic_message_profile/src/api_update.rs index 792210a..324e0de 100644 --- a/src/ic_message_profile/src/api_update.rs +++ b/src/ic_message_profile/src/api_update.rs @@ -1,4 +1,5 @@ use ic_cose_types::MILLISECONDS; +use serde_bytes::ByteArray; use crate::{store, types}; @@ -10,3 +11,10 @@ fn update_profile(input: types::UpdateProfileInput) -> Result) -> Result<(), String> { + let caller = ic_cdk::caller(); + let now_ms = ic_cdk::api::time() / MILLISECONDS; + store::profile::update_profile_ecdh_pub(caller, now_ms, ecdh_pub) +} diff --git a/src/ic_message_profile/src/store.rs b/src/ic_message_profile/src/store.rs index 82a0b32..4f3cb52 100644 --- a/src/ic_message_profile/src/store.rs +++ b/src/ic_message_profile/src/store.rs @@ -233,7 +233,7 @@ pub mod profile { }) } - pub fn admin_update_profile_ecdh_pub( + pub fn update_profile_ecdh_pub( user: Principal, now_ms: u64, ecdh_pub: ByteArray<32>, diff --git a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did index a9c85a4..4b53ee1 100644 --- a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did +++ b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did @@ -66,6 +66,7 @@ service : (opt ChainArgs) -> { get_profile : (opt principal) -> (Result_2) query; get_state : () -> (Result_3) query; update_profile : (UpdateProfileInput) -> (Result_2); + update_profile_ecdh_pub : (blob) -> (Result); validate_admin_add_managers : (vec principal) -> (Result); validate_admin_remove_managers : (vec principal) -> (Result); } diff --git a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.d.ts b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.d.ts index 7ec9339..f1ec229 100644 --- a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.d.ts +++ b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.d.ts @@ -89,6 +89,7 @@ export interface _SERVICE { 'get_profile' : ActorMethod<[[] | [Principal]], Result_2>, 'get_state' : ActorMethod<[], Result_3>, 'update_profile' : ActorMethod<[UpdateProfileInput], Result_2>, + 'update_profile_ecdh_pub' : ActorMethod<[Uint8Array | number[]], Result>, 'validate_admin_add_managers' : ActorMethod<[Array], Result>, 'validate_admin_remove_managers' : ActorMethod<[Array], Result>, } diff --git a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.js b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.js index f52ad50..b98a28d 100644 --- a/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.js +++ b/src/ic_panda_frontend/src/declarations/ic_message_profile/ic_message_profile.did.js @@ -97,6 +97,7 @@ export const idlFactory = ({ IDL }) => { 'get_profile' : IDL.Func([IDL.Opt(IDL.Principal)], [Result_2], ['query']), 'get_state' : IDL.Func([], [Result_3], ['query']), 'update_profile' : IDL.Func([UpdateProfileInput], [Result_2], []), + 'update_profile_ecdh_pub' : IDL.Func([IDL.Vec(IDL.Nat8)], [Result], []), 'validate_admin_add_managers' : IDL.Func( [IDL.Vec(IDL.Principal)], [Result], diff --git a/src/ic_panda_frontend/src/lib/canisters/messageprofile.ts b/src/ic_panda_frontend/src/lib/canisters/messageprofile.ts index 2b5b9c4..dfb1a2c 100644 --- a/src/ic_panda_frontend/src/lib/canisters/messageprofile.ts +++ b/src/ic_panda_frontend/src/lib/canisters/messageprofile.ts @@ -71,4 +71,9 @@ export class ProfileAPI { const res = await this.actor.update_profile(input) return unwrapResult(res, 'call update_profile failed') } + + async update_profile_ecdh_pub(input: Uint8Array): Promise { + const res = await this.actor.update_profile_ecdh_pub(input) + return unwrapResult(res, 'call update_profile_ecdh_pub failed') + } } diff --git a/src/ic_panda_frontend/src/lib/components/messages/ChannelDetail.svelte b/src/ic_panda_frontend/src/lib/components/messages/ChannelDetail.svelte index a0e61c0..5f2d7a6 100644 --- a/src/ic_panda_frontend/src/lib/components/messages/ChannelDetail.svelte +++ b/src/ic_panda_frontend/src/lib/components/messages/ChannelDetail.svelte @@ -20,12 +20,12 @@ export let channelId: string export let myState: MyMessageState + export let myInfo: Readable const toastStore = getToastStore() const { canister, id } = ChannelAPI.parseChannelParam(channelId) const onChatBack = getContext('onChatBack') as () => void - let myInfo: Readable let channelInfo: Readable let openSettings = false @@ -48,7 +48,6 @@ const { abort, finally: onfinally } = toastRun( async (signal: AbortSignal) => { if (canister) { - myInfo = myState.agent.subscribeUser() as Readable channelInfo = await myState.loadChannelInfo(canister, id) openSettings = !$channelInfo._kek return channelInfo diff --git a/src/ic_panda_frontend/src/lib/components/messages/ChannelSetting.svelte b/src/ic_panda_frontend/src/lib/components/messages/ChannelSetting.svelte index 8663f75..d79179d 100644 --- a/src/ic_panda_frontend/src/lib/components/messages/ChannelSetting.svelte +++ b/src/ic_panda_frontend/src/lib/components/messages/ChannelSetting.svelte @@ -11,6 +11,7 @@ import IconEditLine from '$lib/components/icons/IconEditLine.svelte' import IconExchange2Line from '$lib/components/icons/IconExchange2Line.svelte' import { toastRun } from '$lib/stores/toast' + import { errMessage } from '$lib/types/result' import { sleep } from '$lib/utils/helper' import { md } from '$lib/utils/markdown' import { @@ -93,7 +94,20 @@ toastRun(async (signal: AbortSignal) => { if (channelInfo.my_setting.ecdh_remote.length === 1) { - await myState.acceptKEK(channelInfo) + try { + await myState.acceptKEK(channelInfo) + } catch (err: any) { + toastStore.trigger({ + timeout: 10000, + hideDismiss: false, + background: 'variant-soft-error', + message: `Failed to receive the key. A new key has been requested.\n
Error: ${errMessage(err)}` + }) + const my_setting = { ...channelInfo.my_setting } + my_setting.ecdh_remote = [] + my_setting.ecdh_pub = [] + await myState.requestKEK({ ...channelInfo, my_setting }) + } } else { await myState.requestKEK(channelInfo) } diff --git a/src/ic_panda_frontend/src/lib/components/messages/Chat.svelte b/src/ic_panda_frontend/src/lib/components/messages/Chat.svelte index b4043ad..6981372 100644 --- a/src/ic_panda_frontend/src/lib/components/messages/Chat.svelte +++ b/src/ic_panda_frontend/src/lib/components/messages/Chat.svelte @@ -74,7 +74,7 @@ > {#key channelId} {#if channelId && channelId !== 'profile'} - + {:else}
-
- {#if !user.isMember && !user.isManager} - - {/if} -
{/each} diff --git a/src/ic_panda_frontend/src/lib/stores/message.ts b/src/ic_panda_frontend/src/lib/stores/message.ts index 9a4fbca..a1d1beb 100644 --- a/src/ic_panda_frontend/src/lib/stores/message.ts +++ b/src/ic_panda_frontend/src/lib/stores/message.ts @@ -269,7 +269,7 @@ export class MyMessageState { this._mks.push(newMK) await this.agent.setMasterKeys(this._mks.map((k) => k.toInfo())) - await this.initStaticECDHKey() + await this.initStaticECDHKey(mKey) } async fetchECDHCoseEncryptedKey(): Promise { @@ -303,13 +303,22 @@ export class MyMessageState { return AesGcmKey.fromBytes(data) } - async initStaticECDHKey(): Promise { + async initStaticECDHKey(prevMK?: AesGcmKey): Promise { const mk = (await this.mustMasterKey()).toA256GCMKey() const aad = this.principal.toUint8Array() try { - const encrypted0 = await this.loadStaticECDHKey() - const data = await coseA256GCMDecrypt0(mk, encrypted0, aad) + let encrypted0 = await this.loadStaticECDHKey() + const data = await coseA256GCMDecrypt0(prevMK || mk, encrypted0, aad) this._ek = ECDHKey.fromBytes(data) + if (prevMK) { + encrypted0 = await coseA256GCMEncrypt0( + mk, + this._ek.toBytes(), + aad, + mk.kid + ) + await this.saveStaticECDHKey(this._ek.getPublicKey(), encrypted0) + } } catch (err) { this._ek = generateECDHKey() this._ek.setKid(encodeCBOR(String(Date.now()))) @@ -354,6 +363,8 @@ export class MyMessageState { if (this.agent.hasCOSE) { await this.api.update_my_ecdh(ecdh_pub, encrypted0) + } else { + await this.agent.profileAPI.update_profile_ecdh_pub(ecdh_pub) } } diff --git a/src/ic_panda_frontend/src/lib/utils/auth.ts b/src/ic_panda_frontend/src/lib/utils/auth.ts index 72441c1..91fb3e6 100644 --- a/src/ic_panda_frontend/src/lib/utils/auth.ts +++ b/src/ic_panda_frontend/src/lib/utils/auth.ts @@ -4,8 +4,7 @@ import { AuthClient } from '@dfinity/auth-client' export const createAuthClient = (): Promise => AuthClient.create({ idleOptions: { - disableIdle: true, - disableDefaultIdleCallback: true + disableIdle: true } })