From 0adb323e544315f43825f9dc197f753a2ea6eccb Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 14:18:00 -0700 Subject: [PATCH 01/32] Retrieve basic message history --- identity-iota/src/chain/diff_chain.rs | 18 +++-- identity-iota/src/chain/integration_chain.rs | 10 ++- identity-iota/src/did/doc/document_diff.rs | 4 + identity-iota/src/did/doc/iota_document.rs | 4 + identity-iota/src/tangle/client.rs | 23 +++--- identity-iota/src/tangle/message_ext.rs | 81 ++++++++++++-------- identity-iota/src/tangle/message_history.rs | 47 ++++++++++++ identity-iota/src/tangle/message_index.rs | 20 +++-- identity-iota/src/tangle/message_set.rs | 68 ++++++++++++++++ identity-iota/src/tangle/mod.rs | 5 ++ identity-iota/src/tangle/traits.rs | 2 + 11 files changed, 223 insertions(+), 59 deletions(-) create mode 100644 identity-iota/src/tangle/message_history.rs create mode 100644 identity-iota/src/tangle/message_set.rs diff --git a/identity-iota/src/chain/diff_chain.rs b/identity-iota/src/chain/diff_chain.rs index 2e0ba2eb41..6fad895074 100644 --- a/identity-iota/src/chain/diff_chain.rs +++ b/identity-iota/src/chain/diff_chain.rs @@ -30,20 +30,26 @@ pub struct DiffChain { impl DiffChain { /// Constructs a new `DiffChain` for the given `IntegrationChain` from a slice of `Message`s. pub fn try_from_messages(integration_chain: &IntegrationChain, messages: &[Message]) -> Result { - if messages.is_empty() { - return Ok(Self::new()); - } - let did: &IotaDID = integration_chain.current().id(); - let mut index: MessageIndex = messages + let index: MessageIndex = messages .iter() .flat_map(|message| message.try_extract_diff(did)) .collect(); - trace!("[Diff] Message Index = {:#?}", index); debug!("[Diff] Valid Messages = {}/{}", messages.len(), index.len()); + Self::try_from_index(integration_chain, index) + } + + /// Constructs a new `DiffChain` for the given `IntegrationChain` from the given `MessageIndex`. + pub fn try_from_index(integration_chain: &IntegrationChain, mut index: MessageIndex) -> Result { + trace!("[Diff] Message Index = {:#?}", index); + + if index.is_empty() { + return Ok(Self::new()); + } + let mut this: Self = Self::new(); while let Some(mut list) = index.remove(DocumentChain::__diff_message_id(integration_chain, &this)) { diff --git a/identity-iota/src/chain/integration_chain.rs b/identity-iota/src/chain/integration_chain.rs index a551d91ca5..e7a1699a39 100644 --- a/identity-iota/src/chain/integration_chain.rs +++ b/identity-iota/src/chain/integration_chain.rs @@ -29,14 +29,20 @@ pub struct IntegrationChain { impl IntegrationChain { /// Constructs a new `IntegrationChain` from a slice of `Message`s. pub fn try_from_messages(did: &IotaDID, messages: &[Message]) -> Result { - let mut index: MessageIndex = messages + let index: MessageIndex = messages .iter() .flat_map(|message| message.try_extract_document(did)) .collect(); - trace!("[Int] Message Index = {:#?}", index); debug!("[Int] Valid Messages = {}/{}", messages.len(), index.len()); + Self::try_from_index(index) + } + + /// Constructs a new `IntegrationChain` from the given `MessageIndex`. + pub fn try_from_index(mut index: MessageIndex) -> Result { + trace!("[Int] Message Index = {:#?}", index); + let current: IotaDocument = index .remove_where(&MessageId::null(), |doc| doc.verify().is_ok()) .ok_or(Error::ChainError { diff --git a/identity-iota/src/did/doc/document_diff.rs b/identity-iota/src/did/doc/document_diff.rs index 237c8677fe..d413918910 100644 --- a/identity-iota/src/did/doc/document_diff.rs +++ b/identity-iota/src/did/doc/document_diff.rs @@ -89,6 +89,10 @@ impl DocumentDiff { } impl TangleRef for DocumentDiff { + fn did(&self) -> &IotaDID { + self.id() + } + fn message_id(&self) -> &MessageId { &self.message_id } diff --git a/identity-iota/src/did/doc/iota_document.rs b/identity-iota/src/did/doc/iota_document.rs index e21b87e1e4..60039f74e3 100644 --- a/identity-iota/src/did/doc/iota_document.rs +++ b/identity-iota/src/did/doc/iota_document.rs @@ -585,6 +585,10 @@ impl SetSignature for IotaDocument { } impl TangleRef for IotaDocument { + fn did(&self) -> &IotaDID { + self.id() + } + fn message_id(&self) -> &MessageId { &self.message_id } diff --git a/identity-iota/src/tangle/client.rs b/identity-iota/src/tangle/client.rs index d891a4afb1..ed6b9a8755 100644 --- a/identity-iota/src/tangle/client.rs +++ b/identity-iota/src/tangle/client.rs @@ -15,6 +15,7 @@ use crate::did::IotaDocument; use crate::error::Result; use crate::tangle::ClientBuilder; use crate::tangle::Message; +use crate::tangle::MessageHistory; use crate::tangle::MessageId; use crate::tangle::Network; use crate::tangle::Receipt; @@ -65,24 +66,20 @@ impl Client { /// Publishes an `IotaDocument` to the Tangle. pub async fn publish_document(&self, document: &IotaDocument) -> Result { - self - .client - .message() - .with_index(document.id().tag()) - .with_data(document.to_json_vec()?) - .finish() - .await - .map_err(Into::into) - .map(|message| Receipt::new(self.network, message)) + self.publish_json(document.id().tag(), document).await } /// Publishes a `DocumentDiff` to the Tangle. pub async fn publish_diff(&self, message_id: &MessageId, diff: &DocumentDiff) -> Result { + self.publish_json(&IotaDocument::diff_address(message_id)?, diff).await + } + + pub async fn publish_json(&self, index: &str, data: &T) -> Result { self .client .message() - .with_index(&IotaDocument::diff_address(message_id)?) - .with_data(diff.to_json_vec()?) + .with_index(index) + .with_data(data.to_json_vec()?) .finish() .await .map_err(Into::into) @@ -98,7 +95,7 @@ impl Client { trace!("Integration Chain Address: {}", did.tag()); // Fetch all messages for the integration chain. - let messages: Vec = Self::read_messages(&self.client, did.tag()).await?; + let messages: Vec = self.read_messages(did.tag()).await?; let integration_chain: IntegrationChain = IntegrationChain::try_from_messages(did, &messages)?; // Check if there is any query given and return @@ -109,7 +106,7 @@ impl Client { } else { // Fetch all messages for the diff chain. let address: String = IotaDocument::diff_address(integration_chain.current_message_id())?; - let messages: Vec = Self::read_messages(&self.client, &address).await?; + let messages: Vec = self.read_messages(&address).await?; trace!("Diff Messages: {:#?}", messages); diff --git a/identity-iota/src/tangle/message_ext.rs b/identity-iota/src/tangle/message_ext.rs index fe093874d1..49a9a334c5 100644 --- a/identity-iota/src/tangle/message_ext.rs +++ b/identity-iota/src/tangle/message_ext.rs @@ -17,39 +17,38 @@ use crate::tangle::TangleRef; // TODO: Use MessageId when it has a const ctor static NULL: &[u8; MESSAGE_ID_LENGTH] = &[0; MESSAGE_ID_LENGTH]; -macro_rules! try_extract { - ($ty:ty, $this:expr, $did:expr) => {{ - match $this.payload() { - Some(Payload::Indexation(payload)) => { - let mut resource: $ty = <$ty>::from_json_slice(payload.data()).ok()?; - - if $did.authority() != resource.id().authority() { - return None; - } - - TangleRef::set_message_id(&mut resource, $this.id().0); - - Some(resource) - } - Some(Payload::Transaction(tx_payload)) => match tx_payload.essence() { - Essence::Regular(regular_essence) => match regular_essence.payload() { - Some(Payload::Indexation(payload)) => { - let mut resource: $ty = <$ty>::from_json_slice(payload.data()).ok()?; - - if $did.authority() != resource.id().authority() { - return None; - } - - TangleRef::set_message_id(&mut resource, $this.id().0); - - Some(resource) - } - _ => None, - }, +fn parse_message(message: &Message, did: &IotaDID) -> Option { + let message_id: MessageId = message.id().0; + let payload: Option<&Payload> = message.payload().as_ref(); + let resource: T = parse_payload(message_id, payload)?; + + if did.authority() != resource.did().authority() { + return None; + } + + Some(resource) +} + +fn parse_payload(message_id: MessageId, payload: Option<&Payload>) -> Option { + match payload { + Some(Payload::Indexation(indexation)) => parse_data(message_id, indexation.data()), + Some(Payload::Transaction(transaction)) => match transaction.essence() { + Essence::Regular(essence) => match essence.payload() { + Some(Payload::Indexation(payload)) => parse_data(message_id, payload.data()), + _ => None, }, _ => None, - } - }}; + }, + _ => None, + } +} + +fn parse_data(message_id: MessageId, data: &[u8]) -> Option { + let mut resource: T = T::from_json_slice(data).ok()?; + + resource.set_message_id(message_id); + + Some(resource) } pub trait MessageIdExt: Sized { @@ -82,10 +81,26 @@ pub trait MessageExt { impl MessageExt for Message { fn try_extract_document(&self, did: &IotaDID) -> Option { - try_extract!(IotaDocument, self, did) + IotaDocument::try_from_message(self, did) } fn try_extract_diff(&self, did: &IotaDID) -> Option { - try_extract!(DocumentDiff, self, did) + DocumentDiff::try_from_message(self, did) + } +} + +pub trait TryFromMessage: Sized { + fn try_from_message(message: &Message, did: &IotaDID) -> Option; +} + +impl TryFromMessage for IotaDocument { + fn try_from_message(message: &Message, did: &IotaDID) -> Option { + parse_message(message, did) + } +} + +impl TryFromMessage for DocumentDiff { + fn try_from_message(message: &Message, did: &IotaDID) -> Option { + parse_message(message, did) } } diff --git a/identity-iota/src/tangle/message_history.rs b/identity-iota/src/tangle/message_history.rs new file mode 100644 index 0000000000..ac0dfa453a --- /dev/null +++ b/identity-iota/src/tangle/message_history.rs @@ -0,0 +1,47 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::chain::DiffChain; +use crate::chain::IntegrationChain; +use crate::did::DocumentDiff; +use crate::did::IotaDID; +use crate::did::IotaDocument; +use crate::error::Result; +use crate::tangle::Client; +use crate::tangle::Message; +use crate::tangle::MessageId; +use crate::tangle::MessageSet; + +#[derive(Clone, Debug, Serialize)] +pub struct MessageHistory { + #[serde(rename = "intChainData")] + pub int_chain_data: IntegrationChain, + #[serde(rename = "intChainSpam")] + pub int_chain_spam: Option>, + #[serde(rename = "diffChainData")] + pub diff_chain_data: DiffChain, + #[serde(rename = "diffChainSpam")] + pub diff_chain_spam: Option>, +} + +impl MessageHistory { + /// Read the message history of the DID Document identified by the given DID. + pub async fn read(client: &Client, did: &IotaDID) -> Result { + let int_messages: Vec = client.read_messages(did.tag()).await?; + let int_message_set: MessageSet = MessageSet::new(did, &int_messages); + let int_chain_data: IntegrationChain = IntegrationChain::try_from_index(int_message_set.to_index())?; + let int_message_id: &MessageId = int_chain_data.current_message_id(); + + let diff_address: String = IotaDocument::diff_address(int_message_id)?; + let diff_messages: Vec = client.read_messages(&diff_address).await?; + let diff_message_set: MessageSet = MessageSet::new(did, &diff_messages); + let diff_chain_data: DiffChain = DiffChain::try_from_index(&int_chain_data, diff_message_set.to_index())?; + + Ok(MessageHistory { + int_chain_data, + int_chain_spam: int_message_set.spam().map(<[_]>::to_vec), + diff_chain_data, + diff_chain_spam: diff_message_set.spam().map(<[_]>::to_vec), + }) + } +} diff --git a/identity-iota/src/tangle/message_index.rs b/identity-iota/src/tangle/message_index.rs index 9eff2a540e..2aebe43cfe 100644 --- a/identity-iota/src/tangle/message_index.rs +++ b/identity-iota/src/tangle/message_index.rs @@ -48,13 +48,16 @@ where { pub fn insert(&mut self, element: T) { let key: &MessageId = element.previous_message_id(); + if let Some(scope) = self.inner.get_mut(key) { - let msg_id: &MessageId = element.message_id(); - let idx = match scope.binary_search_by(|elem| elem.message_id().cmp(msg_id)) { - Ok(idx) => idx, - Err(idx) => idx, + let message_id: &MessageId = element.message_id(); + + let index: usize = match scope.binary_search_by(|elem| elem.message_id().cmp(message_id)) { + Ok(index) => index, + Err(index) => index, }; - scope.insert(idx, element); + + scope.insert(index, element); } else { self.inner.insert(*key, vec![element]); } @@ -107,9 +110,11 @@ where #[cfg(test)] mod tests { use super::*; + use crate::did::IotaDID; #[derive(Debug)] struct Case { + did: IotaDID, message_id: MessageId, previous_message_id: MessageId, state: bool, @@ -118,6 +123,7 @@ mod tests { impl Case { fn new(message_id: [u8; 32], previous_message_id: [u8; 32], state: bool) -> Self { Self { + did: IotaDID::new(&[]).unwrap(), message_id: MessageId::new(message_id), previous_message_id: MessageId::new(previous_message_id), state, @@ -126,6 +132,10 @@ mod tests { } impl TangleRef for Case { + fn did(&self) -> &IotaDID { + &self.did + } + fn message_id(&self) -> &MessageId { &self.message_id } diff --git a/identity-iota/src/tangle/message_set.rs b/identity-iota/src/tangle/message_set.rs new file mode 100644 index 0000000000..3982913fd8 --- /dev/null +++ b/identity-iota/src/tangle/message_set.rs @@ -0,0 +1,68 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; +// use identity_common::core::FromJson; + +use crate::did::IotaDID; +use crate::tangle::Message; +use crate::tangle::MessageId; +use crate::tangle::MessageIndex; +use crate::tangle::TangleRef; +use crate::tangle::TryFromMessage; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct MessageSet { + data: BTreeMap, + spam: Option>, +} + +impl MessageSet { + pub fn get(&self, message_id: &MessageId) -> Option<&T> { + self.data.get(message_id) + } + + pub fn data(&self) -> &BTreeMap { + &self.data + } + + pub fn spam(&self) -> Option<&[MessageId]> { + self.spam.as_deref() + } + + pub fn message_ids(&self) -> impl Iterator { + self.data.keys() + } + + pub fn resources(&self) -> impl Iterator { + self.data.values() + } +} + +impl MessageSet { + pub fn new(did: &IotaDID, messages: &[Message]) -> Self { + let mut data: BTreeMap = BTreeMap::new(); + let mut spam: Option> = None; + + for message in messages { + let message_id: MessageId = message.id().0; + + match T::try_from_message(message, did) { + Some(resource) => { + data.insert(message_id, resource); + } + None => { + spam.get_or_insert_with(Default::default).push(message_id); + } + } + } + + Self { data, spam } + } +} + +impl MessageSet { + pub fn to_index(&self) -> MessageIndex { + self.resources().cloned().collect() + } +} diff --git a/identity-iota/src/tangle/mod.rs b/identity-iota/src/tangle/mod.rs index aec8f45084..37b9985ff6 100644 --- a/identity-iota/src/tangle/mod.rs +++ b/identity-iota/src/tangle/mod.rs @@ -5,7 +5,9 @@ mod client; mod client_builder; mod client_map; mod message_ext; +mod message_history; mod message_index; +mod message_set; mod network; mod receipt; mod traits; @@ -15,7 +17,10 @@ pub use self::client_builder::ClientBuilder; pub use self::client_map::ClientMap; pub use self::message_ext::MessageExt; pub use self::message_ext::MessageIdExt; +pub use self::message_ext::TryFromMessage; +pub use self::message_history::MessageHistory; pub use self::message_index::MessageIndex; +pub use self::message_set::MessageSet; pub use self::network::Network; pub use self::receipt::Receipt; pub use self::traits::TangleRef; diff --git a/identity-iota/src/tangle/traits.rs b/identity-iota/src/tangle/traits.rs index d86666b0be..92999aecb2 100644 --- a/identity-iota/src/tangle/traits.rs +++ b/identity-iota/src/tangle/traits.rs @@ -7,6 +7,8 @@ use crate::error::Result; use crate::tangle::MessageId; pub trait TangleRef { + fn did(&self) -> &IotaDID; + fn message_id(&self) -> &MessageId; fn set_message_id(&mut self, message_id: MessageId); From bfcc3b258b79bacfc0915cd4a9e1a90b94f76960 Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 16:34:40 -0700 Subject: [PATCH 02/32] add Client::resolve_diffs --- identity-did/src/verifiable/document.rs | 47 ++++++++++++++------- identity-iota/src/chain/diff_chain.rs | 6 +++ identity-iota/src/tangle/client.rs | 45 ++++++++++++++++++-- identity-iota/src/tangle/message_history.rs | 1 + 4 files changed, 80 insertions(+), 19 deletions(-) diff --git a/identity-did/src/verifiable/document.rs b/identity-did/src/verifiable/document.rs index 86c431221f..552d8ce480 100644 --- a/identity-did/src/verifiable/document.rs +++ b/identity-did/src/verifiable/document.rs @@ -289,6 +289,20 @@ where { let signature: &Signature = that.try_signature()?; let method: &VerificationMethod = self.document.try_resolve(signature)?; + + Self::do_verify(method, that) + } + + /// Verifies the signature of the provided data. + /// + /// # Errors + /// + /// Fails if an unsupported verification method is used, document + /// serialization fails, or the verification operation fails. + pub fn do_verify(method: &VerificationMethod, that: &X) -> Result<()> + where + X: Serialize + TrySignature, + { let data: Vec = method.key_data().try_decode()?; match method.key_type() { @@ -297,10 +311,10 @@ where } MethodType::MerkleKeyCollection2021 => match MerkleKey::extract_tags(&data)? { (MerkleSignatureTag::ED25519, MerkleDigestTag::SHA256) => { - self.merkle_key_verify::(that, method, &data)?; + merkle_key_verify::(that, method, &data)?; } (MerkleSignatureTag::ED25519, MerkleDigestTag::BLAKE2B_256) => { - self.merkle_key_verify::(that, method, &data)?; + merkle_key_verify::(that, method, &data)?; } (_, _) => { return Err(Error::InvalidMethodType); @@ -310,22 +324,23 @@ where Ok(()) } +} - fn merkle_key_verify(&self, that: &X, method: &VerificationMethod, data: &[u8]) -> Result<()> - where - X: Serialize + TrySignature, - D: MerkleDigest, - S: MerkleSignature + Verify, - { - let revocation: Option = method.revocation()?; - let mut vkey: VerificationKey<'_> = VerificationKey::from_borrowed(data); +fn merkle_key_verify(that: &X, method: &VerificationMethod, data: &[u8]) -> Result<()> +where + X: Serialize + TrySignature, + D: MerkleDigest, + S: MerkleSignature + Verify, + U: Revocation, +{ + let revocation: Option = method.revocation()?; + let mut vkey: VerificationKey<'_> = VerificationKey::from_borrowed(data); - if let Some(revocation) = revocation.as_ref() { - vkey.set_revocation(revocation); - } + if let Some(revocation) = revocation.as_ref() { + vkey.set_revocation(revocation); + } - MerkleVerifier::::verify_signature(that, &vkey)?; + MerkleVerifier::::verify_signature(that, &vkey)?; - Ok(()) - } + Ok(()) } diff --git a/identity-iota/src/chain/diff_chain.rs b/identity-iota/src/chain/diff_chain.rs index 6fad895074..fc13e61eb4 100644 --- a/identity-iota/src/chain/diff_chain.rs +++ b/identity-iota/src/chain/diff_chain.rs @@ -176,6 +176,12 @@ impl Display for DiffChain { } } +impl From for Vec { + fn from(other: DiffChain) -> Self { + other.inner + } +} + #[cfg(test)] mod test { use identity_core::common::Timestamp; diff --git a/identity-iota/src/tangle/client.rs b/identity-iota/src/tangle/client.rs index ed6b9a8755..cba08ca565 100644 --- a/identity-iota/src/tangle/client.rs +++ b/identity-iota/src/tangle/client.rs @@ -12,13 +12,19 @@ use crate::chain::IntegrationChain; use crate::did::DocumentDiff; use crate::did::IotaDID; use crate::did::IotaDocument; +use crate::did::IotaVerificationMethod; +use crate::did::Verifier; use crate::error::Result; use crate::tangle::ClientBuilder; use crate::tangle::Message; use crate::tangle::MessageHistory; use crate::tangle::MessageId; +use crate::tangle::MessageIdExt; +use crate::tangle::MessageIndex; +use crate::tangle::MessageSet; use crate::tangle::Network; use crate::tangle::Receipt; +use crate::tangle::TangleRef; use crate::tangle::TangleResolve; #[derive(Debug)] @@ -116,9 +122,42 @@ impl Client { DocumentChain::with_diff_chain(integration_chain, diff) } - async fn read_messages(client: &IotaClient, address: &str) -> Result> { - let message_ids: Box<[MessageId]> = Self::read_message_index(client, address).await?; - let messages: Vec = Self::read_message_data(client, &message_ids).await?; + /// Returns the message history of the given DID. + pub async fn resolve_history(&self, did: &IotaDID) -> Result { + MessageHistory::read(self, did).await + } + + /// Returns the diff chain for the integration chain specified by `message_id`. + pub async fn resolve_diffs( + &self, + did: &IotaDID, + method: &IotaVerificationMethod, + message_id: &MessageId, + ) -> Result> { + let diff_address: String = IotaDocument::diff_address(message_id)?; + let diff_messages: Vec = self.read_messages(&diff_address).await?; + let diff_message_set: MessageSet = MessageSet::new(did, &diff_messages); + + let mut index: MessageIndex = diff_message_set.to_index(); + let mut target: MessageId = *message_id; + let mut output: Vec = Vec::new(); + + while let Some(mut list) = index.remove(&target) { + 'inner: while let Some(next) = list.pop() { + if Verifier::do_verify(method, &next).is_ok() { + target = *next.message_id(); + output.push(next); + break 'inner; + } + } + } + + Ok(output) + } + + pub(crate) async fn read_messages(&self, address: &str) -> Result> { + let message_ids: Box<[MessageId]> = Self::read_message_index(&self.client, address).await?; + let messages: Vec = Self::read_message_data(&self.client, &message_ids).await?; Ok(messages) } diff --git a/identity-iota/src/tangle/message_history.rs b/identity-iota/src/tangle/message_history.rs index ac0dfa453a..34a9194c12 100644 --- a/identity-iota/src/tangle/message_history.rs +++ b/identity-iota/src/tangle/message_history.rs @@ -12,6 +12,7 @@ use crate::tangle::Message; use crate::tangle::MessageId; use crate::tangle::MessageSet; +/// A representation of a DID Document message history. #[derive(Clone, Debug, Serialize)] pub struct MessageHistory { #[serde(rename = "intChainData")] From b306e9ffa19649d84af7969294009ea2309079e8 Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 16:35:52 -0700 Subject: [PATCH 03/32] Add WASM support/example --- bindings/wasm/docs/api-reference.md | 26 ++++ bindings/wasm/src/credential/credential.rs | 2 +- bindings/wasm/src/credential/presentation.rs | 2 +- bindings/wasm/src/did/mod.rs | 10 ++ bindings/wasm/src/{ => did}/wasm_did.rs | 0 bindings/wasm/src/{ => did}/wasm_document.rs | 4 +- .../src/{ => did}/wasm_verification_method.rs | 2 +- bindings/wasm/src/lib.rs | 4 +- bindings/wasm/src/tangle/client.rs | 43 +++++++ bindings/wasm/tests/wasm.rs | 4 +- examples/Cargo.toml | 4 + examples/low-level-api/did_chain.rs | 119 ++++++++++++++++++ identity-iota/src/tangle/client.rs | 25 +--- identity-iota/src/tangle/message_index.rs | 4 + identity-iota/src/tangle/message_set.rs | 37 ++++++ identity-iota/src/tangle/mod.rs | 1 + 16 files changed, 255 insertions(+), 32 deletions(-) create mode 100644 bindings/wasm/src/did/mod.rs rename bindings/wasm/src/{ => did}/wasm_did.rs (100%) rename bindings/wasm/src/{ => did}/wasm_document.rs (99%) rename bindings/wasm/src/{ => did}/wasm_verification_method.rs (99%) create mode 100644 examples/low-level-api/did_chain.rs diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index b1080f00cb..5381374edb 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -146,6 +146,8 @@ * [.publishDocument(document)](#Client+publishDocument) ⇒ Promise.<any> * [.publishDiff(message_id, value)](#Client+publishDiff) ⇒ Promise.<any> * [.resolve(did)](#Client+resolve) ⇒ Promise.<any> + * [.resolveHistory(did)](#Client+resolveHistory) ⇒ Promise.<any> + * [.resolveDiffs(did, method, message_id)](#Client+resolveDiffs) ⇒ Promise.<any> * [.checkCredential(data)](#Client+checkCredential) ⇒ Promise.<any> * [.checkPresentation(data)](#Client+checkPresentation) ⇒ Promise.<any> * _static_ @@ -195,6 +197,30 @@ Publishes a `DocumentDiff` to the Tangle. | --- | --- | | did | string | + + +### client.resolveHistory(did) ⇒ Promise.<any> +Returns the message history of the given DID. + +**Kind**: instance method of [Client](#Client) + +| Param | Type | +| --- | --- | +| did | string | + + + +### client.resolveDiffs(did, method, message_id) ⇒ Promise.<any> +Returns the diff chain for the integration chain specified by `message_id`. + +**Kind**: instance method of [Client](#Client) + +| Param | Type | +| --- | --- | +| did | string | +| method | [VerificationMethod](#VerificationMethod) | +| message_id | string | + ### client.checkCredential(data) ⇒ Promise.<any> diff --git a/bindings/wasm/src/credential/credential.rs b/bindings/wasm/src/credential/credential.rs index 092f81c55d..d5a7868844 100644 --- a/bindings/wasm/src/credential/credential.rs +++ b/bindings/wasm/src/credential/credential.rs @@ -12,7 +12,7 @@ use identity::credential::Subject; use wasm_bindgen::prelude::*; use crate::utils::err; -use crate::wasm_document::WasmDocument; +use crate::did::WasmDocument; #[wasm_bindgen(inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/credential/presentation.rs b/bindings/wasm/src/credential/presentation.rs index 8659cba499..1068407418 100644 --- a/bindings/wasm/src/credential/presentation.rs +++ b/bindings/wasm/src/credential/presentation.rs @@ -9,7 +9,7 @@ use identity::credential::PresentationBuilder; use wasm_bindgen::prelude::*; use crate::utils::err; -use crate::wasm_document::WasmDocument; +use crate::did::WasmDocument; #[wasm_bindgen(inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/did/mod.rs b/bindings/wasm/src/did/mod.rs new file mode 100644 index 0000000000..80c7b663ce --- /dev/null +++ b/bindings/wasm/src/did/mod.rs @@ -0,0 +1,10 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod wasm_did; +mod wasm_document; +mod wasm_verification_method; + +pub use self::wasm_did::WasmDID; +pub use self::wasm_document::WasmDocument; +pub use self::wasm_verification_method::WasmVerificationMethod; diff --git a/bindings/wasm/src/wasm_did.rs b/bindings/wasm/src/did/wasm_did.rs similarity index 100% rename from bindings/wasm/src/wasm_did.rs rename to bindings/wasm/src/did/wasm_did.rs diff --git a/bindings/wasm/src/wasm_document.rs b/bindings/wasm/src/did/wasm_document.rs similarity index 99% rename from bindings/wasm/src/wasm_document.rs rename to bindings/wasm/src/did/wasm_document.rs index a8accc42f9..1f3c59c29d 100644 --- a/bindings/wasm/src/wasm_document.rs +++ b/bindings/wasm/src/did/wasm_document.rs @@ -26,8 +26,8 @@ use crate::crypto::KeyPair; use crate::crypto::KeyType; use crate::service::Service; use crate::utils::err; -use crate::wasm_did::WasmDID; -use crate::wasm_verification_method::WasmVerificationMethod; +use crate::did::WasmDID; +use crate::did::WasmVerificationMethod; #[wasm_bindgen(inspectable)] pub struct NewDocument { diff --git a/bindings/wasm/src/wasm_verification_method.rs b/bindings/wasm/src/did/wasm_verification_method.rs similarity index 99% rename from bindings/wasm/src/wasm_verification_method.rs rename to bindings/wasm/src/did/wasm_verification_method.rs index af763ce042..2b46e31b2c 100644 --- a/bindings/wasm/src/wasm_verification_method.rs +++ b/bindings/wasm/src/did/wasm_verification_method.rs @@ -11,7 +11,7 @@ use crate::crypto::Digest; use crate::crypto::KeyCollection; use crate::crypto::KeyPair; use crate::utils::err; -use crate::wasm_did::WasmDID; +use crate::did::WasmDID; #[wasm_bindgen(js_name = VerificationMethod, inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index 83935c74e9..26d0b46bef 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -14,12 +14,10 @@ mod utils; pub mod credential; pub mod crypto; +pub mod did; pub mod message; pub mod service; pub mod tangle; -pub mod wasm_did; -pub mod wasm_document; -pub mod wasm_verification_method; /// Initializes the console error panic hook for better error messages #[wasm_bindgen(start)] diff --git a/bindings/wasm/src/tangle/client.rs b/bindings/wasm/src/tangle/client.rs index 21f9cc9a35..86110574d9 100644 --- a/bindings/wasm/src/tangle/client.rs +++ b/bindings/wasm/src/tangle/client.rs @@ -14,6 +14,7 @@ use identity::iota::IotaDocument; use identity::iota::MessageId; use identity::iota::TangleRef; use identity::iota::TangleResolve; +use identity::iota::IotaVerificationMethod; use js_sys::Promise; use std::rc::Rc; use wasm_bindgen::prelude::*; @@ -22,6 +23,7 @@ use wasm_bindgen_futures::future_to_promise; use crate::tangle::Config; use crate::tangle::WasmNetwork; use crate::utils::err; +use crate::did::WasmVerificationMethod; #[wasm_bindgen] #[derive(Debug)] @@ -128,6 +130,47 @@ impl Client { Ok(promise) } + /// Returns the message history of the given DID. + #[wasm_bindgen(js_name = resolveHistory)] + pub fn resolve_history(&self, did: &str) -> Result { + let did: IotaDID = did.parse().map_err(err)?; + let client: Rc = self.client.clone(); + + let promise: Promise = future_to_promise(async move { + client + .resolve_history(&did) + .await + .map_err(err) + .and_then(|output| JsValue::from_serde(&output).map_err(err)) + }); + + Ok(promise) + } + + /// Returns the diff chain for the integration chain specified by `message_id`. + #[wasm_bindgen(js_name = resolveDiffs)] + pub fn resolve_diffs( + &self, + did: &str, + method: &WasmVerificationMethod, + message_id: &str, + ) -> Result { + let did: IotaDID = did.parse().map_err(err)?; + let message_id: MessageId = message_id.parse().map_err(err)?; + let client: Rc = self.client.clone(); + let method: IotaVerificationMethod = method.0.clone(); + + let promise: Promise = future_to_promise(async move { + client + .resolve_diffs(&did, &method, &message_id) + .await + .map_err(err) + .and_then(|output| JsValue::from_serde(&output).map_err(err)) + }); + + Ok(promise) + } + /// Validates a credential with the DID Document from the Tangle. #[wasm_bindgen(js_name = checkCredential)] pub fn check_credential(&self, data: &str) -> Result { diff --git a/bindings/wasm/tests/wasm.rs b/bindings/wasm/tests/wasm.rs index d97fdbe099..27a7763844 100644 --- a/bindings/wasm/tests/wasm.rs +++ b/bindings/wasm/tests/wasm.rs @@ -7,8 +7,8 @@ use identity_wasm::crypto::Digest; use identity_wasm::crypto::KeyCollection; use identity_wasm::crypto::KeyPair; use identity_wasm::crypto::KeyType; -use identity_wasm::wasm_did::WasmDID; -use identity_wasm::wasm_document::WasmDocument; +use identity_wasm::did::WasmDID; +use identity_wasm::did::WasmDocument; #[wasm_bindgen_test] fn test_keypair() { diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 75c783b09f..bce7dd4d88 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -61,3 +61,7 @@ path = "low-level-api/merkle_key.rs" [[example]] name = "resolution" path = "low-level-api/resolution.rs" + +[[example]] +name = "did_chain" +path = "low-level-api/did_chain.rs" diff --git a/examples/low-level-api/did_chain.rs b/examples/low-level-api/did_chain.rs new file mode 100644 index 0000000000..e3bc80b46c --- /dev/null +++ b/examples/low-level-api/did_chain.rs @@ -0,0 +1,119 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! cargo run --example did_chain + +mod create_did; + +use identity::core::json; +use identity::core::Timestamp; +use identity::crypto::KeyPair; +use identity::iota::Client; +use identity::iota::DiffSet; +use identity::iota::DocumentDiff; +use identity::iota::IotaDocument; +use identity::iota::IotaVerificationMethod; +use identity::iota::MessageHistory; +use identity::iota::MessageId; +use identity::iota::Receipt; +use identity::iota::Result; + +#[tokio::main] +async fn main() -> Result<()> { + // Create a client instance to send messages to the Tangle. + let client: Client = Client::new().await?; + let keypair: KeyPair = KeyPair::new_ed25519()?; + + // Create a new DID Document from the generated key pair. + let mut document: IotaDocument = IotaDocument::from_keypair(&keypair)?; + + // Sign the DID Document + document.sign(keypair.secret())?; + + // Publish the DID Document to the Tangle + let receipt: Receipt = client.publish_document(&document).await?; + + // Publish some spam + let index: &str = document.id().tag(); + client.publish_json(index, &json!({ "spam:1": true })).await?; + client.publish_json(index, &json!({ "spam:2": true })).await?; + client.publish_json(index, &json!({ "spam:3": true })).await?; + client.publish_json(index, &json!({ "spam:4": true })).await?; + client.publish_json(index, &json!({ "spam:5": true })).await?; + + // Update the DID Document with newly added values and sign once again + document.properties_mut().insert("foo".into(), 123.into()); + // document.set_message_id(*receipt.message_id()); + document.set_previous_message_id(*receipt.message_id()); + document.set_updated(Timestamp::now_utc()); + document.sign(keypair.secret())?; + + // Publish the updated DID Document to the integration chain address + let receipt: Receipt = client.publish_document(&document).await?; + + // Prepare a diff chain DID Document update + let update: IotaDocument = { + let mut new: IotaDocument = document.clone(); + new.properties_mut().insert("foo".into(), 0.into()); // change `foo` + new.properties_mut().insert("bar".into(), 456.into()); // insert `bar` + new.set_updated(Timestamp::now_utc()); + new + }; + + // Generate a signed diff object. + // + // This is the first diff therefore the `previous_message_id` property is + // set to the authentication message + let diff: DocumentDiff = document.diff(&update, *receipt.message_id(), keypair.secret())?; + + // Publish the diff object to the Tangle + let diff_receipt: Receipt = client.publish_diff(receipt.message_id(), &diff).await?; + + // Prepare another diff chain update + let update: IotaDocument = { + let mut new: IotaDocument = document.clone(); + new.properties_mut().insert("baz".into(), 789.into()); // insert `baz` + new.set_updated(Timestamp::now_utc()); + new + }; + + // Generate a signed diff object. + // + // This is the second diff therefore the `previous_message_id` property is + // set to the previously published diff object + let diff: DocumentDiff = document.diff(&update, *diff_receipt.message_id(), keypair.secret())?; + + // Publish the diff object to the Tangle + let _diff_receipt: Receipt = client.publish_diff(receipt.message_id(), &diff).await?; + + // Retrieve the message history of the DID + let history: MessageHistory = client.resolve_history(document.id()).await?; + + println!("History (1) = {:#?}", history); + + // Publish another integration chain update + document = update; + document.properties_mut().insert("foo".into(), 123456789.into()); + document.properties_mut().remove("bar"); + document.properties_mut().remove("baz"); + document.set_previous_message_id(*receipt.message_id()); + document.set_updated(Timestamp::now_utc()); + document.sign(keypair.secret())?; + + // Send the updated DID Document to the Tangle + let _receipt: Receipt = client.publish_document(&document).await?; + + // Retrieve the updated message history of the DID + let history: MessageHistory = client.resolve_history(document.id()).await?; + + println!("History (2) = {:#?}", history); + + // Retrieve the diff chain of the previous integration message + let method: &IotaVerificationMethod = document.authentication(); + let target: &MessageId = receipt.message_id(); + let diffs: DiffSet = client.resolve_diffs(document.id(), method, target).await?; + + println!("Diffs = {:#?}", diffs); + + Ok(()) +} diff --git a/identity-iota/src/tangle/client.rs b/identity-iota/src/tangle/client.rs index cba08ca565..520ce936aa 100644 --- a/identity-iota/src/tangle/client.rs +++ b/identity-iota/src/tangle/client.rs @@ -13,18 +13,14 @@ use crate::did::DocumentDiff; use crate::did::IotaDID; use crate::did::IotaDocument; use crate::did::IotaVerificationMethod; -use crate::did::Verifier; use crate::error::Result; use crate::tangle::ClientBuilder; +use crate::tangle::DiffSet; use crate::tangle::Message; use crate::tangle::MessageHistory; use crate::tangle::MessageId; -use crate::tangle::MessageIdExt; -use crate::tangle::MessageIndex; -use crate::tangle::MessageSet; use crate::tangle::Network; use crate::tangle::Receipt; -use crate::tangle::TangleRef; use crate::tangle::TangleResolve; #[derive(Debug)] @@ -133,26 +129,11 @@ impl Client { did: &IotaDID, method: &IotaVerificationMethod, message_id: &MessageId, - ) -> Result> { + ) -> Result { let diff_address: String = IotaDocument::diff_address(message_id)?; let diff_messages: Vec = self.read_messages(&diff_address).await?; - let diff_message_set: MessageSet = MessageSet::new(did, &diff_messages); - - let mut index: MessageIndex = diff_message_set.to_index(); - let mut target: MessageId = *message_id; - let mut output: Vec = Vec::new(); - - while let Some(mut list) = index.remove(&target) { - 'inner: while let Some(next) = list.pop() { - if Verifier::do_verify(method, &next).is_ok() { - target = *next.message_id(); - output.push(next); - break 'inner; - } - } - } - Ok(output) + Ok(DiffSet::new(did, method, message_id, &diff_messages)) } pub(crate) async fn read_messages(&self, address: &str) -> Result> { diff --git a/identity-iota/src/tangle/message_index.rs b/identity-iota/src/tangle/message_index.rs index 2aebe43cfe..e086f989d8 100644 --- a/identity-iota/src/tangle/message_index.rs +++ b/identity-iota/src/tangle/message_index.rs @@ -40,6 +40,10 @@ impl MessageIndex { None } } + + pub fn drain_keys(&mut self) -> impl Iterator + '_ { + self.inner.drain().map(|(data, _)| data) + } } impl MessageIndex diff --git a/identity-iota/src/tangle/message_set.rs b/identity-iota/src/tangle/message_set.rs index 3982913fd8..afba697f53 100644 --- a/identity-iota/src/tangle/message_set.rs +++ b/identity-iota/src/tangle/message_set.rs @@ -4,7 +4,10 @@ use std::collections::BTreeMap; // use identity_common::core::FromJson; +use crate::did::DocumentDiff; use crate::did::IotaDID; +use crate::did::IotaVerificationMethod; +use crate::did::Verifier; use crate::tangle::Message; use crate::tangle::MessageId; use crate::tangle::MessageIndex; @@ -66,3 +69,37 @@ impl MessageSet { self.resources().cloned().collect() } } + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DiffSet { + data: Vec, + spam: Option>, +} + +impl DiffSet { + pub fn new(did: &IotaDID, method: &IotaVerificationMethod, message_id: &MessageId, messages: &[Message]) -> Self { + let message_set: MessageSet = MessageSet::new(did, messages); + + let mut index: MessageIndex = message_set.to_index(); + let mut target: MessageId = *message_id; + + let mut data: Vec = Vec::new(); + let mut spam: Option> = None; + + while let Some(mut list) = index.remove(&target) { + 'inner: while let Some(next) = list.pop() { + if Verifier::do_verify(method, &next).is_ok() { + target = *next.message_id(); + data.push(next); + break 'inner; + } else { + spam.get_or_insert_with(Vec::new).push(*next.message_id()); + } + } + } + + spam.get_or_insert_with(Vec::new).extend(index.drain_keys()); + + Self { data, spam } + } +} diff --git a/identity-iota/src/tangle/mod.rs b/identity-iota/src/tangle/mod.rs index 37b9985ff6..e186731e77 100644 --- a/identity-iota/src/tangle/mod.rs +++ b/identity-iota/src/tangle/mod.rs @@ -20,6 +20,7 @@ pub use self::message_ext::MessageIdExt; pub use self::message_ext::TryFromMessage; pub use self::message_history::MessageHistory; pub use self::message_index::MessageIndex; +pub use self::message_set::DiffSet; pub use self::message_set::MessageSet; pub use self::network::Network; pub use self::receipt::Receipt; From 0119b6ba7158264360e8e48859d8c90845d6dd60 Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 18:23:44 -0700 Subject: [PATCH 04/32] Remove needless borrow --- libjose/src/jwk/key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libjose/src/jwk/key.rs b/libjose/src/jwk/key.rs index 7bd11c9680..915175843b 100644 --- a/libjose/src/jwk/key.rs +++ b/libjose/src/jwk/key.rs @@ -521,7 +521,7 @@ impl Jwk { [..] => return Err(Error::KeyError("multi prime keys are not supported")), }; - let values: RsaComputed = RsaComputed::new(secret.d(), &p, &q)?; + let values: RsaComputed = RsaComputed::new(secret.d(), p, q)?; Ok(Jwk::from_params(JwkParamsRsa { n: encode_b64(secret.n().to_bytes_be()), From d12a8d0f30beb4782d2cc7a76fc93ff2c4dd5b20 Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 18:44:03 -0700 Subject: [PATCH 05/32] cargo clean --- identity-iota/src/tangle/message_ext.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/identity-iota/src/tangle/message_ext.rs b/identity-iota/src/tangle/message_ext.rs index 49a9a334c5..136a21b371 100644 --- a/identity-iota/src/tangle/message_ext.rs +++ b/identity-iota/src/tangle/message_ext.rs @@ -37,7 +37,6 @@ fn parse_payload(message_id: MessageId, payload: Option Some(Payload::Indexation(payload)) => parse_data(message_id, payload.data()), _ => None, }, - _ => None, }, _ => None, } From dbce3089e863cb57db672eb6ce32d5ad11b45039 Mon Sep 17 00:00:00 2001 From: l1h3r Date: Tue, 3 Aug 2021 18:46:27 -0700 Subject: [PATCH 06/32] cargo fmt --- bindings/wasm/src/credential/credential.rs | 2 +- bindings/wasm/src/credential/presentation.rs | 2 +- bindings/wasm/src/did/wasm_document.rs | 4 ++-- bindings/wasm/src/did/wasm_verification_method.rs | 2 +- bindings/wasm/src/tangle/client.rs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bindings/wasm/src/credential/credential.rs b/bindings/wasm/src/credential/credential.rs index d5a7868844..c934134afe 100644 --- a/bindings/wasm/src/credential/credential.rs +++ b/bindings/wasm/src/credential/credential.rs @@ -11,8 +11,8 @@ use identity::credential::CredentialBuilder; use identity::credential::Subject; use wasm_bindgen::prelude::*; -use crate::utils::err; use crate::did::WasmDocument; +use crate::utils::err; #[wasm_bindgen(inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/credential/presentation.rs b/bindings/wasm/src/credential/presentation.rs index 1068407418..315a125273 100644 --- a/bindings/wasm/src/credential/presentation.rs +++ b/bindings/wasm/src/credential/presentation.rs @@ -8,8 +8,8 @@ use identity::credential::Presentation; use identity::credential::PresentationBuilder; use wasm_bindgen::prelude::*; -use crate::utils::err; use crate::did::WasmDocument; +use crate::utils::err; #[wasm_bindgen(inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/did/wasm_document.rs b/bindings/wasm/src/did/wasm_document.rs index 1f3c59c29d..340599007c 100644 --- a/bindings/wasm/src/did/wasm_document.rs +++ b/bindings/wasm/src/did/wasm_document.rs @@ -24,10 +24,10 @@ use crate::credential::VerifiableCredential; use crate::credential::VerifiablePresentation; use crate::crypto::KeyPair; use crate::crypto::KeyType; -use crate::service::Service; -use crate::utils::err; use crate::did::WasmDID; use crate::did::WasmVerificationMethod; +use crate::service::Service; +use crate::utils::err; #[wasm_bindgen(inspectable)] pub struct NewDocument { diff --git a/bindings/wasm/src/did/wasm_verification_method.rs b/bindings/wasm/src/did/wasm_verification_method.rs index 2b46e31b2c..6c03ec0716 100644 --- a/bindings/wasm/src/did/wasm_verification_method.rs +++ b/bindings/wasm/src/did/wasm_verification_method.rs @@ -10,8 +10,8 @@ use wasm_bindgen::prelude::*; use crate::crypto::Digest; use crate::crypto::KeyCollection; use crate::crypto::KeyPair; -use crate::utils::err; use crate::did::WasmDID; +use crate::utils::err; #[wasm_bindgen(js_name = VerificationMethod, inspectable)] #[derive(Clone, Debug, PartialEq)] diff --git a/bindings/wasm/src/tangle/client.rs b/bindings/wasm/src/tangle/client.rs index 86110574d9..c8a2d88be0 100644 --- a/bindings/wasm/src/tangle/client.rs +++ b/bindings/wasm/src/tangle/client.rs @@ -11,19 +11,19 @@ use identity::iota::CredentialValidator; use identity::iota::DocumentDiff; use identity::iota::IotaDID; use identity::iota::IotaDocument; +use identity::iota::IotaVerificationMethod; use identity::iota::MessageId; use identity::iota::TangleRef; use identity::iota::TangleResolve; -use identity::iota::IotaVerificationMethod; use js_sys::Promise; use std::rc::Rc; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::future_to_promise; +use crate::did::WasmVerificationMethod; use crate::tangle::Config; use crate::tangle::WasmNetwork; use crate::utils::err; -use crate::did::WasmVerificationMethod; #[wasm_bindgen] #[derive(Debug)] From 894b125f7992a758602fb82e381dcd34b4b69ad5 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Thu, 5 Aug 2021 23:25:09 +0200 Subject: [PATCH 07/32] add did-history node example --- bindings/wasm/examples/node/history.js | 31 +++++++++++++++ bindings/wasm/examples/node/node.js | 55 ++++++++++++++------------ 2 files changed, 61 insertions(+), 25 deletions(-) create mode 100644 bindings/wasm/examples/node/history.js diff --git a/bindings/wasm/examples/node/history.js b/bindings/wasm/examples/node/history.js new file mode 100644 index 0000000000..13a6215c4e --- /dev/null +++ b/bindings/wasm/examples/node/history.js @@ -0,0 +1,31 @@ +// Copyright 2020-2021 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +const { Client, Config } = require('../../node/identity_wasm') +const { manipulateIdentity } = require("./manipulate_did"); +const { CLIENT_CONFIG } = require("./config"); + +/* + + @param {{network: string, node: string}} clientConfig +*/ +async function resolveHistory(clientConfig) { + // Create a default client configuration from the parent config network. + const config = Config.fromNetwork(clientConfig.network); + + // Create a client instance to publish messages to the Tangle. + const client = Client.fromConfig(config); + + // Creates a new identity, that also is updated (See "manipulate_did" example). + const result = await manipulateIdentity(clientConfig); + + console.log(result) + const chain = await client.resolveHistory(result.doc.id.toString()) + + console.log(chain); + console.log(chain.intChainData.history); +} + +resolveHistory(CLIENT_CONFIG) + +// exports.resolveHistory = resolveHistory; diff --git a/bindings/wasm/examples/node/node.js b/bindings/wasm/examples/node/node.js index 022272e91b..500f0f848b 100644 --- a/bindings/wasm/examples/node/node.js +++ b/bindings/wasm/examples/node/node.js @@ -1,39 +1,42 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -const { createIdentity } = require('./create_did'); -const { manipulateIdentity } = require('./manipulate_did'); -const { resolution } = require('./resolution'); -const { createVC } = require('./create_vc'); -const { createVP } = require('./create_vp'); -const { revokeVC } = require('./revocation'); -const { merkleKey } = require('./merkle_key'); -const { CLIENT_CONFIG } = require('./config') +const { createIdentity } = require("./create_did"); +const { manipulateIdentity } = require("./manipulate_did"); +const { resolution } = require("./resolution"); +const { createVC } = require("./create_vc"); +const { createVP } = require("./create_vp"); +const { revokeVC } = require("./revocation"); +const { merkleKey } = require("./merkle_key"); +const { resolveHistory } = require("./history"); +const { CLIENT_CONFIG } = require("./config"); async function main() { //Check if an example is mentioned - if(process.argv.length != 3) { - throw 'Please provide one command line argument with the example name.'; + if (process.argv.length != 3) { + throw "Please provide one command line argument with the example name."; } //Take out the argument let argument = process.argv[2]; - switch(argument) { - case 'create_did': + switch (argument) { + case "create_did": return await createIdentity(CLIENT_CONFIG); - case 'manipulate_did': + case "manipulate_did": return await manipulateIdentity(CLIENT_CONFIG); - case 'resolution': + case "resolution": return await resolution(CLIENT_CONFIG); - case 'create_vc': + case "create_vc": return await createVC(CLIENT_CONFIG); - case 'revocation': + case "revocation": return await revokeVC(CLIENT_CONFIG); - case 'create_vp': + case "create_vp": return await createVP(CLIENT_CONFIG); - case 'merkle_key': + case "merkle_key": return await merkleKey(CLIENT_CONFIG); - case 'all': + case "resolve_history": + return await resolveHistory(CLIENT_CONFIG); + case "all": console.log(">>> Run All Examples"); await createIdentity(CLIENT_CONFIG); @@ -46,12 +49,14 @@ async function main() { console.log(">>> End All Examples"); default: - throw 'Unknown example name'; + throw "Unknown example name"; } } -main().then((output) => { - console.log("Ok >", output) -}).catch((error) => { - console.log("Err >", error) -}) +main() + .then((output) => { + console.log("Ok >", output); + }) + .catch((error) => { + console.log("Err >", error); + }); From 981329924c825a2dba54c40d3f3475a4a5bed64e Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Fri, 6 Aug 2021 00:12:55 +0200 Subject: [PATCH 08/32] fix did-history node example --- bindings/wasm/examples/node/history.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/bindings/wasm/examples/node/history.js b/bindings/wasm/examples/node/history.js index 13a6215c4e..a40b1a93fa 100644 --- a/bindings/wasm/examples/node/history.js +++ b/bindings/wasm/examples/node/history.js @@ -1,12 +1,14 @@ // Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -const { Client, Config } = require('../../node/identity_wasm') +const { Client, Config } = require("../../node/identity_wasm"); const { manipulateIdentity } = require("./manipulate_did"); const { CLIENT_CONFIG } = require("./config"); /* - + An example for resolving the integration-message-history of a DID. + The history is usually only useful for debugging puropses. + @param {{network: string, node: string}} clientConfig */ async function resolveHistory(clientConfig) { @@ -19,13 +21,9 @@ async function resolveHistory(clientConfig) { // Creates a new identity, that also is updated (See "manipulate_did" example). const result = await manipulateIdentity(clientConfig); - console.log(result) - const chain = await client.resolveHistory(result.doc.id.toString()) + const chain = await client.resolveHistory(result.doc.id.toString()); - console.log(chain); - console.log(chain.intChainData.history); + return chain; } -resolveHistory(CLIENT_CONFIG) - -// exports.resolveHistory = resolveHistory; +exports.resolveHistory = resolveHistory; From a02dc5ac0805f2916cd97f3923c7814458e1e300 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Fri, 6 Aug 2021 00:14:03 +0200 Subject: [PATCH 09/32] add did-history browser example --- bindings/wasm/examples/browser/history.js | 30 +++++++++++++++++++++++ bindings/wasm/examples/browser/index.html | 5 ++++ bindings/wasm/examples/browser/main.js | 6 +++++ bindings/wasm/examples/node/node.js | 1 + 4 files changed, 42 insertions(+) create mode 100644 bindings/wasm/examples/browser/history.js diff --git a/bindings/wasm/examples/browser/history.js b/bindings/wasm/examples/browser/history.js new file mode 100644 index 0000000000..fb184b9be1 --- /dev/null +++ b/bindings/wasm/examples/browser/history.js @@ -0,0 +1,30 @@ +import * as identity from "../../web/identity_wasm.js"; +import { logObjectToScreen, logToScreen } from "./utils.js"; +import { manipulateIdentity } from "./mainpulate_did.js"; + +/** + + An example for resolving the integration-message-history of a DID. + The history is usually only useful for debugging puropses. + + @param {{network: string, node: string}} clientConfig + @param {boolean} log log the to the output window +*/ +export async function resolveHistory(clientConfig, log = true) { + + if (log) logToScreen("resolve history..."); + + // Create a default client configuration from network. + const config = identity.Config.fromNetwork(clientConfig.network); + + // Create a client instance to publish messages to the Tangle. + const client = identity.Client.fromConfig(config); + + // Creates a new identity, that also is updated (See "manipulate_did" example). + const did = await manipulateIdentity(clientConfig, false); + + const res = await client.resolveHistory(did.doc.id.toString()); + + if (log) logObjectToScreen(res); + return res; +} diff --git a/bindings/wasm/examples/browser/index.html b/bindings/wasm/examples/browser/index.html index 41fb7ee1f7..5b6ccf14c9 100644 --- a/bindings/wasm/examples/browser/index.html +++ b/bindings/wasm/examples/browser/index.html @@ -46,6 +46,11 @@ + + + + + + +