From e63a4db4f01b55592544657f1b9c44befd8c3e42 Mon Sep 17 00:00:00 2001 From: Andrej Krakau Date: Thu, 1 Apr 2021 15:16:22 +0200 Subject: [PATCH] Add to_message on envelopes & clean up --- identity-comm/src/envelope/plaintext.rs | 16 +-- identity-comm/src/envelope/signed.rs | 40 ++++-- identity-comm/src/error.rs | 20 +-- identity-comm/src/lib.rs | 2 - identity-comm/src/message/authentication.rs | 4 - identity-comm/src/message/builder.rs | 96 ------------- identity-comm/src/message/discovery.rs | 55 +++---- identity-comm/src/message/message.rs | 47 ++---- identity-comm/src/message/mod.rs | 9 +- identity-comm/src/message/resolution.rs | 19 ++- identity-comm/src/message/timing.rs | 152 ++++++++++---------- identity-comm/src/message/trustping.rs | 41 +++--- identity-comm/src/utils/timestamp.rs | 6 +- 13 files changed, 198 insertions(+), 309 deletions(-) delete mode 100644 identity-comm/src/message/builder.rs diff --git a/identity-comm/src/envelope/plaintext.rs b/identity-comm/src/envelope/plaintext.rs index aba832c544..c1e205302d 100644 --- a/identity-comm/src/envelope/plaintext.rs +++ b/identity-comm/src/envelope/plaintext.rs @@ -1,11 +1,11 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use crate::envelope::EnvelopeExt; +use crate::error::Result; use identity_core::convert::ToJson as _; -use serde::Serialize; use serde::Deserialize; - -use crate::{envelope::EnvelopeExt, error::Result, error::Error}; +use serde::Serialize; /// A DIDComm Plaintext Message /// @@ -21,12 +21,12 @@ impl Envelope { pub fn from_message(message: &T) -> Result { message.to_json().map_err(Into::into).map(Self) } - pub fn to_message<'a, T>(&'a self) -> Result - where - T: Deserialize<'a> { - serde_json::from_str(&self.0).map_err(Error::from) + pub fn to_message(&self) -> Result + where + for<'a> T: Deserialize<'a>, + { + serde_json::from_str(&self.0).map_err(Into::into) } - } impl EnvelopeExt for Envelope { diff --git a/identity-comm/src/envelope/signed.rs b/identity-comm/src/envelope/signed.rs index 5a1dbc9090..7d0336f2f1 100644 --- a/identity-comm/src/envelope/signed.rs +++ b/identity-comm/src/envelope/signed.rs @@ -1,19 +1,20 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_core::{crypto::KeyPair, utils::encode_b58}; -use libjose::{ - jose::JoseTokenType, - jws::{Encoder, JwsAlgorithm, JwsFormat, JwsHeader,Decoder}, -}; -use serde::Serialize; +use crate::envelope::EnvelopeExt; +use crate::envelope::Plaintext; +use crate::error::Result; +use identity_core::crypto::KeyPair; +use identity_core::crypto::PublicKey; +use identity_core::utils::encode_b58; +use libjose::jose::JoseTokenType; +use libjose::jws::Decoder; +use libjose::jws::Encoder; +use libjose::jws::JwsAlgorithm; +use libjose::jws::JwsFormat; +use libjose::jws::JwsHeader; use serde::Deserialize; - - -use crate::{ - envelope::{EnvelopeExt, Plaintext}, - error::Result, -}; +use serde::Serialize; /// Supported digital signature algorithms /// @@ -65,9 +66,18 @@ impl Envelope { .map_err(Into::into) .map(Self) } - pub fn to_message<'a, T>(&'a self, algorithm: Algorithm, keypair: &KeyPair) -> Result - where T: Deserialize<'a> { - Decoder::new(keypair.public().as_bytes()).format(JwsFormat::Compact).algorithm(algorithm).decode(self.as_bytes()).map_err(Into::into) + + pub fn to_message(&self, algorithm: Algorithm, public: &PublicKey) -> Result + where + for<'a> T: Deserialize<'a>, + { + let token = Decoder::new(public.as_ref()) + .key_id(encode_b58(public)) + .format(JwsFormat::Compact) + .algorithm(algorithm.into()) + .decode(self.as_bytes())?; + + serde_json::from_slice(&token.claims.to_vec()).map_err(Into::into) } } diff --git a/identity-comm/src/error.rs b/identity-comm/src/error.rs index 509bbd33d7..3810bc726c 100644 --- a/identity-comm/src/error.rs +++ b/identity-comm/src/error.rs @@ -5,14 +5,14 @@ pub type Result = core::result::Result; #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("IOTA Error: {0}")] - IotaError(#[from] identity_iota::error::Error), - #[error("IOTA Core Error: {0}")] - CoreError(#[from] identity_core::error::Error), - #[error("JOSE Error: {0}")] - JoseError(#[from] libjose::error::Error), - #[error("DID Document Error: {0}")] - DocumentError(#[from] did_doc::Error), - #[error("JSON Error: {0}")] - JsonError(#[from] serde_json::error::Error) + #[error("IOTA Error: {0}")] + IotaError(#[from] identity_iota::error::Error), + #[error("IOTA Core Error: {0}")] + CoreError(#[from] identity_core::error::Error), + #[error("JOSE Error: {0}")] + JoseError(#[from] libjose::error::Error), + #[error("DID Document Error: {0}")] + DocumentError(#[from] did_doc::Error), + #[error("JSON Error: {0}")] + JsonError(#[from] serde_json::error::Error), } diff --git a/identity-comm/src/lib.rs b/identity-comm/src/lib.rs index 7c782f0c93..f99eeec445 100644 --- a/identity-comm/src/lib.rs +++ b/identity-comm/src/lib.rs @@ -8,5 +8,3 @@ pub mod envelope; pub mod error; pub mod message; pub mod utils; - - diff --git a/identity-comm/src/message/authentication.rs b/identity-comm/src/message/authentication.rs index 0ae641bcfa..e831462b6f 100644 --- a/identity-comm/src/message/authentication.rs +++ b/identity-comm/src/message/authentication.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use crate::message::Timing; -use crate::message::Message; use did_doc::{url::Url, Signature}; use identity_iota::did::DID; use serde::Serialize; @@ -146,6 +145,3 @@ impl AuthenticationResponse { self.signature = signature; } } - -impl Message for AuthenticationRequest {} -impl Message for AuthenticationResponse {} diff --git a/identity-comm/src/message/builder.rs b/identity-comm/src/message/builder.rs deleted file mode 100644 index cfc0b04026..0000000000 --- a/identity-comm/src/message/builder.rs +++ /dev/null @@ -1,96 +0,0 @@ -// // Copyright 2020-2021 IOTA Stiftung -// // SPDX-License-Identifier: Apache-2.0 - -// use did_doc::{url::Url, Document, Signature}; -// use identity_iota::did::DID; - -// use crate::{error::Result, message::Message, message::Timing}; - - -// /// A `MessageBuilder` is used to generated a customized `Message`. -// #[derive(Debug)] -// pub struct MessageBuilder { -// pub(crate) callback_url: Option, -// pub(crate) response_requested: Option, -// pub(crate) context: Option, -// pub(crate) id: Option, -// pub(crate) did_document: Option, -// pub(crate) thread: Option, -// pub(crate) challenge: Option, -// pub(crate) signature: Option, -// pub(crate) timing: Option, -// } - - - -// impl MessageBuilder { -// /// Creates a new `MessageBuilder`. -// pub fn new() -> Self { -// Self { -// callback_url: None, -// response_requested: None, -// context: None, -// id: None, -// did_document: None, -// thread: None, -// challenge: None, -// signature: None, -// timing: None, -// } -// } - - - -// /// Sets the `id` value of the generated `Message`. -// #[must_use] -// pub fn id(mut self, value: impl Into) -> Self { -// self.id = value.into(); -// self -// } - -// /// Sets the `type` value of the generated `Message`. -// #[must_use] -// pub fn type_(mut self, value: impl Into) -> Self { -// self.type_ = Some(value.into()); -// self -// } - -// /// Sets the `from` value of the generated `Message`. -// #[must_use] -// pub fn from(mut self, value: DID) -> Self { -// self.from = Some(value); -// self -// } - -// /// Adds a value to the list of recipients for the generated `Message`. -// #[must_use] -// pub fn to(mut self, value: DID) -> Self { -// self.to.push(value); -// self -// } - -// /// Sets the `created_time` value of the generated `Message`. -// #[must_use] -// pub fn created_time(mut self, value: impl Into) -> Self { -// self.created_time = Some(value.into()); -// self -// } - -// /// Sets the `expires_time` value of the generated `Message`. -// #[must_use] -// pub fn expires_time(mut self, value: impl Into) -> Self { -// self.expires_time = Some(value.into()); -// self -// } - -// /// Returns a new `Message` based on the `MessageBuilder` configuration. -// pub fn build(self) -> Result { -// Message::from_builder(self) -// } -// } - -// impl Default for MessageBuilder { -// fn default() -> Self { -// Self::new() -// } -// } diff --git a/identity-comm/src/message/discovery.rs b/identity-comm/src/message/discovery.rs index fb29afaa8e..a2c17ee430 100644 --- a/identity-comm/src/message/discovery.rs +++ b/identity-comm/src/message/discovery.rs @@ -1,5 +1,7 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use crate::message::Timing; -use crate::message::Message; use did_doc::url::Url; use identity_iota::did::DID; @@ -15,31 +17,7 @@ pub struct DidRequest { #[serde(skip_serializing_if = "Option::is_none")] timing: Option, } -#[derive(Debug, Deserialize, Serialize)] -pub struct DidResponse { - id: DID, -} -impl DidResponse { - pub fn new(id: DID) -> Self { - Self { id } - } - - /// Get a mutable reference to the did response's id. - pub fn id_mut(&mut self) -> &mut DID { - &mut self.id - } - - /// Get a reference to the did response's id. - pub fn id(&self) -> &DID { - &self.id - } - - /// Set the did response's id. - pub fn set_id(&mut self, id: DID) { - self.id = id; - } -} impl DidRequest { pub fn new(callback_url: Url) -> Self { Self { @@ -127,5 +105,28 @@ impl DidRequest { } } -impl Message for DidRequest {} -impl Message for DidResponse {} +#[derive(Debug, Deserialize, Serialize)] +pub struct DidResponse { + id: DID, +} + +impl DidResponse { + pub fn new(id: DID) -> Self { + Self { id } + } + + /// Get a mutable reference to the did response's id. + pub fn id_mut(&mut self) -> &mut DID { + &mut self.id + } + + /// Get a reference to the did response's id. + pub fn id(&self) -> &DID { + &self.id + } + + /// Set the did response's id. + pub fn set_id(&mut self, id: DID) { + self.id = id; + } +} diff --git a/identity-comm/src/message/message.rs b/identity-comm/src/message/message.rs index 54e997915d..38e16b7ca0 100644 --- a/identity-comm/src/message/message.rs +++ b/identity-comm/src/message/message.rs @@ -1,43 +1,16 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 - -use did_doc::{url::Url, Document, Signature}; - -use identity_core::crypto::{KeyPair, PublicKey}; -use identity_iota::did::DID; +use crate::envelope::Encrypted; +use crate::envelope::EncryptionAlgorithm; +use crate::envelope::Plaintext; +use crate::envelope::SignatureAlgorithm; +use crate::envelope::Signed; +use crate::error::Result; +use identity_core::crypto::KeyPair; +use identity_core::crypto::PublicKey; use serde::Serialize; -use crate::{ - envelope::{Encrypted, EncryptionAlgorithm, Plaintext, SignatureAlgorithm, Signed}, - error::Result, - message::Timing -}; - -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct CustomMessage { - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) callback_url: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) response_requested: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) context: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) did_document: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) thread: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) challenge: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) signature: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub(super) timing: Option, -} -pub trait Message: Serialize {} - - -pub trait AsEnvelope { +pub trait Message { fn pack_plain(&self) -> Result; fn pack_auth(&self, algorithm: EncryptionAlgorithm, recipients: &[PublicKey], sender: &KeyPair) -> Result<Encrypted>; fn pack_auth_non_repudiable( @@ -51,7 +24,7 @@ pub trait AsEnvelope { fn pack_non_repudiable(&self, algorithm: SignatureAlgorithm, sender: &KeyPair) -> Result<Signed>; } -impl<T: Serialize> AsEnvelope for T { +impl<T: Serialize> Message for T { fn pack_plain(&self) -> Result<Plaintext> { Plaintext::from_message(self) } diff --git a/identity-comm/src/message/mod.rs b/identity-comm/src/message/mod.rs index 2eb3f29285..4c208fe03b 100644 --- a/identity-comm/src/message/mod.rs +++ b/identity-comm/src/message/mod.rs @@ -2,12 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::module_inception)] -mod builder; +mod authentication; +mod discovery; mod message; +mod resolution; mod timing; mod trustping; -mod discovery; -mod resolution; -mod authentication; -pub use self::{builder::*, message::*,timing::*,trustping::*,discovery::*,resolution::*,authentication::*}; +pub use self::{authentication::*, discovery::*, message::*, resolution::*, timing::*, trustping::*}; diff --git a/identity-comm/src/message/resolution.rs b/identity-comm/src/message/resolution.rs index e6e10bc0a4..53e783ebbd 100644 --- a/identity-comm/src/message/resolution.rs +++ b/identity-comm/src/message/resolution.rs @@ -1,5 +1,7 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + use crate::message::Timing; -use crate::message::Message; use did_doc::{url::Url, Document}; use identity_iota::did::DID; @@ -86,7 +88,7 @@ impl ResolutionRequest { } #[derive(Debug, Deserialize, Serialize)] -pub struct ResolutionResult { +pub struct ResolutionResponse { did_document: Document, #[serde(skip_serializing_if = "Option::is_none")] id: Option<DID>, @@ -96,13 +98,13 @@ pub struct ResolutionResult { timing: Option<Timing>, } -impl ResolutionResult { - pub fn new(did_document: Document, ) -> Self { +impl ResolutionResponse { + pub fn new(did_document: Document) -> Self { Self { did_document, - id:None, - thread:None, - timing:None, + id: None, + thread: None, + timing: None, } } @@ -166,6 +168,3 @@ impl ResolutionResult { self.timing = timing; } } - -impl Message for ResolutionRequest {} -impl Message for ResolutionResult {} diff --git a/identity-comm/src/message/timing.rs b/identity-comm/src/message/timing.rs index c7e97ffc14..737a861d12 100644 --- a/identity-comm/src/message/timing.rs +++ b/identity-comm/src/message/timing.rs @@ -22,102 +22,102 @@ pub struct Timing { impl Timing { pub fn new() -> Self { Self { - out_time:None, - in_time:None, - stale_time:None, - expires_time:None, + out_time: None, + in_time: None, + stale_time: None, + expires_time: None, delay_milli: None, wait_until_time: None, } } - /// Get a mutable reference to the timing's out time. - pub fn out_time_mut(&mut self) -> &mut Option<Timestamp> { - &mut self.out_time - } + /// Get a mutable reference to the timing's out time. + pub fn out_time_mut(&mut self) -> &mut Option<Timestamp> { + &mut self.out_time + } - /// Get a reference to the timing's out time. - pub fn out_time(&self) -> &Option<Timestamp> { - &self.out_time - } + /// Get a reference to the timing's out time. + pub fn out_time(&self) -> &Option<Timestamp> { + &self.out_time + } - /// Set the timing's out time. - pub fn set_out_time(&mut self, out_time: Option<Timestamp>) { - self.out_time = out_time; - } + /// Set the timing's out time. + pub fn set_out_time(&mut self, out_time: Option<Timestamp>) { + self.out_time = out_time; + } - /// Get a mutable reference to the timing's in time. - pub fn in_time_mut(&mut self) -> &mut Option<Timestamp> { - &mut self.in_time - } + /// Get a mutable reference to the timing's in time. + pub fn in_time_mut(&mut self) -> &mut Option<Timestamp> { + &mut self.in_time + } - /// Get a reference to the timing's in time. - pub fn in_time(&self) -> &Option<Timestamp> { - &self.in_time - } + /// Get a reference to the timing's in time. + pub fn in_time(&self) -> &Option<Timestamp> { + &self.in_time + } - /// Set the timing's in time. - pub fn set_in_time(&mut self, in_time: Option<Timestamp>) { - self.in_time = in_time; - } + /// Set the timing's in time. + pub fn set_in_time(&mut self, in_time: Option<Timestamp>) { + self.in_time = in_time; + } - /// Get a mutable reference to the timing's stale time. - pub fn stale_time_mut(&mut self) -> &mut Option<Timestamp> { - &mut self.stale_time - } + /// Get a mutable reference to the timing's stale time. + pub fn stale_time_mut(&mut self) -> &mut Option<Timestamp> { + &mut self.stale_time + } - /// Get a reference to the timing's stale time. - pub fn stale_time(&self) -> &Option<Timestamp> { - &self.stale_time - } + /// Get a reference to the timing's stale time. + pub fn stale_time(&self) -> &Option<Timestamp> { + &self.stale_time + } - /// Set the timing's stale time. - pub fn set_stale_time(&mut self, stale_time: Option<Timestamp>) { - self.stale_time = stale_time; - } + /// Set the timing's stale time. + pub fn set_stale_time(&mut self, stale_time: Option<Timestamp>) { + self.stale_time = stale_time; + } - /// Get a mutable reference to the timing's expires time. - pub fn expires_time_mut(&mut self) -> &mut Option<Timestamp> { - &mut self.expires_time - } + /// Get a mutable reference to the timing's expires time. + pub fn expires_time_mut(&mut self) -> &mut Option<Timestamp> { + &mut self.expires_time + } - /// Get a reference to the timing's expires time. - pub fn expires_time(&self) -> &Option<Timestamp> { - &self.expires_time - } + /// Get a reference to the timing's expires time. + pub fn expires_time(&self) -> &Option<Timestamp> { + &self.expires_time + } - /// Set the timing's expires time. - pub fn set_expires_time(&mut self, expires_time: Option<Timestamp>) { - self.expires_time = expires_time; - } + /// Set the timing's expires time. + pub fn set_expires_time(&mut self, expires_time: Option<Timestamp>) { + self.expires_time = expires_time; + } - /// Get a mutable reference to the timing's delay milli. - pub fn delay_milli_mut(&mut self) -> &mut Option<i32> { - &mut self.delay_milli - } + /// Get a mutable reference to the timing's delay milli. + pub fn delay_milli_mut(&mut self) -> &mut Option<i32> { + &mut self.delay_milli + } - /// Get a reference to the timing's delay milli. - pub fn delay_milli(&self) -> &Option<i32> { - &self.delay_milli - } + /// Get a reference to the timing's delay milli. + pub fn delay_milli(&self) -> &Option<i32> { + &self.delay_milli + } - /// Set the timing's delay milli. - pub fn set_delay_milli(&mut self, delay_milli: Option<i32>) { - self.delay_milli = delay_milli; - } + /// Set the timing's delay milli. + pub fn set_delay_milli(&mut self, delay_milli: Option<i32>) { + self.delay_milli = delay_milli; + } - /// Get a mutable reference to the timing's wait until time. - pub fn wait_until_time_mut(&mut self) -> &mut Option<Timestamp> { - &mut self.wait_until_time - } + /// Get a mutable reference to the timing's wait until time. + pub fn wait_until_time_mut(&mut self) -> &mut Option<Timestamp> { + &mut self.wait_until_time + } - /// Get a reference to the timing's wait until time. - pub fn wait_until_time(&self) -> &Option<Timestamp> { - &self.wait_until_time - } + /// Get a reference to the timing's wait until time. + pub fn wait_until_time(&self) -> &Option<Timestamp> { + &self.wait_until_time + } - /// Set the timing's wait until time. - pub fn set_wait_until_time(&mut self, wait_until_time: Option<Timestamp>) { - self.wait_until_time = wait_until_time; - } + /// Set the timing's wait until time. + pub fn set_wait_until_time(&mut self, wait_until_time: Option<Timestamp>) { + self.wait_until_time = wait_until_time; + } } diff --git a/identity-comm/src/message/trustping.rs b/identity-comm/src/message/trustping.rs index 6c03f418a2..3b95a0df9e 100644 --- a/identity-comm/src/message/trustping.rs +++ b/identity-comm/src/message/trustping.rs @@ -1,4 +1,5 @@ -use crate::message::Message; +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 use crate::message::Timing; use did_doc::url::Url; @@ -125,6 +126,7 @@ impl Trustping { #[derive(Debug, Deserialize, Serialize, Default)] pub struct TrustpingResponse { + #[serde(skip_serializing_if = "Option::is_none")] id: Option<DID>, #[serde(skip_serializing_if = "Option::is_none")] thread: Option<String>, @@ -186,28 +188,35 @@ impl TrustpingResponse { self.timing = timing; } } -impl Message for Trustping{} -impl Message for TrustpingResponse{} +#[cfg(test)] mod tests { - use std::str::FromStr; - use did_doc::Signature; - - use super::*; - use crate::message::message::AsEnvelope; - use crate::envelope::EnvelopeExt; + use super::*; use crate::envelope::SignatureAlgorithm; + use crate::message::message::Message; use identity_core::crypto::KeyPair; + #[test] - pub fn test_setter() { - let mut message = Trustping::new(Url::from_str("https://example.com").unwrap()); + pub fn test_plaintext_roundtrip() { + let mut message = Trustping::new(Url::parse("https://example.com").unwrap()); message.set_response_requested(Some(true)); let plain_envelope = message.pack_plain().unwrap(); - let bytes = plain_envelope.as_bytes(); - let message2:Trustping = plain_envelope.to_message().unwrap(); - dbg!(message2); + + let tp: Trustping = plain_envelope.to_message().unwrap(); + assert_eq!(format!("{:?}", tp), format!("{:?}", message)); + } + #[test] + pub fn test_signed_roundtrip() { let keypair = KeyPair::new_ed25519().unwrap(); - let message3 = message.pack_non_repudiable(SignatureAlgorithm::EdDSA,&keypair).unwrap(); - dbg!(message3); + + let message = Trustping::new(Url::parse("https://example.com").unwrap()); + let signed = message + .pack_non_repudiable(SignatureAlgorithm::EdDSA, &keypair) + .unwrap(); + + let tp = signed + .to_message::<Trustping>(SignatureAlgorithm::EdDSA, &keypair.public()) + .unwrap(); + assert_eq!(format!("{:?}", tp), format!("{:?}", message)); } } diff --git a/identity-comm/src/utils/timestamp.rs b/identity-comm/src/utils/timestamp.rs index 6692bf7d4d..7a27a67d07 100644 --- a/identity-comm/src/utils/timestamp.rs +++ b/identity-comm/src/utils/timestamp.rs @@ -6,7 +6,7 @@ pub struct Timestamp(i64); impl Timestamp { - pub const fn get(self) -> i64 { - self.0 - } + pub const fn get(self) -> i64 { + self.0 + } }