ockam_identity/models/
credential_and_purpose_key.rs1use minicbor::{CborLen, Decode, Encode};
2use ockam_core::compat::string::String;
3use ockam_core::compat::vec::Vec;
4use ockam_core::errcode::{Kind, Origin};
5use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Error, Message, Result};
6
7use crate::alloc::string::ToString;
8use crate::models::{Credential, CredentialData, PurposeKeyAttestation};
9use crate::TimestampInSeconds;
10
11#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, CborLen, Message)]
14#[rustfmt::skip]
15pub struct CredentialAndPurposeKey {
16 #[n(0)] pub credential: Credential,
18 #[n(1)] pub purpose_key_attestation: PurposeKeyAttestation,
21}
22
23impl Encodable for CredentialAndPurposeKey {
24 fn encode(self) -> Result<Encoded> {
25 cbor_encode_preallocate(self)
26 }
27}
28
29impl Decodable for CredentialAndPurposeKey {
30 fn decode(e: &[u8]) -> Result<Self> {
31 Ok(minicbor::decode(e)?)
32 }
33}
34
35impl CredentialAndPurposeKey {
36 pub fn encode_as_string(&self) -> Result<String> {
38 Ok(hex::encode(self.encode_as_cbor_bytes()?))
39 }
40
41 pub fn encode_as_cbor_bytes(&self) -> Result<Vec<u8>> {
43 cbor_encode_preallocate(self)
44 }
45
46 pub fn decode_from_cbor_bytes(bytes: &[u8]) -> Result<CredentialAndPurposeKey> {
48 Ok(minicbor::decode(bytes)?)
49 }
50
51 pub fn decode_from_string(as_hex: &str) -> Result<CredentialAndPurposeKey> {
53 let hex_decoded = hex::decode(as_hex.as_bytes())
54 .map_err(|e| Error::new(Origin::Api, Kind::Serialization, e.to_string()))?;
55 Self::decode_from_cbor_bytes(&hex_decoded)
56 }
57
58 pub fn get_credential_data(&self) -> Result<CredentialData> {
60 self.credential.get_credential_data()
61 }
62
63 pub fn get_expires_at(&self) -> Result<TimestampInSeconds> {
65 Ok(self.get_credential_data()?.expires_at)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use std::time::Duration;
72
73 use crate::identities;
74 use crate::models::CredentialSchemaIdentifier;
75 use crate::utils::AttributesBuilder;
76
77 use super::*;
78
79 #[tokio::test]
80 async fn test_encode_decode_as_bytes() -> Result<()> {
81 let credential = create_credential().await?;
82 let decoded = CredentialAndPurposeKey::decode_from_cbor_bytes(
83 &credential.encode_as_cbor_bytes().unwrap(),
84 );
85 assert!(decoded.is_ok());
86 assert_eq!(decoded.unwrap(), credential);
87
88 Ok(())
89 }
90
91 #[tokio::test]
92 async fn test_encode_decode_as_string() -> Result<()> {
93 let credential = create_credential().await?;
94 let decoded =
95 CredentialAndPurposeKey::decode_from_string(&credential.encode_as_string().unwrap());
96 assert!(decoded.is_ok());
97 assert_eq!(decoded.unwrap(), credential);
98
99 Ok(())
100 }
101
102 async fn create_credential() -> Result<CredentialAndPurposeKey> {
104 let identities = identities().await?;
105 let issuer = identities.identities_creation().create_identity().await?;
106 let subject = identities.identities_creation().create_identity().await?;
107
108 let attributes = AttributesBuilder::with_schema(CredentialSchemaIdentifier(1))
109 .with_attribute("name".as_bytes().to_vec(), b"value".to_vec())
110 .build();
111
112 identities
113 .credentials()
114 .credentials_creation()
115 .issue_credential(&issuer, &subject, attributes, Duration::from_secs(1))
116 .await
117 }
118}