From f9444f25e489ca4bdc101459bb0856677ee43739 Mon Sep 17 00:00:00 2001 From: alenmestrov Date: Sun, 1 Dec 2024 18:30:07 +0100 Subject: [PATCH] feat: resolved mutate ICP encode and decode, query privileges for examplE2 --- .../config/src/client/env/config/mutate.rs | 29 +- .../src/client/env/config/query/privileges.rs | 31 +- .../config/src/client/env/config/types.rs | 1 + .../config/src/client/env/config/types/icp.rs | 444 ++++++++++++++++++ crates/context/config/src/guard.rs | 137 ------ crates/context/config/src/icpTypes.rs | 367 --------------- crates/context/config/src/lib.rs | 2 - 7 files changed, 478 insertions(+), 533 deletions(-) create mode 100644 crates/context/config/src/client/env/config/types/icp.rs delete mode 100644 crates/context/config/src/guard.rs delete mode 100644 crates/context/config/src/icpTypes.rs diff --git a/crates/context/config/src/client/env/config/mutate.rs b/crates/context/config/src/client/env/config/mutate.rs index 6ea964858..08c2d3b4d 100644 --- a/crates/context/config/src/client/env/config/mutate.rs +++ b/crates/context/config/src/client/env/config/mutate.rs @@ -6,6 +6,7 @@ use starknet::core::codec::Encode as StarknetEncode; use starknet::signers::SigningKey as StarknetSigningKey; use starknet_crypto::{poseidon_hash_many, Felt}; +use super::types::icp::{ICPSigned, ICPRequest}; use super::types::starknet::{Request as StarknetRequest, Signed as StarknetSigned}; use crate::client::env::{utils, Method}; use crate::client::protocol::icp::Icp; @@ -13,7 +14,7 @@ use crate::client::protocol::near::Near; use crate::client::protocol::starknet::Starknet; use crate::client::transport::Transport; use crate::client::{CallClient, ClientError, Operation}; -use crate::icpTypes::ICMutate; +// use crate::icpTypes::ICMutate; use crate::repr::{Repr, ReprTransmute}; use crate::types::Signed; use crate::{ContextIdentity, Request, RequestKind}; @@ -135,21 +136,23 @@ impl<'a> Method for Mutate<'a> { const METHOD: &'static str = "mutate"; fn encode(self) -> eyre::Result> { - let signing_key = &self.signing_key; - let nonce = &self.nonce; - let kind = &self.kind; - - let request = ICMutate { - signing_key: *signing_key, - nonce: *nonce, - kind: kind.into(), - }; + let signer_sk = SigningKey::from_bytes(&self.signing_key); + + let request = ICPRequest::new(signer_sk.verifying_key().rt()?, self.kind.into()); + + let signed = ICPSigned::new(request, |b| signer_sk.sign(b))?; - Encode!(&self).map_err(|e| eyre::eyre!(e)) + let encoded = candid::encode_one(&signed)?; + + Ok(encoded) } - fn decode(_response: Vec) -> eyre::Result { - todo!() + fn decode(response: Vec) -> eyre::Result { + if !response.is_empty() { + eyre::bail!("unexpected response {:?}", response); + } + + Ok(()) } } diff --git a/crates/context/config/src/client/env/config/query/privileges.rs b/crates/context/config/src/client/env/config/query/privileges.rs index 161d8f498..671c5e194 100644 --- a/crates/context/config/src/client/env/config/query/privileges.rs +++ b/crates/context/config/src/client/env/config/query/privileges.rs @@ -6,6 +6,7 @@ use serde::Serialize; use starknet::core::codec::{Decode as StarknetDecode, Encode as StarknetEncode, FeltWriter}; use starknet_crypto::Felt; +use crate::client::env::config::types::icp::{ICCapability, ICContextId, ICContextIdentity, ICSignerId}; use crate::client::env::config::types::starknet::{ CallData, ContextId as StarknetContextId, ContextIdentity as StarknetContextIdentity, StarknetPrivileges, @@ -14,10 +15,7 @@ use crate::client::env::Method; use crate::client::protocol::icp::Icp; use crate::client::protocol::near::Near; use crate::client::protocol::starknet::Starknet; -use crate::icpTypes::{ - ICCapability, ICContextId, ICContextIdentity, ICPrivilegesRequest, ICSignerId, -}; -use crate::repr::Repr; +use crate::repr::{Repr, ReprTransmute}; use crate::types::{Capability, ContextId, ContextIdentity, SignerId}; #[derive(Copy, Clone, Debug, Serialize)] @@ -138,22 +136,27 @@ impl<'a> Method for PrivilegesRequest<'a> { const METHOD: &'static str = "privileges"; fn encode(self) -> eyre::Result> { - let context_id: ICContextId = self.context_id.into(); - let identities: ICContextIdentity = self.identities.into(); - let request = ICPrivilegesRequest { - context_id, - identities, - }; - Encode!(&request).map_err(|e| eyre::eyre!(e)) + // Convert context_id and identities to ICP types + let context_id: ICContextId = (*self.context_id).rt()?; + let identities: Vec = self.identities + .iter() + .map(|id| (*id).rt()) + .collect::, _>>()?; + + // Create a tuple of the values we want to encode + let payload = (context_id, identities); + + // Encode using Candid + Encode!(&payload) + .map_err(|e| eyre::eyre!("Failed to encode privileges request: {}", e)) } fn decode(response: Vec) -> eyre::Result { let decoded: BTreeMap> = Decode!(&response, BTreeMap>)?; - let value: Self::Returns = decoded + Ok(decoded .into_iter() .map(|(k, v)| (k.into(), v.into_iter().map(Into::into).collect())) - .collect(); - Ok(value) + .collect()) } } diff --git a/crates/context/config/src/client/env/config/types.rs b/crates/context/config/src/client/env/config/types.rs index a8dc8cd36..aa1efa641 100644 --- a/crates/context/config/src/client/env/config/types.rs +++ b/crates/context/config/src/client/env/config/types.rs @@ -1 +1,2 @@ pub mod starknet; +pub mod icp; \ No newline at end of file diff --git a/crates/context/config/src/client/env/config/types/icp.rs b/crates/context/config/src/client/env/config/types/icp.rs new file mode 100644 index 000000000..c07c0670f --- /dev/null +++ b/crates/context/config/src/client/env/config/types/icp.rs @@ -0,0 +1,444 @@ +use std::borrow::Cow; +use std::marker::PhantomData; + + + +use bs58::decode::Result as Bs58Result; +use crate::repr::{self, LengthMismatch, Repr, ReprBytes, ReprTransmute}; +use crate::RequestKind; +use crate::types::{ + Application, ApplicationMetadata, ApplicationSource, Capability, IntoResult, SignerId, +}; +use candid::CandidType; +use ed25519_dalek::{Verifier, VerifyingKey}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use thiserror::Error as ThisError; +use crate::ContextRequestKind; + +#[derive( + CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, +)] +pub struct Identity([u8; 32]); + +impl ReprBytes for Identity { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0 + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Self::DecodeBytes::from_bytes(f).map(Self) + } +} + +#[derive( + CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, +)] +pub struct ICSignerId(Identity); + +impl ICSignerId { + pub fn new(bytes: [u8; 32]) -> Self { + Self(Identity(bytes)) + } +} + +impl ReprBytes for ICSignerId { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0.as_bytes() + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Identity::from_bytes(f).map(Self) + } +} + +// From implementation for SignerId +impl From for SignerId { + fn from(value: ICSignerId) -> Self { + value.rt().expect("infallible conversion") + } +} + +#[derive( + CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, +)] +pub struct ICContextIdentity(Identity); + +impl ICContextIdentity { + pub fn new(bytes: [u8; 32]) -> Self { + Self(Identity(bytes)) + } +} + +impl ReprBytes for ICContextIdentity { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0 .0 + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Identity::from_bytes(f).map(Self) + } +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)] +pub struct ICContextId(Identity); + +impl ICContextId { + pub fn new(bytes: [u8; 32]) -> Self { + Self(Identity(bytes)) + } + + pub fn as_bytes(&self) -> [u8; 32] { + self.0.as_bytes() + } +} + +impl ReprBytes for ICContextId { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0.as_bytes() + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Identity::from_bytes(f).map(Self) + } +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ICApplicationId(Identity); + +impl ICApplicationId { + pub fn new(bytes: [u8; 32]) -> Self { + Self(Identity(bytes)) + } +} + +impl ReprBytes for ICApplicationId { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0.as_bytes() + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Identity::from_bytes(f).map(Self) + } +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ICBlobId(Identity); + +impl ICBlobId { + pub fn new(bytes: [u8; 32]) -> Self { + Self(Identity(bytes)) + } +} + +impl ReprBytes for ICBlobId { + type EncodeBytes<'a> = [u8; 32]; + type DecodeBytes = [u8; 32]; + type Error = LengthMismatch; + + fn as_bytes(&self) -> Self::EncodeBytes<'_> { + self.0.as_bytes() + } + + fn from_bytes(f: F) -> repr::Result + where + F: FnOnce(&mut Self::DecodeBytes) -> Bs58Result, + { + Identity::from_bytes(f).map(Self) + } +} + +#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ICApplication { + pub id: ICApplicationId, + pub blob: ICBlobId, + pub size: u64, + pub source: String, + pub metadata: Vec, +} + +impl From> for ICApplication { + fn from(value: Application) -> Self { + ICApplication { + id: value.id.rt().expect("infallible conversion"), + blob: value.blob.rt().expect("infallible conversion"), + size: value.size, + source: value.source.0.into_owned(), + metadata: value.metadata.0.into_inner().into_owned(), + } + } +} + +impl<'a> From for Application<'a> { + fn from(value: ICApplication) -> Self { + Application::new( + value.id.rt().expect("infallible conversion"), + value.blob.rt().expect("infallible conversion"), + value.size, + ApplicationSource(Cow::Owned(value.source)), + ApplicationMetadata(Repr::new(Cow::Owned(value.metadata))), + ) + } +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub struct ICPContextRequest { + pub context_id: ICContextId, + pub kind: ICPContextRequestKind, +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum ICCapability { + ManageApplication, + ManageMembers, + Proxy, +} + +// From implementation for Capability +impl From for Capability { + fn from(value: ICCapability) -> Self { + match value { + ICCapability::ManageApplication => Capability::ManageApplication, + ICCapability::ManageMembers => Capability::ManageMembers, + ICCapability::Proxy => Capability::Proxy, + } + } +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub enum ICPContextRequestKind { + Add { + author_id: ICContextIdentity, + application: ICApplication, + }, + UpdateApplication { + application: ICApplication, + }, + AddMembers { + members: Vec, + }, + RemoveMembers { + members: Vec, + }, + Grant { + capabilities: Vec<(ICContextIdentity, ICCapability)>, + }, + Revoke { + capabilities: Vec<(ICContextIdentity, ICCapability)>, + }, + UpdateProxyContract, +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub enum ICPRequestKind { + Context(ICPContextRequest), +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub struct ICPRequest { + pub kind: ICPRequestKind, + pub signer_id: ICSignerId, + pub timestamp_ms: u64, +} + +impl ICPRequest { + pub fn new(signer_id: ICSignerId, kind: ICPRequestKind) -> Self { + Self { + signer_id, + kind, + timestamp_ms: 0, // Default timestamp for tests + } + } +} + +#[derive(Debug, ThisError)] +pub enum ICPSignedError { + #[error("invalid signature")] + InvalidSignature, + #[error("json error: {0}")] + ParseError(#[from] serde_json::Error), + #[error("derivation error: {0}")] + DerivationError(E), + #[error("invalid public key")] + InvalidPublicKey, + #[error("signature error: {0}")] + SignatureError(#[from] ed25519_dalek::ed25519::Error), + #[error("serialization error: {0}")] + SerializationError(String), + #[error("deserialization error: {0}")] + DeserializationError(String), +} + +#[derive(Deserialize, Debug, Clone)] +struct Phantom(#[serde(skip)] std::marker::PhantomData); + +impl CandidType for Phantom { + fn _ty() -> candid::types::Type { + candid::types::TypeInner::Null.into() + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: candid::types::Serializer, + { + serializer.serialize_null(()) + } +} + +#[derive(CandidType, Deserialize, Debug, Clone)] +pub struct ICPSigned { + payload: Vec, + signature: Vec, + _phantom: Phantom, +} + +impl ICPSigned { + pub fn new(payload: T, sign: F) -> Result> + where + R: IntoResult, + F: FnOnce(&[u8]) -> R, + { + let bytes = candid::encode_one(payload) + .map_err(|e| ICPSignedError::SerializationError(e.to_string()))?; + + let signature = sign(&bytes) + .into_result() + .map_err(ICPSignedError::DerivationError)?; + + Ok(Self { + payload: bytes, + signature: signature.to_vec(), + _phantom: Phantom(PhantomData), + }) + } + + pub fn parse(&self, f: F) -> Result> + where + R: IntoResult, + F: FnOnce(&T) -> R, + { + let parsed: T = candid::decode_one(&self.payload) + .map_err(|e| ICPSignedError::DeserializationError(e.to_string()))?; + + let signer_id = f(&parsed) + .into_result() + .map_err(ICPSignedError::DerivationError)?; + + let key = signer_id + .rt::() + .map_err(|_| ICPSignedError::InvalidPublicKey)?; + + let signature_bytes: [u8; 64] = + self.signature.as_slice().try_into().map_err(|_| { + ICPSignedError::SignatureError(ed25519_dalek::ed25519::Error::new()) + })?; + let signature = ed25519_dalek::Signature::from_bytes(&signature_bytes); + + key.verify(&self.payload, &signature) + .map_err(|_| ICPSignedError::InvalidSignature)?; + + Ok(parsed) + } +} + +impl From<&Capability> for ICCapability { + fn from(value: &Capability) -> Self { + match value { + Capability::ManageApplication => ICCapability::ManageApplication, + Capability::ManageMembers => ICCapability::ManageMembers, + Capability::Proxy => ICCapability::Proxy, + } + } +} + +impl From for ICCapability { + fn from(value: Capability) -> Self { + match value { + Capability::ManageApplication => ICCapability::ManageApplication, + Capability::ManageMembers => ICCapability::ManageMembers, + Capability::Proxy => ICCapability::Proxy, + } + } +} + + +impl From> for ICPRequestKind { + fn from(value: RequestKind<'_>) -> Self { + match value { + RequestKind::Context(context_request) => ICPRequestKind::Context(ICPContextRequest { + context_id: context_request.context_id.rt().expect("infallible conversion"), + kind: match context_request.kind { + ContextRequestKind::Add { author_id, application } => ICPContextRequestKind::Add { + author_id: author_id.rt().expect("infallible conversion"), + application: application.into(), + }, + ContextRequestKind::UpdateApplication { application } => ICPContextRequestKind::UpdateApplication { + application: application.into(), + }, + ContextRequestKind::AddMembers { members } => ICPContextRequestKind::AddMembers { + members: members.into_iter() + .map(|m| m.rt().expect("infallible conversion")) + .collect(), + }, + ContextRequestKind::RemoveMembers { members } => ICPContextRequestKind::RemoveMembers { + members: members.into_iter() + .map(|m| m.rt().expect("infallible conversion")) + .collect(), + }, + ContextRequestKind::Grant { capabilities } => ICPContextRequestKind::Grant { + capabilities: capabilities.into_iter() + .map(|(id, cap)| ( + id.rt().expect("infallible conversion"), + cap.into() + )) + .collect(), + }, + ContextRequestKind::Revoke { capabilities } => ICPContextRequestKind::Revoke { + capabilities: capabilities.into_iter() + .map(|(id, cap)| ( + id.rt().expect("infallible conversion"), + cap.into() + )) + .collect(), + }, + ContextRequestKind::UpdateProxyContract => ICPContextRequestKind::UpdateProxyContract, + }, + }), + } + } +} \ No newline at end of file diff --git a/crates/context/config/src/guard.rs b/crates/context/config/src/guard.rs deleted file mode 100644 index 355ea1d0d..000000000 --- a/crates/context/config/src/guard.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::fmt; -use std::ops::{Deref, DerefMut}; - -use candid::CandidType; -use serde::{Deserialize, Serialize}; - -use crate::icpTypes::ICSignerId; -use crate::types::Revision; - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct Guard { - inner: T, - revision: Revision, - privileged: Vec, -} - -#[derive(Debug, Copy, Clone)] -pub struct UnauthorizedAccess { - _priv: (), -} - -impl fmt::Display for UnauthorizedAccess { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("unauthorized access") - } -} - -impl Guard { - pub fn new(creator: ICSignerId, inner: T) -> Self { - Self { - inner, - revision: 0, - privileged: vec![creator], - } - } - - pub fn get( - &mut self, - signer_id: &ICSignerId, - ) -> Result, UnauthorizedAccess> { - if !self.privileged.contains(signer_id) { - return Err(UnauthorizedAccess { _priv: () }); - } - Ok(GuardHandle { inner: self }) - } - - pub fn into_inner(self) -> T { - self.inner - } - - pub fn privileged(&self) -> &[ICSignerId] { - &self.privileged - } - - pub fn privileges(&mut self) -> Privileges<'_> { - Privileges { - inner: &mut self.privileged, - } - } - - pub const fn revision(&self) -> Revision { - self.revision - } -} - -impl Deref for Guard { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -#[derive(Debug)] -pub struct GuardHandle<'a, T> { - inner: &'a mut Guard, -} - -impl<'a, T> GuardHandle<'a, T> { - pub fn get_mut(self) -> GuardMut<'a, T> { - GuardMut { inner: self.inner } - } - - pub fn privileges(&mut self) -> Privileges<'_> { - self.inner.privileges() - } -} - -#[derive(Debug)] -pub struct GuardMut<'a, T> { - inner: &'a mut Guard, -} - -impl GuardMut<'_, T> { - pub fn privileges(&mut self) -> Privileges<'_> { - self.inner.privileges() - } -} - -impl Deref for GuardMut<'_, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.inner - } -} - -impl DerefMut for GuardMut<'_, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner.inner - } -} - -impl Drop for GuardMut<'_, T> { - fn drop(&mut self) { - self.inner.revision = self.inner.revision.wrapping_add(1); - } -} - -#[derive(Debug)] -pub struct Privileges<'a> { - inner: &'a mut Vec, -} - -impl Privileges<'_> { - pub fn grant(&mut self, signer_id: ICSignerId) { - if !self.inner.contains(&signer_id) { - self.inner.push(signer_id); - } - } - - pub fn revoke(&mut self, signer_id: &ICSignerId) { - if let Some(pos) = self.inner.iter().position(|x| x == signer_id) { - self.inner.remove(pos); - } - } -} diff --git a/crates/context/config/src/icpTypes.rs b/crates/context/config/src/icpTypes.rs deleted file mode 100644 index ae84a6b5b..000000000 --- a/crates/context/config/src/icpTypes.rs +++ /dev/null @@ -1,367 +0,0 @@ -use std::borrow::Cow; -use std::collections::HashMap; - -use candid::CandidType; -use ed25519_dalek::{Verifier, VerifyingKey}; -use serde::{Deserialize, Serialize}; - -use crate::guard::Guard; -use crate::repr::{Repr, ReprBytes, ReprTransmute}; -use crate::types::{ - Application, ApplicationId, ApplicationMetadata, ApplicationSource, BlobId, Capability, - ContextId, ContextIdentity, SignerId, -}; - -#[derive( - CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, -)] -pub struct Identity(pub [u8; 32]); - -#[derive( - CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, -)] -pub struct ICSignerId(pub Identity); - -impl ICSignerId { - pub fn new(bytes: [u8; 32]) -> Self { - Self(Identity(bytes)) - } -} - -pub type ICContextIdentity = ICSignerId; - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)] -pub struct ICContextId(pub Identity); - -impl ICContextId { - pub fn new(bytes: [u8; 32]) -> Self { - Self(Identity(bytes)) - } -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct ICApplicationId(pub Identity); - -impl ICApplicationId { - pub fn new(bytes: [u8; 32]) -> Self { - Self(Identity(bytes)) - } -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct ICHasMemberRequest { - pub context_id: ICContextId, - pub identity: ICContextIdentity, -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct ICMembersRequest { - pub context_id: ICContextId, - pub offset: usize, - pub length: usize, -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct ICPrivilegesRequest { - pub context_id: ICContextId, - pub identities: ICContextIdentity, -} - -#[derive(CandidType, Debug)] -pub struct ICMutate { - pub signing_key: [u8; 32], - pub nonce: u64, - pub kind: RequestKind, -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct ICBlobId(pub Identity); - -impl ICBlobId { - pub fn new(bytes: [u8; 32]) -> Self { - Self(Identity(bytes)) - } -} - -// Update the From implementations -impl From for ICSignerId { - fn from(value: SignerId) -> Self { - ICSignerId(Identity(value.as_bytes())) - } -} -impl From for ContextIdentity { - fn from(sign_id: ICSignerId) -> Self { - sign_id.0 .0.rt().expect("Infallible conversion") - } -} - -impl From> for ICSignerId { - fn from(value: Repr) -> Self { - ICSignerId(Identity(value.as_bytes())) - } -} - -impl From for SignerId { - fn from(value: ICSignerId) -> Self { - value.0 .0.rt().expect("Infallible conversion") - } -} - -// Similar From implementations for other types -impl From for ICContextId { - fn from(value: ContextId) -> Self { - ICContextId(Identity(value.as_bytes())) - } -} - -impl From> for ICContextId { - fn from(value: Repr) -> Self { - ICContextId(Identity(value.as_bytes())) - } -} - -impl From for ContextId { - fn from(value: ICContextId) -> Self { - value.0 .0.rt().expect("Infallible conversion") - } -} - -impl From> for ICContextIdentity { - fn from(value: Repr) -> Self { - ICSignerId(Identity(value.as_bytes())) - } -} - -impl From<&[Repr]> for ICContextIdentity { - fn from(value: &[Repr]) -> Self { - let mut bytes = [0; 32]; - bytes.copy_from_slice(&value[0].as_bytes()); - ICSignerId(Identity(bytes)) - } -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct ICApplication { - pub id: ICApplicationId, - pub blob: ICBlobId, - pub size: u64, - pub source: String, - pub metadata: Vec, -} - -// Conversions for ApplicationId -impl From for ICApplicationId { - fn from(value: ApplicationId) -> Self { - ICApplicationId(Identity(value.as_bytes())) - } -} - -impl From> for ICApplicationId { - fn from(value: Repr) -> Self { - ICApplicationId(Identity(value.as_bytes())) - } -} - -impl From for ApplicationId { - fn from(value: ICApplicationId) -> Self { - value.0 .0.rt().expect("Infallible conversion") - } -} - -// Conversions for BlobId -impl From for ICBlobId { - fn from(value: BlobId) -> Self { - ICBlobId(Identity(value.as_bytes())) - } -} - -impl From> for ICBlobId { - fn from(value: Repr) -> Self { - ICBlobId(Identity(value.as_bytes())) - } -} - -impl From for BlobId { - fn from(value: ICBlobId) -> Self { - value.0 .0.rt().expect("Infallible conversion") - } -} - -// Conversions for Application -impl From> for ICApplication { - fn from(value: Application) -> Self { - ICApplication { - id: ICApplicationId(Identity(value.id.as_bytes())), - blob: ICBlobId(Identity(value.blob.as_bytes())), - size: value.size, - source: value.source.0.into_owned(), - metadata: value.metadata.0.into_inner().into_owned().to_vec(), - } - } -} - -impl<'a> From for Application<'a> { - fn from(value: ICApplication) -> Self { - Application::new( - Repr::new(value.id.into()), - Repr::new(value.blob.into()), - value.size, - ApplicationSource(Cow::Owned(value.source)), - ApplicationMetadata(Repr::new(Cow::Owned(value.metadata))), - ) - } -} - -#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] -pub struct ContextRequest { - pub context_id: ICContextId, - pub kind: ContextRequestKind, -} - -#[derive(CandidType, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -pub enum ICCapability { - ManageApplication, - ManageMembers, - Proxy, -} - -#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] -pub enum ContextRequestKind { - Add { - author_id: ICContextIdentity, - application: ICApplication, - }, - UpdateApplication { - application: ICApplication, - }, - AddMembers { - members: Vec, - }, - RemoveMembers { - members: Vec, - }, - Grant { - capabilities: Vec<(ICContextIdentity, ICCapability)>, - }, - Revoke { - capabilities: Vec<(ICContextIdentity, ICCapability)>, - }, - UpdateProxyContract, -} - -#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] -pub enum RequestKind { - Context(ContextRequest), -} - -#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] -pub struct Request { - pub kind: RequestKind, - pub signer_id: ICSignerId, - pub timestamp_ms: u64, -} - -impl Request { - pub fn new(signer_id: ICSignerId, kind: RequestKind) -> Self { - Self { - signer_id, - kind, - timestamp_ms: 0, // Default timestamp for tests - } - } - - #[cfg(not(test))] - pub fn new_with_time(signer_id: ICSignerId, kind: RequestKind) -> Self { - Self { - signer_id, - kind, - timestamp_ms: ic_cdk::api::time(), - } - } - - #[cfg(test)] - pub fn new_with_time(signer_id: ICSignerId, kind: RequestKind, timestamp_ms: u64) -> Self { - Self { - signer_id, - kind, - timestamp_ms, - } - } -} - -#[derive(CandidType, Deserialize, Debug, Clone)] -pub struct ICPSigned { - pub payload: T, - pub signature: Vec, -} - -impl ICPSigned { - pub fn parse(&self, f: F) -> Result<&T, &'static str> - where - F: FnOnce(&T) -> &ICSignerId, - { - // Get the signer's public key from the payload - let signer_id = f(&self.payload); - - // Convert signer_id to VerifyingKey (public key) - let verifying_key = - VerifyingKey::from_bytes(&signer_id.0 .0).map_err(|_| "invalid public key")?; - - // Serialize the payload for verification - let message = - candid::encode_one(&self.payload).map_err(|_| "failed to serialize payload")?; - - // Convert signature bytes to ed25519::Signature - let signature = ed25519_dalek::Signature::from_slice(&self.signature) - .map_err(|_| "invalid signature format")?; - - // Verify the signature - verifying_key - .verify(&message, &signature) - .map_err(|_| "invalid signature")?; - - Ok(&self.payload) - } -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct Context { - pub application: Guard, - pub members: Guard>, - pub proxy: Guard, -} - -pub struct ContextConfigs { - pub contexts: HashMap, - pub next_proxy_id: u64, -} - -impl Default for ContextConfigs { - fn default() -> Self { - Self { - contexts: HashMap::new(), - next_proxy_id: 0, - } - } -} - -// Add these conversions for ICCapability -impl From for ICCapability { - fn from(value: Capability) -> Self { - match value { - Capability::ManageApplication => ICCapability::ManageApplication, - Capability::ManageMembers => ICCapability::ManageMembers, - Capability::Proxy => ICCapability::Proxy, - } - } -} - -impl From for Capability { - fn from(value: ICCapability) -> Self { - match value { - ICCapability::ManageApplication => Capability::ManageApplication, - ICCapability::ManageMembers => Capability::ManageMembers, - ICCapability::Proxy => Capability::Proxy, - } - } -} diff --git a/crates/context/config/src/lib.rs b/crates/context/config/src/lib.rs index 5a65bb3a7..13a4ee500 100644 --- a/crates/context/config/src/lib.rs +++ b/crates/context/config/src/lib.rs @@ -8,8 +8,6 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "client")] pub mod client; -pub mod guard; -pub mod icpTypes; pub mod repr; pub mod types;