From 4ffa0d551c8c5e01f4a1a9c64f585b7a3f444de2 Mon Sep 17 00:00:00 2001 From: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com> Date: Mon, 27 Jan 2025 11:36:47 +0100 Subject: [PATCH] refactor: cleanup credentials serialization --- polimec-common/common/src/credentials/mod.rs | 56 +++++++------------- polimec-common/test-utils/src/lib.rs | 14 ++--- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/polimec-common/common/src/credentials/mod.rs b/polimec-common/common/src/credentials/mod.rs index 741a91759..179fcc123 100644 --- a/polimec-common/common/src/credentials/mod.rs +++ b/polimec-common/common/src/credentials/mod.rs @@ -19,7 +19,7 @@ use pallet_timestamp::Now; use parity_scale_codec::{Decode, Encode}; use scale_info::{prelude::string::String, TypeInfo}; use serde::{de::Error, ser::SerializeStruct, Serializer}; -use sp_runtime::{traits::BadOrigin, DeserializeOwned, RuntimeDebug}; +use sp_runtime::{traits::BadOrigin, DeserializeOwned}; pub use jwt_compact::{ alg::{Ed25519, VerifyingKey}, @@ -27,9 +27,7 @@ pub use jwt_compact::{ }; use serde::Deserializer; -#[derive( - Clone, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, Deserialize, Serialize, MaxEncodedLen, -)] +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, TypeInfo, Deserialize, Serialize, MaxEncodedLen, RuntimeDebug)] #[serde(rename_all = "lowercase")] pub enum InvestorType { Retail, @@ -54,8 +52,8 @@ parameter_types! { pub const Institutional: InvestorType = InvestorType::Institutional; } -#[derive(Clone, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, Deserialize)] -pub struct SampleClaims { +#[derive(Clone, Encode, Decode, Eq, PartialEq, TypeInfo, Deserialize)] +pub struct PolimecPayload { #[serde(rename = "sub")] pub subject: AccountId, #[serde(rename = "iss")] @@ -75,7 +73,7 @@ impl EnsureOriginWithCredentials for EnsureInvestor where T: frame_system::Config + pallet_timestamp::Config, { - type Claims = SampleClaims; + type Claims = PolimecPayload; type Success = (T::AccountId, Did, InvestorType, Cid); fn try_origin( @@ -86,19 +84,14 @@ where let Some(who) = origin.clone().into_signer() else { return Err(origin) }; let Ok(token) = Self::verify_token(token, verifying_key) else { return Err(origin) }; let claims = token.claims(); - // Get the current timestamp from the pallet_timestamp. It is in milliseconds. + // Get current timestamp from pallet_timestamp (milliseconds) let Ok(now) = Now::::get().try_into() else { return Err(origin) }; let Some(date_time) = claims.expiration else { return Err(origin) }; let timestamp: u64 = date_time.timestamp_millis().try_into().map_err(|_| origin.clone())?; if claims.custom.subject == who && timestamp >= now { - return Ok(( - who, - claims.custom.did.clone(), - claims.custom.investor_type.clone(), - claims.custom.ipfs_cid.clone(), - )); + return Ok((who, claims.custom.did.clone(), claims.custom.investor_type, claims.custom.ipfs_cid.clone())); } Err(origin) @@ -111,7 +104,7 @@ where OuterOrigin: OriginTrait, { type Success; - type Claims: Clone + Encode + Decode + Eq + PartialEq + Ord + PartialOrd + TypeInfo + DeserializeOwned; + type Claims: Clone + Encode + Decode + Eq + PartialEq + TypeInfo + DeserializeOwned; fn try_origin( origin: OuterOrigin, @@ -142,8 +135,8 @@ where D: Deserializer<'de>, { String::deserialize(deserializer) - .map(|string| string.as_bytes().to_vec()) - .and_then(|vec| vec.try_into().map_err(|_| Error::custom("failed to deserialize"))) + .map(|string| string.into_bytes()) + .and_then(|vec| BoundedVec::try_from(vec).map_err(|_| Error::custom("DID exceeds length limit"))) } pub fn from_bounded_cid<'de, D>(deserializer: D) -> Result @@ -151,40 +144,31 @@ where D: Deserializer<'de>, { String::deserialize(deserializer) - .map(|string| string.as_bytes().to_vec()) - .and_then(|vec| vec.try_into().map_err(|_| Error::custom("failed to deserialize"))) + .map(|string| string.into_bytes()) + .and_then(|vec| BoundedVec::try_from(vec).map_err(|_| Error::custom("CID exceeds length limit"))) } -impl Serialize for SampleClaims +// Key corrected serialization implementation +impl Serialize for PolimecPayload where - AccountId: Serialize, // Ensure AccountId can be serialized + AccountId: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { // Define how many fields we are serializing. - let mut state = serializer.serialize_struct("SampleClaims", 5)?; + let mut state = serializer.serialize_struct("PolimecPayload", 5)?; // Serialize each field. // Fields like `subject`, `issuer`, and `investor_type` can be serialized directly. state.serialize_field("sub", &self.subject)?; state.serialize_field("iss", &self.issuer)?; - // For the `ipfs_cid_string` field, you'd use your custom logic to convert it to a string or another format suitable for serialization. - // Assuming `cid` is a `BoundedVec>` and you're encoding it as a UTF-8 string. - let ipfs_cid_bytes: scale_info::prelude::vec::Vec = self.ipfs_cid.clone().into(); // Convert BoundedVec to Vec - let ipfs_cid_string = String::from_utf8_lossy(&ipfs_cid_bytes); // Convert Vec to String - state.serialize_field("aud", &ipfs_cid_string)?; - state.serialize_field("investor_type", &self.investor_type)?; - - // For the `did` field, you'd use your custom logic to convert it to a string or another format suitable for serialization. - // Assuming `did` is a `BoundedVec>` and you're encoding it as a UTF-8 string. - let did_bytes: scale_info::prelude::vec::Vec = self.did.clone().into(); // Convert BoundedVec to Vec - let did_string = String::from_utf8_lossy(&did_bytes); // Convert Vec to String - state.serialize_field("did", &did_string)?; - - // End the serialization + // Serialize the `ipfs_cid` and `did` fields as strings. + state + .serialize_field("aud", core::str::from_utf8(&self.ipfs_cid).map_err(|e| serde::ser::Error::custom(e))?)?; + state.serialize_field("did", core::str::from_utf8(&self.did).map_err(|e| serde::ser::Error::custom(e))?)?; state.end() } } diff --git a/polimec-common/test-utils/src/lib.rs b/polimec-common/test-utils/src/lib.rs index 8be167de7..c3fa9d8be 100644 --- a/polimec-common/test-utils/src/lib.rs +++ b/polimec-common/test-utils/src/lib.rs @@ -21,7 +21,7 @@ use alloc::{vec, vec::Vec}; use frame_support::{sp_runtime::app_crypto::sp_core::bytes::to_hex, traits::ConstU32, BoundedVec, Parameter}; use jwt_compact::{alg::Ed25519, AlgorithmExt, Header}; use parity_scale_codec::alloc::string::ToString; -use polimec_common::credentials::{Did, InvestorType, SampleClaims, UntrustedToken}; +use polimec_common::credentials::{Did, InvestorType, PolimecPayload, UntrustedToken}; use xcm::{ opaque::{v4::Xcm, VersionedXcm}, v4::{Assets, Location, SendError, SendResult, SendXcm, XcmHash}, @@ -83,7 +83,7 @@ mod jwt_utils { // Handle optional IPFS CID let ipfs_cid = ipfs_cid.unwrap_or_else(|| BoundedVec::with_bounded_capacity(96)); let custom_claims = - SampleClaims { subject: account_id, investor_type, issuer: "verifier".to_string(), did, ipfs_cid }; + PolimecPayload { subject: account_id, investor_type, issuer: "verifier".to_string(), did, ipfs_cid }; let mut claims = Claims::new(custom_claims); claims.expiration = Some(Utc.with_ymd_and_hms(2030, 1, 1, 0, 0, 0).unwrap()); @@ -92,7 +92,7 @@ mod jwt_utils { UntrustedToken::new(&token_string).expect("Failed to parse the JWT") } - // The `Serialize` trait is needed to serialize the `account_id` into a `SampleClaims` struct. + // The `Serialize` trait is needed to serialize the `account_id` into a `PolimecPayload` struct. pub fn get_mock_jwt( account_id: AccountId, investor_type: InvestorType, @@ -101,7 +101,7 @@ mod jwt_utils { create_jwt(account_id, investor_type, did, None) } - // The `Serialize` trait is needed to serialize the `account_id` into a `SampleClaims` struct. + // The `Serialize` trait is needed to serialize the `account_id` into a `PolimecPayload` struct. pub fn get_mock_jwt_with_cid( account_id: AccountId, investor_type: InvestorType, @@ -189,7 +189,7 @@ mod tests { alg::{Ed25519, VerifyingKey}, AlgorithmExt, }; - use polimec_common::credentials::{InvestorType, SampleClaims}; + use polimec_common::credentials::{InvestorType, PolimecPayload}; #[test] fn test_get_test_jwt() { @@ -202,7 +202,7 @@ mod tests { ) .unwrap(); let token = get_mock_jwt("0x1234", InvestorType::Institutional, generate_did_from_account(40u64)); - let res = Ed25519.validator::>(&verifying_key).validate(&token); + let res = Ed25519.validator::>(&verifying_key).validate(&token); assert!(res.is_ok()); } @@ -224,7 +224,7 @@ mod tests { generate_did_from_account(40u64), bounded_cid.clone(), ); - let res = Ed25519.validator::>(&verifying_key).validate(&token); + let res = Ed25519.validator::>(&verifying_key).validate(&token); assert!(res.is_ok()); let validated_token = res.unwrap(); let claims = validated_token.claims();