Skip to content

Commit

Permalink
chore: improve ECDH
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Sep 26, 2024
1 parent 26b608e commit 95d0969
Show file tree
Hide file tree
Showing 16 changed files with 59 additions and 25 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
1 change: 1 addition & 0 deletions src/ic_message_profile/ic_message_profile.did
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion src/ic_message_profile/src/api_admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
8 changes: 8 additions & 0 deletions src/ic_message_profile/src/api_update.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use ic_cose_types::MILLISECONDS;
use serde_bytes::ByteArray;

use crate::{store, types};

Expand All @@ -10,3 +11,10 @@ fn update_profile(input: types::UpdateProfileInput) -> Result<types::ProfileInfo
let now_ms = ic_cdk::api::time() / MILLISECONDS;
store::profile::update(caller, now_ms, input)
}

#[ic_cdk::update]
fn update_profile_ecdh_pub(ecdh_pub: ByteArray<32>) -> 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)
}
2 changes: 1 addition & 1 deletion src/ic_message_profile/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Principal>], Result>,
'validate_admin_remove_managers' : ActorMethod<[Array<Principal>], Result>,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
5 changes: 5 additions & 0 deletions src/ic_panda_frontend/src/lib/canisters/messageprofile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<null> {
const res = await this.actor.update_profile_ecdh_pub(input)
return unwrapResult(res, 'call update_profile_ecdh_pub failed')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
export let channelId: string
export let myState: MyMessageState
export let myInfo: Readable<UserInfo>
const toastStore = getToastStore()
const { canister, id } = ChannelAPI.parseChannelParam(channelId)
const onChatBack = getContext('onChatBack') as () => void
let myInfo: Readable<UserInfo>
let channelInfo: Readable<ChannelInfoEx>
let openSettings = false
Expand All @@ -48,7 +48,6 @@
const { abort, finally: onfinally } = toastRun(
async (signal: AbortSignal) => {
if (canister) {
myInfo = myState.agent.subscribeUser() as Readable<UserInfo>
channelInfo = await myState.loadChannelInfo(canister, id)
openSettings = !$channelInfo._kek
return channelInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<br />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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
>
{#key channelId}
{#if channelId && channelId !== 'profile'}
<ChannelDetail {channelId} {myState} />
<ChannelDetail {channelId} {myState} {myInfo} />
{:else}
<div class="h-[60px] px-4 py-2 md:hidden">
<button class="btn -ml-6" on:click={onChatBack}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts">
import { type UserInfo } from '$lib/canisters/message'
import IconCheckLine from '$lib/components/icons/IconCheckLine.svelte'
import IconCircleSpin from '$lib/components/icons/IconCircleSpin.svelte'
import IconSubtractLine from '$lib/components/icons/IconSubtractLine.svelte'
import ModalCard from '$lib/components/ui/ModalCard.svelte'
Expand Down Expand Up @@ -225,11 +224,6 @@
{user.name + (user.username ? ' @' + user.username : '')}
</p>
</div>
<div class="">
{#if !user.isMember && !user.isManager}
<span class="text-gray/60 *:size-6"><IconCheckLine /></span>
{/if}
</div>
</button>
{/each}
</div>
Expand Down
19 changes: 15 additions & 4 deletions src/ic_panda_frontend/src/lib/stores/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<AesGcmKey> {
Expand Down Expand Up @@ -303,13 +303,22 @@ export class MyMessageState {
return AesGcmKey.fromBytes(data)
}

async initStaticECDHKey(): Promise<void> {
async initStaticECDHKey(prevMK?: AesGcmKey): Promise<void> {
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())))
Expand Down Expand Up @@ -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)
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/ic_panda_frontend/src/lib/utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { AuthClient } from '@dfinity/auth-client'
export const createAuthClient = (): Promise<AuthClient> =>
AuthClient.create({
idleOptions: {
disableIdle: true,
disableDefaultIdleCallback: true
disableIdle: true
}
})

Expand Down

0 comments on commit 95d0969

Please sign in to comment.