diff --git a/Cargo.toml b/Cargo.toml index 5ee3b519d9..0a2ba21ebb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,11 @@ members = [ "identity_credential", "identity_did", "identity_diff", + "identity_document", "identity_iota", "identity_iota_core", "identity_resolver", + "identity_verification", "examples", ] @@ -22,3 +24,16 @@ exclude = [ [profile.dev] split-debuginfo = "unpacked" + +[workspace.dependencies] +serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +thiserror = { version = "1.0", default-features = false } +strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } + +[workspace.package] +authors = ["IOTA Stiftung"] +edition = "2021" +homepage = "https://www.iota.org" +license = "Apache-2.0" +repository = "https://github.com/iotaledger/identity.rs" +rust-version = "1.65" diff --git a/bindings/stronghold-nodejs/src/stronghold.rs b/bindings/stronghold-nodejs/src/stronghold.rs index de9be2744e..c19e2f0f5f 100644 --- a/bindings/stronghold-nodejs/src/stronghold.rs +++ b/bindings/stronghold-nodejs/src/stronghold.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_account_storage::storage::Storage; @@ -7,7 +7,7 @@ use identity_account_storage::types::EncryptedData; use identity_account_storage::types::KeyLocation; use identity_core::crypto::PrivateKey; use identity_core::crypto::PublicKey; -use identity_did::did::CoreDID; +use identity_did::CoreDID; use identity_iota_core_legacy::tangle::NetworkName; use napi::bindgen_prelude::Error; use napi::Result; diff --git a/bindings/stronghold-nodejs/src/types/derive.rs b/bindings/stronghold-nodejs/src/types/derive.rs index c6991f4cec..94a67e0950 100644 --- a/bindings/stronghold-nodejs/src/types/derive.rs +++ b/bindings/stronghold-nodejs/src/types/derive.rs @@ -7,7 +7,7 @@ use identity_account_storage::types::EncryptedData; use identity_account_storage::types::EncryptionAlgorithm; use identity_account_storage::types::KeyLocation; use identity_account_storage::types::Signature; -use identity_did::did::CoreDID; +use identity_did::CoreDID; use identity_iota_core_legacy::document::IotaDocument; use napi::Result; use napi_derive::napi; diff --git a/bindings/stronghold-nodejs/src/types/did_location_tuple.rs b/bindings/stronghold-nodejs/src/types/did_location_tuple.rs index dd5a23e1d1..edb18fc071 100644 --- a/bindings/stronghold-nodejs/src/types/did_location_tuple.rs +++ b/bindings/stronghold-nodejs/src/types/did_location_tuple.rs @@ -1,8 +1,8 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_account_storage::types::KeyLocation; -use identity_did::did::CoreDID; +use identity_did::CoreDID; use napi::Result; use napi_derive::napi; diff --git a/bindings/wasm/src/credential/credential_builder.rs b/bindings/wasm/src/credential/credential_builder.rs index 1aa8c0ecac..50ef9b6f96 100644 --- a/bindings/wasm/src/credential/credential_builder.rs +++ b/bindings/wasm/src/credential/credential_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::core::Context; @@ -49,7 +49,7 @@ impl TryFrom for CredentialBuilder { } } if let Some(id) = id { - builder = builder.id(Url::parse(&id).wasm_result()?); + builder = builder.id(Url::parse(id).wasm_result()?); } if let Some(types) = r#type { for value in types.iter() { diff --git a/bindings/wasm/src/credential/presentation_builder.rs b/bindings/wasm/src/credential/presentation_builder.rs index f93cccb6bf..793184ad8c 100644 --- a/bindings/wasm/src/credential/presentation_builder.rs +++ b/bindings/wasm/src/credential/presentation_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::core::Context; @@ -37,7 +37,7 @@ impl TryFrom for PresentationBuilder { } } if let Some(id) = id { - builder = builder.id(Url::parse(&id).wasm_result()?); + builder = builder.id(Url::parse(id).wasm_result()?); } if let Some(types) = r#type { for value in types.iter() { diff --git a/bindings/wasm/src/credential/validation_options.rs b/bindings/wasm/src/credential/validation_options.rs index 69974784f2..f5384f65c9 100644 --- a/bindings/wasm/src/credential/validation_options.rs +++ b/bindings/wasm/src/credential/validation_options.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::credential::CredentialValidationOptions; @@ -29,6 +29,7 @@ impl WasmCredentialValidationOptions { } /// Creates a new `CredentialValidationOptions` with defaults. + #[allow(clippy::should_implement_trait)] #[wasm_bindgen] pub fn default() -> WasmCredentialValidationOptions { WasmCredentialValidationOptions::from(CredentialValidationOptions::default()) @@ -66,6 +67,7 @@ impl WasmPresentationValidationOptions { } /// Creates a new `PresentationValidationOptions` with defaults. + #[allow(clippy::should_implement_trait)] #[wasm_bindgen] pub fn default() -> WasmPresentationValidationOptions { WasmPresentationValidationOptions::from(PresentationValidationOptions::default()) diff --git a/bindings/wasm/src/crypto/wasm_proof_options.rs b/bindings/wasm/src/crypto/wasm_proof_options.rs index 69b5ecdfb0..3262ca77e4 100644 --- a/bindings/wasm/src/crypto/wasm_proof_options.rs +++ b/bindings/wasm/src/crypto/wasm_proof_options.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::crypto::ProofOptions; @@ -24,6 +24,7 @@ impl WasmProofOptions { } /// Creates a new `ProofOptions` with default options. + #[allow(clippy::should_implement_trait)] #[wasm_bindgen] pub fn default() -> WasmProofOptions { WasmProofOptions::from(ProofOptions::default()) diff --git a/bindings/wasm/src/did/service_common.rs b/bindings/wasm/src/did/service_common.rs index 517d2cb906..02cb6369b5 100644 --- a/bindings/wasm/src/did/service_common.rs +++ b/bindings/wasm/src/did/service_common.rs @@ -1,7 +1,7 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::ServiceEndpoint; +use identity_iota::document::ServiceEndpoint; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; diff --git a/bindings/wasm/src/did/wasm_core_document.rs b/bindings/wasm/src/did/wasm_core_document.rs index 54e5b7ee63..019945ce36 100644 --- a/bindings/wasm/src/did/wasm_core_document.rs +++ b/bindings/wasm/src/did/wasm_core_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use super::WasmCoreDID; @@ -21,16 +21,17 @@ use identity_iota::core::OneOrMany; use identity_iota::core::OneOrSet; use identity_iota::core::OrderedSet; use identity_iota::core::Url; +use identity_iota::credential::RevocationDocumentExt; use identity_iota::crypto::PrivateKey; use identity_iota::crypto::ProofOptions; -use identity_iota::did::verifiable::VerifiableProperties; use identity_iota::did::CoreDID; -use identity_iota::did::CoreDocument; -use identity_iota::did::Document; -use identity_iota::did::MethodRef; -use identity_iota::did::MethodScope; -use identity_iota::did::Service; -use identity_iota::did::VerificationMethod; +use identity_iota::document::verifiable::VerifiableProperties; +use identity_iota::document::CoreDocument; +use identity_iota::document::Document; +use identity_iota::document::Service; +use identity_iota::verification::MethodRef; +use identity_iota::verification::MethodScope; +use identity_iota::verification::VerificationMethod; use proc_typescript::typescript; use wasm_bindgen::prelude::*; diff --git a/bindings/wasm/src/did/wasm_core_service.rs b/bindings/wasm/src/did/wasm_core_service.rs index e4c3a9689f..60eb4f64f9 100644 --- a/bindings/wasm/src/did/wasm_core_service.rs +++ b/bindings/wasm/src/did/wasm_core_service.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::common::deserialize_map_or_any; @@ -11,8 +11,8 @@ use crate::error::Result; use crate::error::WasmResult; use identity_iota::core::OneOrMany; use identity_iota::did::CoreDIDUrl; -use identity_iota::did::Service; -use identity_iota::did::ServiceEndpoint; +use identity_iota::document::Service; +use identity_iota::document::ServiceEndpoint; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; diff --git a/bindings/wasm/src/did/wasm_core_verification_method.rs b/bindings/wasm/src/did/wasm_core_verification_method.rs index 9398c417f5..7096153f36 100644 --- a/bindings/wasm/src/did/wasm_core_verification_method.rs +++ b/bindings/wasm/src/did/wasm_core_verification_method.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::common::MapStringAny; @@ -10,7 +10,7 @@ use crate::did::WasmMethodType; use crate::error::Result; use crate::error::WasmResult; use identity_iota::crypto::PublicKey; -use identity_iota::did::VerificationMethod; +use identity_iota::verification::VerificationMethod; use wasm_bindgen::prelude::*; /// A DID Document Verification Method. diff --git a/bindings/wasm/src/did/wasm_method_data.rs b/bindings/wasm/src/did/wasm_method_data.rs index d040fbebf7..97e663e020 100644 --- a/bindings/wasm/src/did/wasm_method_data.rs +++ b/bindings/wasm/src/did/wasm_method_data.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::MethodData; +use identity_iota::verification::MethodData; use wasm_bindgen::prelude::*; use crate::error::Result; diff --git a/bindings/wasm/src/did/wasm_method_relationship.rs b/bindings/wasm/src/did/wasm_method_relationship.rs index 2cc3238fbb..2e9b4307d6 100644 --- a/bindings/wasm/src/did/wasm_method_relationship.rs +++ b/bindings/wasm/src/did/wasm_method_relationship.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::MethodRelationship; +use identity_iota::verification::MethodRelationship; use serde_repr::Deserialize_repr; use serde_repr::Serialize_repr; use wasm_bindgen::prelude::*; diff --git a/bindings/wasm/src/did/wasm_method_scope.rs b/bindings/wasm/src/did/wasm_method_scope.rs index 8764b342bb..a7c775dc0b 100644 --- a/bindings/wasm/src/did/wasm_method_scope.rs +++ b/bindings/wasm/src/did/wasm_method_scope.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::MethodScope; +use identity_iota::verification::MethodScope; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/bindings/wasm/src/did/wasm_method_type.rs b/bindings/wasm/src/did/wasm_method_type.rs index 7256e43f6a..e7fd932476 100644 --- a/bindings/wasm/src/did/wasm_method_type.rs +++ b/bindings/wasm/src/did/wasm_method_type.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::MethodType; +use identity_iota::verification::MethodType; use wasm_bindgen::prelude::*; /// Supported verification method types. diff --git a/bindings/wasm/src/did/wasm_verifier_options.rs b/bindings/wasm/src/did/wasm_verifier_options.rs index 71fdbee98e..6c0049659e 100644 --- a/bindings/wasm/src/did/wasm_verifier_options.rs +++ b/bindings/wasm/src/did/wasm_verifier_options.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::verifiable::VerifierOptions; +use identity_iota::document::verifiable::VerifierOptions; use wasm_bindgen::prelude::*; use crate::error::Result; @@ -24,6 +24,7 @@ impl WasmVerifierOptions { } /// Creates a new `VerifierOptions` with default options. + #[allow(clippy::should_implement_trait)] #[wasm_bindgen] pub fn default() -> WasmVerifierOptions { WasmVerifierOptions(VerifierOptions::default()) diff --git a/bindings/wasm/src/error.rs b/bindings/wasm/src/error.rs index afa05c5131..7d47ed2b0d 100644 --- a/bindings/wasm/src/error.rs +++ b/bindings/wasm/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::resolver; @@ -90,9 +90,11 @@ impl_wasm_error_from!( identity_iota::core::Error, identity_iota::credential::Error, identity_iota::did::Error, - identity_iota::did::DIDError, + identity_iota::document::Error, identity_iota::iota::Error, - identity_iota::credential::ValidationError + identity_iota::credential::ValidationError, + identity_iota::credential::RevocationError, + identity_iota::verification::Error ); // Similar to `impl_wasm_error_from`, but uses the types name instead of requiring/calling Into &'static str diff --git a/bindings/wasm/src/iota/iota_did.rs b/bindings/wasm/src/iota/iota_did.rs index 423b047102..3db351f58b 100644 --- a/bindings/wasm/src/iota/iota_did.rs +++ b/bindings/wasm/src/iota/iota_did.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::did::DIDError; +use identity_iota::did::Error as DIDError; use identity_iota::did::DID; use identity_iota::iota::IotaDID; use identity_iota::iota::NetworkName; diff --git a/bindings/wasm/src/iota/iota_document.rs b/bindings/wasm/src/iota/iota_document.rs index 9b3a994694..3ce91c5be6 100644 --- a/bindings/wasm/src/iota/iota_document.rs +++ b/bindings/wasm/src/iota/iota_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::core::OneOrMany; @@ -9,9 +9,8 @@ use identity_iota::credential::Credential; use identity_iota::credential::Presentation; use identity_iota::crypto::PrivateKey; use identity_iota::crypto::ProofOptions; -use identity_iota::did::verifiable::VerifiableProperties; -use identity_iota::did::Document; -use identity_iota::did::MethodScope; +use identity_iota::document::verifiable::VerifiableProperties; +use identity_iota::document::Document; use identity_iota::iota::block::output::dto::AliasOutputDto; use identity_iota::iota::block::output::AliasOutput; use identity_iota::iota::IotaDID; @@ -19,6 +18,7 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; use identity_iota::iota::StateMetadataEncoding; +use identity_iota::verification::MethodScope; use iota_types::block::protocol::dto::ProtocolParametersDto; use iota_types::block::protocol::ProtocolParameters; use wasm_bindgen::prelude::*; diff --git a/bindings/wasm/src/iota/iota_service.rs b/bindings/wasm/src/iota/iota_service.rs index 0f930c60dc..262857e0df 100644 --- a/bindings/wasm/src/iota/iota_service.rs +++ b/bindings/wasm/src/iota/iota_service.rs @@ -1,8 +1,8 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota::core::OneOrMany; -use identity_iota::did::ServiceEndpoint; +use identity_iota::document::ServiceEndpoint; use identity_iota::iota::IotaDIDUrl; use identity_iota::iota::IotaService; use wasm_bindgen::prelude::*; diff --git a/bindings/wasm/src/resolver/supported_document_types.rs b/bindings/wasm/src/resolver/supported_document_types.rs index 63d98c586d..adaf54b626 100644 --- a/bindings/wasm/src/resolver/supported_document_types.rs +++ b/bindings/wasm/src/resolver/supported_document_types.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::did::WasmCoreDID; @@ -9,8 +9,8 @@ use crate::iota::WasmIotaDID; use crate::iota::WasmIotaDocument; use identity_iota::credential::AbstractValidatorDocument; use identity_iota::did::CoreDID; -use identity_iota::did::CoreDocument; use identity_iota::did::DID; +use identity_iota::document::CoreDocument; use identity_iota::iota::IotaDID; use identity_iota::iota::IotaDocument; use serde::Deserialize; diff --git a/bindings/wasm/src/revocation/bitmap.rs b/bindings/wasm/src/revocation/bitmap.rs index efef9111f9..4c20ca4e57 100644 --- a/bindings/wasm/src/revocation/bitmap.rs +++ b/bindings/wasm/src/revocation/bitmap.rs @@ -1,10 +1,10 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::borrow::Cow; -use identity_iota::did::RevocationBitmap; -use identity_iota::did::ServiceEndpoint; +use identity_iota::credential::RevocationBitmap; +use identity_iota::document::ServiceEndpoint; use wasm_bindgen::prelude::*; use crate::did::UServiceEndpoint; diff --git a/examples/0_basic/0_create_did.rs b/examples/0_basic/0_create_did.rs index 7a4efa1d16..e4baa7eead 100644 --- a/examples/0_basic/0_create_did.rs +++ b/examples/0_basic/0_create_did.rs @@ -1,16 +1,16 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use examples::get_address_with_funds; use examples::random_stronghold_path; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; -use identity_iota::did::MethodScope; use identity_iota::iota::IotaClientExt; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; +use identity_iota::verification::MethodScope; use iota_client::block::address::Address; use iota_client::block::output::AliasOutput; use iota_client::secret::stronghold::StrongholdSecretManager; diff --git a/examples/0_basic/1_update_did.rs b/examples/0_basic/1_update_did.rs index 8b24a4266b..7a8ae77ff5 100644 --- a/examples/0_basic/1_update_did.rs +++ b/examples/0_basic/1_update_did.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use examples::create_did; @@ -10,11 +10,9 @@ use identity_iota::core::Timestamp; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; use identity_iota::did::DIDUrl; -use identity_iota::did::Document; -use identity_iota::did::MethodRelationship; -use identity_iota::did::MethodScope; -use identity_iota::did::Service; use identity_iota::did::DID; +use identity_iota::document::Document; +use identity_iota::document::Service; use identity_iota::iota::block::address::Address; use identity_iota::iota::block::output::RentStructure; use identity_iota::iota::IotaClientExt; @@ -23,6 +21,8 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaService; use identity_iota::iota::IotaVerificationMethod; +use identity_iota::verification::MethodRelationship; +use identity_iota::verification::MethodScope; use iota_client::block::output::AliasOutput; use iota_client::block::output::AliasOutputBuilder; use iota_client::secret::stronghold::StrongholdSecretManager; diff --git a/examples/0_basic/6_create_vp.rs b/examples/0_basic/6_create_vp.rs index 73bb9e3c4b..eb2712fb77 100644 --- a/examples/0_basic/6_create_vp.rs +++ b/examples/0_basic/6_create_vp.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! This example shows how to create a Verifiable Presentation and validate it. @@ -33,8 +33,8 @@ use identity_iota::credential::Subject; use identity_iota::credential::SubjectHolderRelationship; use identity_iota::crypto::KeyPair; use identity_iota::crypto::ProofOptions; -use identity_iota::did::verifiable::VerifierOptions; use identity_iota::did::DID; +use identity_iota::document::verifiable::VerifierOptions; use identity_iota::iota::IotaDocument; use identity_iota::resolver::Resolver; diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index 257235a55c..f67922cabd 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! This example shows how to revoke a verifiable credential. @@ -21,6 +21,7 @@ use identity_iota::credential::CredentialBuilder; use identity_iota::credential::CredentialValidationOptions; use identity_iota::credential::CredentialValidator; use identity_iota::credential::FailFast; +use identity_iota::credential::RevocationBitmap; use identity_iota::credential::RevocationBitmapStatus; use identity_iota::credential::Status; use identity_iota::credential::Subject; @@ -28,10 +29,9 @@ use identity_iota::credential::ValidationError; use identity_iota::crypto::KeyPair; use identity_iota::crypto::ProofOptions; use identity_iota::did::DIDUrl; -use identity_iota::did::Document; -use identity_iota::did::RevocationBitmap; -use identity_iota::did::Service; use identity_iota::did::DID; +use identity_iota::document::Document; +use identity_iota::document::Service; use identity_iota::iota::IotaClientExt; use identity_iota::iota::IotaDID; use identity_iota::iota::IotaDocument; diff --git a/examples/1_advanced/0_did_controls_did.rs b/examples/1_advanced/0_did_controls_did.rs index 35050f902d..65f6ebf277 100644 --- a/examples/1_advanced/0_did_controls_did.rs +++ b/examples/1_advanced/0_did_controls_did.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::ops::Deref; @@ -8,7 +8,6 @@ use examples::random_stronghold_path; use examples::API_ENDPOINT; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; -use identity_iota::did::MethodScope; use identity_iota::iota::block::output::AliasId; use identity_iota::iota::block::output::UnlockCondition; use identity_iota::iota::IotaClientExt; @@ -17,6 +16,7 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; +use identity_iota::verification::MethodScope; use iota_client::block::address::Address; use iota_client::block::address::AliasAddress; use iota_client::block::output::feature::IssuerFeature; diff --git a/examples/1_advanced/4_key_exchange.rs b/examples/1_advanced/4_key_exchange.rs index 0062c64ad4..84355e2f2f 100644 --- a/examples/1_advanced/4_key_exchange.rs +++ b/examples/1_advanced/4_key_exchange.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use anyhow::Context; @@ -9,7 +9,6 @@ use examples::FAUCET_ENDPOINT; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; use identity_iota::crypto::X25519; -use identity_iota::did::MethodScope; use identity_iota::iota::block::address::Address; use identity_iota::iota::block::output::AliasOutput; use identity_iota::iota::block::output::RentStructure; @@ -19,6 +18,7 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; +use identity_iota::verification::MethodScope; use iota_client::secret::stronghold::StrongholdSecretManager; use iota_client::secret::SecretManager; use iota_client::Client; diff --git a/examples/1_advanced/5_alias_output_history.rs b/examples/1_advanced/5_alias_output_history.rs index 49c576ae02..3fcd2d1a07 100644 --- a/examples/1_advanced/5_alias_output_history.rs +++ b/examples/1_advanced/5_alias_output_history.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -11,9 +11,8 @@ use identity_iota::core::json; use identity_iota::core::FromJson; use identity_iota::core::Timestamp; use identity_iota::crypto::KeyPair; -use identity_iota::did::MethodRelationship; -use identity_iota::did::Service; use identity_iota::did::DID; +use identity_iota::document::Service; use identity_iota::iota::block::address::Address; use identity_iota::iota::block::output::RentStructure; use identity_iota::iota::IotaClientExt; @@ -22,6 +21,7 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClient; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaService; +use identity_iota::verification::MethodRelationship; use iota_client::api_types::response::OutputMetadataResponse; use iota_client::block::input::Input; use iota_client::block::output::AliasId; diff --git a/examples/1_advanced/6_custom_resolution.rs b/examples/1_advanced/6_custom_resolution.rs index 7eecb86639..6417577fce 100644 --- a/examples/1_advanced/6_custom_resolution.rs +++ b/examples/1_advanced/6_custom_resolution.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use examples::create_did; @@ -9,7 +9,7 @@ use identity_iota::core::ToJson; use identity_iota::credential::AbstractThreadSafeValidatorDocument; use identity_iota::crypto::KeyPair as IotaKeyPair; use identity_iota::did::CoreDID; -use identity_iota::did::CoreDocument; +use identity_iota::document::CoreDocument; use identity_iota::iota::IotaDID; use identity_iota::iota::IotaDocument; use identity_iota::resolver::Resolver; diff --git a/examples/utils/utils.rs b/examples/utils/utils.rs index 7ca2c3c8c1..0306c5b34e 100644 --- a/examples/utils/utils.rs +++ b/examples/utils/utils.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::PathBuf; @@ -7,12 +7,12 @@ use anyhow::Context; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; -use identity_iota::did::MethodScope; use identity_iota::iota::IotaClientExt; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; +use identity_iota::verification::MethodScope; use iota_client::block::address::Address; use iota_client::block::output::AliasOutput; diff --git a/identity_account_storage/src/stronghold/client_path.rs b/identity_account_storage/src/stronghold/client_path.rs index d70448bef3..08a0f66200 100644 --- a/identity_account_storage/src/stronghold/client_path.rs +++ b/identity_account_storage/src/stronghold/client_path.rs @@ -1,7 +1,7 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_did::did::CoreDID; +use identity_did::CoreDID; use identity_iota_core_legacy::did::IotaDID; /// A helper type to ensure a consistently generated client path, for DIDs and strings diff --git a/identity_account_storage/src/stronghold/wrapper.rs b/identity_account_storage/src/stronghold/wrapper.rs index 54954de01e..7bdc6902c5 100644 --- a/identity_account_storage/src/stronghold/wrapper.rs +++ b/identity_account_storage/src/stronghold/wrapper.rs @@ -1,9 +1,9 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::path::Path; -use identity_did::did::CoreDID; +use identity_did::CoreDID; use iota_stronghold::Client; use iota_stronghold::ClientError; use iota_stronghold::KeyProvider; diff --git a/identity_agent/Cargo.toml b/identity_agent/Cargo.toml index bdf7c69592..6343625192 100644 --- a/identity_agent/Cargo.toml +++ b/identity_agent/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "identity_agent" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] -edition = "2021" -homepage = "https://www.iota.org" +authors.workspace = true +edition.workspace = true +homepage.workspace = true keywords = ["iota", "tangle", "identity", "p2p", "agent"] -license = "Apache-2.0" +license.workspace = true publish = false readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" +repository.workspace = true description = "A peer-to-peer communication framework for building SSI agents on IOTA Identity" [dependencies] diff --git a/identity_core/Cargo.toml b/identity_core/Cargo.toml index e09ee53349..d94c41a984 100644 --- a/identity_core/Cargo.toml +++ b/identity_core/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "identity_core" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] -edition = "2021" -homepage = "https://www.iota.org" +authors.workspace = true +edition.workspace = true +homepage.workspace = true keywords = ["iota", "tangle", "identity"] -license = "Apache-2.0" +license.workspace = true readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" +repository.workspace = true +rust-version.workspace = true description = "The core traits and types for the identity-rs library." [dependencies] diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml index 15cf85c635..a44de22aa2 100644 --- a/identity_credential/Cargo.toml +++ b/identity_credential/Cargo.toml @@ -3,24 +3,29 @@ name = "identity_credential" version = "0.7.0-alpha.4" authors = ["IOTA Stiftung"] edition = "2021" -homepage = "https://www.iota.org" +homepage.workspace = true keywords = ["iota", "tangle", "identity"] -license = "Apache-2.0" +license.workspace = true readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" -rust-version = "1.62" +repository.workspace = true +rust-version.workspace = true description = "An implementation of the Verifiable Credentials standard." [dependencies] +dataurl = { version = "0.1.2", default-features = false, optional = true } erased-serde = { version = "0.3.21", default-features = false, features = ["std"], optional = true } +flate2 = { version = "1.0.23", default-features = false, features = ["rust_backend"], optional = true } identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core", default-features = false } identity_did = { version = "=0.7.0-alpha.4", path = "../identity_did", default-features = false } +identity_document = { version = "=0.7.0-alpha.4", path = "../identity_document", default-features = false } +identity_verification = { version = "=0.7.0-alpha.4", path = "../identity_verification", default-features = false } itertools = { version = "0.10", default-features = false, features = ["use_std"], optional = true } lazy_static = { version = "1.4", default-features = false } -serde = { version = "1.0", default-features = false, features = ["std", "derive"] } +roaring = { version = "0.9.0", default-features = false, optional = true } +serde.workspace = true serde_repr = { version = "0.1", default-features = false, optional = true } -strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } -thiserror = { version = "1.0", default-features = false } +strum.workspace = true +thiserror.workspace = true [dev-dependencies] proptest = { version = "1.0.0", default-features = false, features = ["std"] } @@ -33,6 +38,8 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] -default = ["revocation-bitmap", "validator"] -revocation-bitmap = ["identity_did/revocation-bitmap"] -validator = ["dep:itertools", "dep:erased-serde", "dep:serde_repr"] +default = ["revocation-bitmap", "validator", "credential", "presentation"] +credential = [] +presentation = ["credential"] +revocation-bitmap = ["dep:dataurl", "dep:flate2", "dep:roaring"] +validator = ["dep:itertools", "dep:erased-serde", "dep:serde_repr", "credential", "presentation"] diff --git a/identity_credential/src/credential/credential.rs b/identity_credential/src/credential/credential.rs index 677ba2f463..72343189e0 100644 --- a/identity_credential/src/credential/credential.rs +++ b/identity_credential/src/credential/credential.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -16,8 +16,8 @@ use identity_core::crypto::GetSignature; use identity_core::crypto::GetSignatureMut; use identity_core::crypto::Proof; use identity_core::crypto::SetSignature; -use identity_did::verification::MethodUriType; -use identity_did::verification::TryMethod; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; use crate::credential::CredentialBuilder; use crate::credential::Evidence; diff --git a/identity_credential/src/credential/revocation_bitmap_status.rs b/identity_credential/src/credential/revocation_bitmap_status.rs index 3810bac8df..bf11c0ed6d 100644 --- a/identity_credential/src/credential/revocation_bitmap_status.rs +++ b/identity_credential/src/credential/revocation_bitmap_status.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; @@ -6,8 +6,8 @@ use std::str::FromStr; use identity_core::common::Object; use identity_core::common::Url; use identity_core::common::Value; -use identity_did::did::DIDUrl; -use identity_did::did::DID; +use identity_did::DIDUrl; +use identity_did::DID; use crate::credential::Status; use crate::error::Error; @@ -31,8 +31,8 @@ impl RevocationBitmapStatus { /// /// ``` /// # use identity_credential::credential::RevocationBitmapStatus; - /// # use identity_did::did::DIDUrl; - /// # use identity_did::did::CoreDID; + /// # use identity_did::DIDUrl; + /// # use identity_did::CoreDID; /// let did_url: DIDUrl = DIDUrl::parse("did:method:0xffff#revocation-1").unwrap(); /// let status: RevocationBitmapStatus = RevocationBitmapStatus::new(did_url, 5); /// assert_eq!( @@ -144,8 +144,8 @@ mod tests { use identity_core::common::Url; use identity_core::common::Value; use identity_core::convert::FromJson; - use identity_did::did::CoreDID; - use identity_did::did::DIDUrl; + use identity_did::CoreDID; + use identity_did::DIDUrl; use crate::Error; diff --git a/identity_credential/src/lib.rs b/identity_credential/src/lib.rs index 11e39cce7f..039496274f 100644 --- a/identity_credential/src/lib.rs +++ b/identity_credential/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![forbid(unsafe_code)] @@ -23,9 +23,13 @@ extern crate serde; pub use self::error::Error; pub use self::error::Result; +#[cfg(feature = "credential")] pub mod credential; pub mod error; +#[cfg(feature = "presentation")] pub mod presentation; +#[cfg(feature = "revocation-bitmap")] +pub mod revocation; #[cfg(feature = "validator")] pub mod validator; diff --git a/identity_credential/src/presentation/builder.rs b/identity_credential/src/presentation/builder.rs index 956cc29996..408ed25bbc 100644 --- a/identity_credential/src/presentation/builder.rs +++ b/identity_credential/src/presentation/builder.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Context; @@ -141,14 +141,14 @@ mod tests { use identity_core::convert::FromJson; use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; - use identity_did::did::CoreDID; - use identity_did::did::DID; - use identity_did::document::CoreDocument; - use identity_did::document::DocumentBuilder; - use identity_did::verification::MethodBuilder; - use identity_did::verification::MethodData; - use identity_did::verification::MethodType; - use identity_did::verification::VerificationMethod; + use identity_did::CoreDID; + use identity_did::DID; + use identity_document::document::CoreDocument; + use identity_document::document::DocumentBuilder; + use identity_verification::MethodBuilder; + use identity_verification::MethodData; + use identity_verification::MethodType; + use identity_verification::VerificationMethod; use crate::credential::Credential; use crate::credential::CredentialBuilder; diff --git a/identity_credential/src/presentation/presentation.rs b/identity_credential/src/presentation/presentation.rs index 1fa5291b5b..865f53aff6 100644 --- a/identity_credential/src/presentation/presentation.rs +++ b/identity_credential/src/presentation/presentation.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -15,8 +15,8 @@ use identity_core::crypto::GetSignature; use identity_core::crypto::GetSignatureMut; use identity_core::crypto::Proof; use identity_core::crypto::SetSignature; -use identity_did::verification::MethodUriType; -use identity_did::verification::TryMethod; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; use crate::credential::Credential; use crate::credential::Policy; diff --git a/identity_did/src/revocation/bitmap.rs b/identity_credential/src/revocation/bitmap.rs similarity index 69% rename from identity_did/src/revocation/bitmap.rs rename to identity_credential/src/revocation/bitmap.rs index 984274de63..c2ef8ac2c2 100644 --- a/identity_did/src/revocation/bitmap.rs +++ b/identity_credential/src/revocation/bitmap.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::io::Write; @@ -12,11 +12,10 @@ use identity_core::utils::Base; use identity_core::utils::BaseEncoding; use roaring::RoaringBitmap; -use crate::did::DID; -use crate::error::Error; -use crate::error::Result; -use crate::service::Service; -use crate::service::ServiceEndpoint; +use super::error::RevocationError; +use identity_did::DID; +use identity_document::service::Service; +use identity_document::service::ServiceEndpoint; const DATA_URL_MEDIA_TYPE: &str = "application/octet-stream"; @@ -63,90 +62,102 @@ impl RevocationBitmap { } /// Return the bitmap as a data url embedded in a service endpoint. - pub fn to_endpoint(&self) -> Result { + pub fn to_endpoint(&self) -> Result { let endpoint_data: String = self.serialize_compressed_base64()?; let mut data_url: DataUrl = DataUrl::new(); data_url.set_media_type(Some(DATA_URL_MEDIA_TYPE.to_owned())); data_url.set_is_base64_encoded(true); data_url.set_data(endpoint_data.as_bytes()); - - Ok(ServiceEndpoint::One(Url::parse(data_url.to_string())?)) + Url::parse(data_url.to_string()) + .map(ServiceEndpoint::One) + .map_err(|e| RevocationError::UrlConstructionError(e.into())) } /// Construct a `RevocationBitmap` from a data url embedded in `service_endpoint`. - pub fn from_endpoint(service_endpoint: &ServiceEndpoint) -> Result { + pub fn from_endpoint(service_endpoint: &ServiceEndpoint) -> Result { if let ServiceEndpoint::One(url) = service_endpoint { - let data_url: DataUrl = - DataUrl::parse(url.as_str()).map_err(|_| Error::InvalidService("invalid url - expected a data url"))?; + let data_url: DataUrl = DataUrl::parse(url.as_str()) + .map_err(|_| RevocationError::InvalidService("invalid url - expected a data url"))?; if !data_url.get_is_base64_encoded() || data_url.get_media_type() != DATA_URL_MEDIA_TYPE { - return Err(Error::InvalidService( + return Err(RevocationError::InvalidService( "invalid url - expected an `application/octet-stream;base64` data url", )); } RevocationBitmap::deserialize_compressed_base64( std::str::from_utf8(data_url.get_data()) - .map_err(|_| Error::InvalidService("invalid data url - expected valid utf-8"))?, + .map_err(|_| RevocationError::InvalidService("invalid data url - expected valid utf-8"))?, ) } else { - Err(Error::InvalidService("invalid endpoint - expected a single data url")) + Err(RevocationError::InvalidService( + "invalid endpoint - expected a single data url", + )) } } /// Deserializes a compressed [`RevocationBitmap`] base64-encoded `data`. - pub(crate) fn deserialize_compressed_base64(data: &T) -> Result + pub(crate) fn deserialize_compressed_base64(data: &T) -> Result where T: AsRef + ?Sized, { let decoded_data: Vec = BaseEncoding::decode(data, Base::Base64Url) - .map_err(|e| Error::Base64DecodingError(data.as_ref().to_owned(), e))?; + .map_err(|e| RevocationError::Base64DecodingError(data.as_ref().to_owned(), e))?; let decompressed_data: Vec = Self::decompress_zlib(decoded_data)?; Self::deserialize_slice(&decompressed_data) } /// Serializes and compressess [`RevocationBitmap`] as a base64-encoded `String`. - pub(crate) fn serialize_compressed_base64(&self) -> Result { + pub(crate) fn serialize_compressed_base64(&self) -> Result { let serialized_data: Vec = self.serialize_vec()?; Self::compress_zlib(serialized_data).map(|data| BaseEncoding::encode(&data, Base::Base64Url)) } /// Deserializes [`RevocationBitmap`] from a slice of bytes. - fn deserialize_slice(data: &[u8]) -> Result { + fn deserialize_slice(data: &[u8]) -> Result { RoaringBitmap::deserialize_from(data) - .map_err(Error::BitmapDecodingError) + .map_err(RevocationError::BitmapDecodingError) .map(Self) } /// Serializes a [`RevocationBitmap`] as a vector of bytes. - fn serialize_vec(&self) -> Result> { + fn serialize_vec(&self) -> Result, RevocationError> { let mut output: Vec = Vec::with_capacity(self.0.serialized_size()); - self.0.serialize_into(&mut output).map_err(Error::BitmapEncodingError)?; + self + .0 + .serialize_into(&mut output) + .map_err(RevocationError::BitmapEncodingError)?; Ok(output) } - fn compress_zlib>(input: T) -> Result> { + fn compress_zlib>(input: T) -> Result, RevocationError> { let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); - encoder.write_all(input.as_ref()).map_err(Error::BitmapEncodingError)?; - encoder.finish().map_err(Error::BitmapEncodingError) + encoder + .write_all(input.as_ref()) + .map_err(RevocationError::BitmapEncodingError)?; + encoder.finish().map_err(RevocationError::BitmapEncodingError) } - fn decompress_zlib>(input: T) -> Result> { + fn decompress_zlib>(input: T) -> Result, RevocationError> { let mut writer = Vec::new(); let mut decoder = ZlibDecoder::new(writer); - decoder.write_all(input.as_ref()).map_err(Error::BitmapDecodingError)?; - writer = decoder.finish().map_err(Error::BitmapDecodingError)?; + decoder + .write_all(input.as_ref()) + .map_err(RevocationError::BitmapDecodingError)?; + writer = decoder.finish().map_err(RevocationError::BitmapDecodingError)?; Ok(writer) } } impl TryFrom<&Service> for RevocationBitmap { - type Error = Error; + type Error = RevocationError; - fn try_from(service: &Service) -> Result { + fn try_from(service: &Service) -> Result { if !service.type_().contains(Self::TYPE) { - return Err(Error::InvalidService("invalid type - expected `RevocationBitmap2022`")); + return Err(RevocationError::InvalidService( + "invalid type - expected `RevocationBitmap2022`", + )); } Self::from_endpoint(service.service_endpoint()) @@ -189,8 +200,10 @@ mod tests { fn test_revocation_bitmap_test_vector_1() { const URL: &str = "data:application/octet-stream;base64,ZUp5ek1tQUFBd0FES0FCcg=="; - let bitmap: RevocationBitmap = - RevocationBitmap::from_endpoint(&crate::service::ServiceEndpoint::One(Url::parse(URL).unwrap())).unwrap(); + let bitmap: RevocationBitmap = RevocationBitmap::from_endpoint(&identity_document::service::ServiceEndpoint::One( + Url::parse(URL).unwrap(), + )) + .unwrap(); assert!(bitmap.is_empty()); } @@ -200,8 +213,10 @@ mod tests { const URL: &str = "data:application/octet-stream;base64,ZUp5ek1tQmdZR0lBQVVZZ1pHQ1FBR0laSUdabDZHUGN3UW9BRXVvQjlB"; const EXPECTED: &[u32] = &[5, 398, 67000]; - let bitmap: RevocationBitmap = - RevocationBitmap::from_endpoint(&crate::service::ServiceEndpoint::One(Url::parse(URL).unwrap())).unwrap(); + let bitmap: RevocationBitmap = RevocationBitmap::from_endpoint(&identity_document::service::ServiceEndpoint::One( + Url::parse(URL).unwrap(), + )) + .unwrap(); for revoked in EXPECTED { assert!(bitmap.is_revoked(*revoked)); @@ -214,8 +229,10 @@ mod tests { fn test_revocation_bitmap_test_vector_3() { const URL: &str = "data:application/octet-stream;base64,ZUp6dHhERVJBQ0FNQkxESEFWS1lXZkN2Q3E0MmFESmtyMlNrM0ROckFLQ2RBQUFBQUFBQTMzbGhHZm9q"; - let bitmap: RevocationBitmap = - RevocationBitmap::from_endpoint(&crate::service::ServiceEndpoint::One(Url::parse(URL).unwrap())).unwrap(); + let bitmap: RevocationBitmap = RevocationBitmap::from_endpoint(&identity_document::service::ServiceEndpoint::One( + Url::parse(URL).unwrap(), + )) + .unwrap(); for index in 0..2u32.pow(14) { assert!(bitmap.is_revoked(index)); diff --git a/identity_credential/src/revocation/document_ext.rs b/identity_credential/src/revocation/document_ext.rs new file mode 100644 index 0000000000..c212a6cf87 --- /dev/null +++ b/identity_credential/src/revocation/document_ext.rs @@ -0,0 +1,186 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use super::RevocationBitmap; +use identity_core::common::KeyComparable; +use identity_did::DID; +use identity_document::document::CoreDocument; +use identity_document::service::Service; +use identity_document::utils::DIDUrlQuery; +use identity_document::utils::Queryable; + +use super::RevocationError; +use super::RevocationResult; +/// Extension trait providing convenience methods to update a `RevocationBitmap2022` service +/// in a [`CoreDocument`](::identity_document::document::CoreDocument). +pub trait RevocationDocumentExt: private::Sealed { + /// If the document has a [`RevocationBitmap`] service identified by `service_query`, + /// revoke all specified `indices`. + fn revoke_credentials<'query, 'me, Q>(&'me mut self, service_query: Q, indices: &[u32]) -> RevocationResult<()> + where + Q: Into>; + + /// If the document has a [`RevocationBitmap`] service identified by `service_query`, + /// unrevoke all specified `indices`. + fn unrevoke_credentials<'query, 'me, Q>(&'me mut self, service_query: Q, indices: &[u32]) -> RevocationResult<()> + where + Q: Into>; +} + +mod private { + use super::CoreDocument; + use super::KeyComparable; + use super::DID; + + pub trait Sealed {} + impl Sealed for CoreDocument {} +} + +impl RevocationDocumentExt for CoreDocument +where + D: DID + KeyComparable, +{ + fn revoke_credentials<'query, 'me, Q>(&'me mut self, service_query: Q, indices: &[u32]) -> RevocationResult<()> + where + Q: Into>, + { + update_revocation_bitmap(self, service_query, |revocation_bitmap| { + for credential in indices { + revocation_bitmap.revoke(*credential); + } + }) + } + + fn unrevoke_credentials<'query, 'me, Q>(&mut self, service_query: Q, indices: &[u32]) -> RevocationResult<()> + where + Q: Into>, + { + update_revocation_bitmap(self, service_query, |revocation_bitmap| { + for credential in indices { + revocation_bitmap.unrevoke(*credential); + } + }) + } +} + +fn update_revocation_bitmap<'query, 'me, F, Q, D, T, U, V>( + document: &'me mut CoreDocument, + service_query: Q, + f: F, +) -> RevocationResult<()> +where + D: DID + KeyComparable, + F: FnOnce(&mut RevocationBitmap), + Q: Into>, +{ + let service: &mut Service = document + .service_mut_unchecked() + .query_mut(service_query) + .ok_or(RevocationError::InvalidService("invalid id - service not found"))?; + + let mut revocation_bitmap: RevocationBitmap = RevocationBitmap::try_from(&*service)?; + f(&mut revocation_bitmap); + + std::mem::swap(service.service_endpoint_mut(), &mut revocation_bitmap.to_endpoint()?); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use identity_core::common::Object; + use identity_core::convert::FromJson; + use identity_document::document::Document; + + const START_DOCUMENT_JSON: &str = r#"{ + "id": "did:example:1234", + "verificationMethod": [ + { + "id": "did:example:1234#key-1", + "controller": "did:example:1234", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zJdzr2UvC" + }, + { + "id": "did:example:1234#key-2", + "controller": "did:example:1234", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zJdzr2UvD" + }, + { + "id": "did:example:1234#key-3", + "controller": "did:example:1234", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zJdzr2UvE" + } + ], + "authentication": [ + { + "id": "did:example:1234#auth-key", + "controller": "did:example:1234", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zT7yhPEwJZL4G" + }, + "did:example:1234#key-3" + ], + "keyAgreement": [ + "did:example:1234#key-4" + ] + } + "#; + + #[test] + fn test_revocation() { + let mut document: CoreDocument = CoreDocument::from_json(&START_DOCUMENT_JSON).unwrap(); + + let indices_1 = [3, 9, 254, 65536]; + let indices_2 = [2, 15, 1337, 1000]; + + let service_id = document.id().to_url().join("#revocation-service").unwrap(); + + // The methods error if the service doesn't exist. + assert!(document.revoke_credentials(&service_id, &indices_2).is_err()); + assert!(document.unrevoke_credentials(&service_id, &indices_2).is_err()); + + // Add service with indices_1 already revoked. + let mut bitmap: crate::revocation::RevocationBitmap = crate::revocation::RevocationBitmap::new(); + for index in indices_1.iter() { + bitmap.revoke(*index); + } + assert!(document + .insert_service( + Service::builder(Object::new()) + .id(service_id.clone()) + .type_(crate::revocation::RevocationBitmap::TYPE) + .service_endpoint(bitmap.to_endpoint().unwrap()) + .build() + .unwrap() + ) + .is_ok()); + + // Revoke indices_2. + document.revoke_credentials(&service_id, &indices_2).unwrap(); + let service: &Service = document.resolve_service(&service_id).unwrap(); + let decoded_bitmap: crate::revocation::RevocationBitmap = service.try_into().unwrap(); + + // We expect all indices to be revoked now. + for index in indices_1.iter().chain(indices_2.iter()) { + assert!(decoded_bitmap.is_revoked(*index)); + } + + // Unrevoke indices_1. + document.unrevoke_credentials(&service_id, &indices_1).unwrap(); + + let service: &Service = document.resolve_service(&service_id).unwrap(); + let decoded_bitmap: crate::revocation::RevocationBitmap = service.try_into().unwrap(); + + // Expect indices_2 to be revoked, but not indices_1. + for index in indices_2 { + assert!(decoded_bitmap.is_revoked(index)); + } + for index in indices_1 { + assert!(!decoded_bitmap.is_revoked(index)); + } + } +} diff --git a/identity_credential/src/revocation/error.rs b/identity_credential/src/revocation/error.rs new file mode 100644 index 0000000000..aaf7068005 --- /dev/null +++ b/identity_credential/src/revocation/error.rs @@ -0,0 +1,27 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +/// A result type designed for `RevocationBitmap2022` handling. +pub type RevocationResult = std::result::Result; + +/// Errors occurring when creating or extracting a Service of type `RevocationBitmap2022` +#[derive(Debug, thiserror::Error, strum::IntoStaticStr)] +pub enum RevocationError { + #[error("revocation bitmap could not be deserialized or decompressed")] + /// Indicates that the bitmap could not be reconstructed. + BitmapDecodingError(#[source] std::io::Error), + #[error("revocation bitmap could not be serialized or compressed")] + /// Indicates that the bitmap could not be encoded. + BitmapEncodingError(#[source] std::io::Error), + /// This variant is typically used to indicate invalid conversions between `Services`, `ServiceEndpoints` and + /// `RevocationBitmaps`. + #[error("{0}")] + InvalidService(&'static str), + /// Indicates a failure to decode a bitmap from a base64 string representation. + #[error("unable to decode base64 string: `{0}`")] + Base64DecodingError(String, #[source] identity_core::error::Error), + #[error("could not parse url")] + #[non_exhaustive] + /// Indicates a failure to construct a URL when attempting to construct a `ServiceEndpoint`. + UrlConstructionError(#[source] Box), +} diff --git a/identity_credential/src/revocation/mod.rs b/identity_credential/src/revocation/mod.rs new file mode 100644 index 0000000000..888e39cb1e --- /dev/null +++ b/identity_credential/src/revocation/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! Contains a bitmap for managing credential revocation. +mod bitmap; +mod document_ext; +mod error; +pub use self::bitmap::RevocationBitmap; +pub use self::document_ext::RevocationDocumentExt; +pub use self::error::RevocationError; +pub use self::error::RevocationResult; diff --git a/identity_credential/src/validator/credential_validator.rs b/identity_credential/src/validator/credential_validator.rs index fd1cd8924f..be37b46779 100644 --- a/identity_credential/src/validator/credential_validator.rs +++ b/identity_credential/src/validator/credential_validator.rs @@ -1,18 +1,18 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::str::FromStr; use serde::Serialize; +#[cfg(feature = "revocation-bitmap")] +use crate::revocation::RevocationBitmap; use identity_core::common::OneOrMany; use identity_core::common::Timestamp; use identity_core::common::Url; -use identity_did::did::CoreDID; -use identity_did::did::DID; -#[cfg(feature = "revocation-bitmap")] -use identity_did::revocation::RevocationBitmap; -use identity_did::verifiable::VerifierOptions; +use identity_did::CoreDID; +use identity_did::DID; +use identity_document::verifiable::VerifierOptions; use crate::credential::Credential; #[cfg(feature = "revocation-bitmap")] @@ -202,12 +202,12 @@ impl CredentialValidator { issuer: &DOC, status: RevocationBitmapStatus, ) -> ValidationUnitResult { - let issuer_service_url: identity_did::did::CoreDIDUrl = status.id().map_err(ValidationError::InvalidStatus)?; + let issuer_service_url: identity_did::CoreDIDUrl = status.id().map_err(ValidationError::InvalidStatus)?; // Check whether index is revoked. let revocation_bitmap: RevocationBitmap = issuer .resolve_revocation_bitmap(issuer_service_url.into()) - .map_err(ValidationError::InvalidService)?; + .map_err(|_| ValidationError::ServiceLookupError)?; let index: u32 = status.index().map_err(ValidationError::InvalidStatus)?; if revocation_bitmap.is_revoked(index) { Err(ValidationError::Revoked) @@ -298,9 +298,9 @@ mod tests { use identity_core::convert::FromJson; use identity_core::crypto::KeyPair; use identity_core::crypto::ProofOptions; - use identity_did::did::DID; - use identity_did::document::CoreDocument; - use identity_did::service::Service; + use identity_did::DID; + use identity_document::document::CoreDocument; + use identity_document::service::Service; use crate::credential::Status; use crate::credential::Subject; @@ -727,8 +727,10 @@ mod tests { .is_ok()); } + #[cfg(feature = "revocation-bitmap")] #[test] fn test_check_status() { + use crate::revocation::RevocationDocumentExt; let Setup { mut issuer_doc, unsigned_credential: mut credential, @@ -756,7 +758,7 @@ mod tests { } // Add a RevocationBitmap status to the credential. - let service_url: identity_did::did::CoreDIDUrl = issuer_doc.id().to_url().join("#revocation-service").unwrap(); + let service_url: identity_did::CoreDIDUrl = issuer_doc.id().to_url().join("#revocation-service").unwrap(); let index: u32 = 42; credential.credential_status = Some(RevocationBitmapStatus::new(service_url.clone(), index).into()); @@ -791,7 +793,7 @@ mod tests { } // 4: revoked index. - issuer_doc.revoke_credentials(&service_url, &[index]).unwrap(); + ::revoke_credentials(&mut issuer_doc, &service_url, &[index]).unwrap(); for (status_check, expected) in [ (StatusCheck::Strict, false), (StatusCheck::SkipUnsupported, false), diff --git a/identity_credential/src/validator/errors.rs b/identity_credential/src/validator/errors.rs index 1ae8683876..b47767e94b 100644 --- a/identity_credential/src/validator/errors.rs +++ b/identity_credential/src/validator/errors.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -65,8 +65,9 @@ pub enum ValidationError { #[error("invalid credential status")] InvalidStatus(#[source] crate::Error), /// Indicates that the the credential's service is invalid. - #[error("invalid service")] - InvalidService(#[source] identity_did::Error), + #[error("service lookup error")] + #[non_exhaustive] + ServiceLookupError, /// Indicates that the credential has been revoked. #[error("credential has been revoked")] Revoked, diff --git a/identity_credential/src/validator/presentation_validator.rs b/identity_credential/src/validator/presentation_validator.rs index f84921560d..de6b569a8e 100644 --- a/identity_credential/src/validator/presentation_validator.rs +++ b/identity_credential/src/validator/presentation_validator.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::BTreeMap; @@ -7,9 +7,9 @@ use std::str::FromStr; use serde::Serialize; use identity_core::common::Url; -use identity_did::did::CoreDID; -use identity_did::did::DID; -use identity_did::verifiable::VerifierOptions; +use identity_did::CoreDID; +use identity_did::DID; +use identity_document::verifiable::VerifierOptions; use crate::presentation::Presentation; @@ -238,7 +238,7 @@ mod tests { use identity_core::common::Url; use identity_core::crypto::KeyPair; use identity_core::crypto::ProofOptions; - use identity_did::document::CoreDocument; + use identity_document::document::CoreDocument; use crate::credential::Credential; use crate::presentation::PresentationBuilder; diff --git a/identity_credential/src/validator/test_utils.rs b/identity_credential/src/validator/test_utils.rs index 25654d53eb..689a5c66f2 100644 --- a/identity_credential/src/validator/test_utils.rs +++ b/identity_credential/src/validator/test_utils.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Object; @@ -9,10 +9,10 @@ use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; use identity_core::json; use identity_core::utils::BaseEncoding; -use identity_did::did::CoreDID; -use identity_did::did::DID; -use identity_did::document::CoreDocument; -use identity_did::verification::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DID; +use identity_document::document::CoreDocument; +use identity_verification::VerificationMethod; use crate::credential::Credential; use crate::credential::CredentialBuilder; diff --git a/identity_credential/src/validator/validation_options.rs b/identity_credential/src/validator/validation_options.rs index 34e7416b4f..72b5c42ba2 100644 --- a/identity_credential/src/validator/validation_options.rs +++ b/identity_credential/src/validator/validation_options.rs @@ -1,8 +1,8 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Timestamp; -use identity_did::verifiable::VerifierOptions; +use identity_document::verifiable::VerifierOptions; use serde::Deserialize; use serde::Serialize; diff --git a/identity_credential/src/validator/validator_document.rs b/identity_credential/src/validator/validator_document.rs index a40a28bd71..d80bbba8b9 100644 --- a/identity_credential/src/validator/validator_document.rs +++ b/identity_credential/src/validator/validator_document.rs @@ -1,14 +1,14 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::any::Any; -use identity_core::crypto::GetSignature; -use identity_did::did::DID; -use identity_did::document::Document; #[cfg(feature = "revocation-bitmap")] -use identity_did::revocation::RevocationBitmap; -use identity_did::verifiable::VerifierOptions; +use crate::revocation::RevocationBitmap; +use identity_core::crypto::GetSignature; +use identity_did::DID; +use identity_document::document::Document; +use identity_document::verifiable::VerifierOptions; use self::private::Sealed; use self::private::Verifiable; @@ -49,7 +49,7 @@ pub trait ValidatorDocument: Sealed + core::fmt::Debug { /// /// Fails if an unsupported verification method is used, data /// serialization fails, or the verification operation fails. - fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_did::Result<()>; + fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_document::Result<()>; #[doc(hidden)] /// Extracts the `RevocationBitmap` from the referenced service in the DID Document. @@ -61,8 +61,8 @@ pub trait ValidatorDocument: Sealed + core::fmt::Debug { #[cfg(feature = "revocation-bitmap")] fn resolve_revocation_bitmap( &self, - query: identity_did::utils::DIDUrlQuery<'_>, - ) -> identity_did::Result; + query: identity_document::utils::DIDUrlQuery<'_>, + ) -> crate::revocation::RevocationResult; } mod private { @@ -96,7 +96,7 @@ impl ValidatorDocument for &dyn ValidatorDocument { (*self).did_str() } - fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_did::Result<()> { + fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_document::Result<()> { (*self).verify_data(data, options) } fn upcast(self: Box) -> Box @@ -109,8 +109,8 @@ impl ValidatorDocument for &dyn ValidatorDocument { #[cfg(feature = "revocation-bitmap")] fn resolve_revocation_bitmap( &self, - query: identity_did::utils::DIDUrlQuery<'_>, - ) -> identity_did::Result { + query: identity_document::utils::DIDUrlQuery<'_>, + ) -> crate::revocation::RevocationResult { (*self).resolve_revocation_bitmap(query) } } @@ -123,7 +123,7 @@ where self.id().as_str() } - fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_did::Result<()> { + fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_document::Result<()> { self.verify_data(data, options).map_err(Into::into) } @@ -137,11 +137,11 @@ where #[cfg(feature = "revocation-bitmap")] fn resolve_revocation_bitmap( &self, - query: identity_did::utils::DIDUrlQuery<'_>, - ) -> identity_did::Result { + query: identity_document::utils::DIDUrlQuery<'_>, + ) -> crate::revocation::RevocationResult { self .resolve_service(query) - .ok_or(identity_did::Error::InvalidService( + .ok_or(crate::revocation::RevocationError::InvalidService( "revocation bitmap service not found", )) .and_then(RevocationBitmap::try_from) @@ -173,7 +173,7 @@ impl ValidatorDocument for AbstractValidatorDocument { self.0.did_str() } - fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_did::Result<()> { + fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_document::Result<()> { self.0.verify_data(data, options) } @@ -187,8 +187,8 @@ impl ValidatorDocument for AbstractValidatorDocument { #[cfg(feature = "revocation-bitmap")] fn resolve_revocation_bitmap( &self, - query: identity_did::utils::DIDUrlQuery<'_>, - ) -> identity_did::Result { + query: identity_document::utils::DIDUrlQuery<'_>, + ) -> crate::revocation::RevocationResult { self.0.resolve_revocation_bitmap(query) } } @@ -232,7 +232,7 @@ impl AbstractThreadSafeValidatorDocument { /// /// # Example /// ``` - /// # use identity_did::document::CoreDocument; + /// # use identity_document::document::CoreDocument; /// # use identity_credential::validator::AbstractValidatorDocument; /// /// fn round_trip(doc: CoreDocument) -> CoreDocument { @@ -246,7 +246,7 @@ impl AbstractThreadSafeValidatorDocument { } impl ValidatorDocument for AbstractThreadSafeValidatorDocument { - fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_did::Result<()> { + fn verify_data(&self, data: &dyn Verifiable, options: &VerifierOptions) -> identity_document::Result<()> { self.0.verify_data(data, options) } @@ -264,8 +264,8 @@ impl ValidatorDocument for AbstractThreadSafeValidatorDocument { #[cfg(feature = "revocation-bitmap")] fn resolve_revocation_bitmap( &self, - query: identity_did::utils::DIDUrlQuery<'_>, - ) -> identity_did::Result { + query: identity_document::utils::DIDUrlQuery<'_>, + ) -> crate::revocation::RevocationResult { self.0.resolve_revocation_bitmap(query) } } diff --git a/identity_did/Cargo.toml b/identity_did/Cargo.toml index 90fbc3baab..fb816fd341 100644 --- a/identity_did/Cargo.toml +++ b/identity_did/Cargo.toml @@ -1,29 +1,24 @@ [package] name = "identity_did" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] +authors.workspace = true edition = "2021" -homepage = "https://www.iota.org" +homepage.workspace = true keywords = ["iota", "tangle", "identity", "did"] -license = "Apache-2.0" +license.workspace = true readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" +repository.workspace = true description = "Agnostic implementation of the Decentralized Identifiers (DID) standard." [dependencies] -dataurl = { version = "0.1.2", default-features = false, optional = true } did_url = { version = "0.1", default-features = false, features = ["std", "serde"] } -flate2 = { version = "1.0.23", default-features = false, features = ["rust_backend"], optional = true } form_urlencoded = { version = "1.0.1", default-features = false } identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core" } -indexmap = { version = "1.7", default-features = false, features = ["std", "serde-1"] } -roaring = { version = "0.9.0", default-features = false, optional = true } -serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } -strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } -thiserror = { version = "1.0", default-features = false } +serde.workspace = true +strum.workspace = true +thiserror.workspace = true [dev-dependencies] -criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } proptest = { version = "1.0" } serde_json = { version = "1.0", default-features = false } @@ -32,11 +27,3 @@ serde_json = { version = "1.0", default-features = false } # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --workspace --open all-features = true rustdoc-args = ["--cfg", "docsrs"] - -[features] -default = ["revocation-bitmap"] -revocation-bitmap = ["dataurl", "flate2", "roaring"] - -[[bench]] -name = "deserialize_document" -harness = false diff --git a/identity_did/README.md b/identity_did/README.md index 4030208c5c..feb7f00442 100644 --- a/identity_did/README.md +++ b/identity_did/README.md @@ -1,27 +1,5 @@ IOTA Identity - DID === -Agnostic implementation of the Decentralized Identifiers (DID) standard from W3C. +Types representing DIDs and DIDUrls as defined in the Decentralized Identifiers (DID) standard by the W3C. -## Overview -Decentralized Identifiers (DID) is a proposed standard from the World Wide Web Consortium (W3C) to enable a -verifiable and decentralized identity. The standard provides a unique identifier (DID), which can be used to look up -more information about the associated identity in the form of a DID Document. The DID Document contains public keys, -to prove control over the identity, and service endpoints which are URI's that can be resolved to find more public -information about the identity. Often the DID Documents are stored on a Distributed Ledger Technology (DLT) such as -Bitcoin, Ethereum and IOTA, but this is not a requirement. - -The [IOTA Identity Framework](https://wiki.iota.org/identity.rs/introduction) leverages this crate to build its own [DID method](https://www.w3.org/TR/2020/WD-did-core-20200731/#dfn-did-methods), but the types and traits here are defined according to the [DID specifications v1.0 Working Draft 20200731](https://www.w3.org/TR/2020/WD-did-core-20200731/) which is method agnostic. - -## Central functionality -When working with the IOTA Identity Framework one will frequently interact with functionality from this crate listed here. - -- [`DID` trait](crate::did::DID) -- [`DIDUrl`](crate::did::DIDUrl) -- [`Service`](crate::service::Service) -- [`VerificationMethod`](crate::verification::VerificationMethod) -- [`MethodRelationship`](crate::verification::MethodRelationship) -- [`MethodScope`](crate::verification::MethodScope) -- [`MethodType`](crate::verification::MethodType) -- [`VerifierOptions`](crate::verifiable::VerifierOptions) -- [`RevocationBitmap`](crate::revocation::RevocationBitmap) \ No newline at end of file diff --git a/identity_did/src/did/did.rs b/identity_did/src/did.rs similarity index 92% rename from identity_did/src/did/did.rs rename to identity_did/src/did.rs index 82ac46f304..9c0a00b6e0 100644 --- a/identity_did/src/did/did.rs +++ b/identity_did/src/did.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryFrom; @@ -14,8 +14,8 @@ use identity_core::common::KeyComparable; use identity_core::diff::Diff; use identity_core::diff::DiffString; -use crate::did::DIDError; -use crate::did::DIDUrl; +use crate::DIDUrl; +use crate::Error; pub trait DID: Clone + PartialEq + Eq + PartialOrd + Ord + Hash + FromStr + TryFrom + Into { const SCHEME: &'static str = BaseDIDUrl::SCHEME; @@ -60,7 +60,7 @@ pub trait DID: Clone + PartialEq + Eq + PartialOrd + Ord + Hash + FromStr + TryF /// fragment to this [`DID`]. /// /// See [`DIDUrl::join`]. - fn join(self, value: impl AsRef) -> Result, DIDError> + fn join(self, value: impl AsRef) -> Result, Error> where Self: Sized; @@ -83,59 +83,59 @@ impl CoreDID { /// # Errors /// /// Returns `Err` if the input is not a valid [`DID`]. - pub fn parse(input: impl AsRef) -> Result { - let base_did_url: BaseDIDUrl = BaseDIDUrl::parse(input).map_err(DIDError::from)?; + pub fn parse(input: impl AsRef) -> Result { + let base_did_url: BaseDIDUrl = BaseDIDUrl::parse(input).map_err(Error::from)?; Self::try_from_base_did(base_did_url) } /// Try convert a [`BaseDIDUrl`] into a [`CoreDID`]. - fn try_from_base_did(base_did_url: BaseDIDUrl) -> Result { + fn try_from_base_did(base_did_url: BaseDIDUrl) -> Result { Self::check_validity(&base_did_url)?; Ok(Self(base_did_url)) } /// Set the method name of the [`DID`]. - pub fn set_method_name(&mut self, value: impl AsRef) -> Result<(), DIDError> { + pub fn set_method_name(&mut self, value: impl AsRef) -> Result<(), Error> { Self::valid_method_name(value.as_ref())?; self.0.set_method(value); Ok(()) } /// Validates whether a string is a valid [`DID`] method name. - pub fn valid_method_name(value: &str) -> Result<(), DIDError> { + pub fn valid_method_name(value: &str) -> Result<(), Error> { if !value.chars().all(is_char_method_name) { - return Err(DIDError::InvalidMethodName); + return Err(Error::InvalidMethodName); } Ok(()) } /// Set the method-specific-id of the [`DID`]. - pub fn set_method_id(&mut self, value: impl AsRef) -> Result<(), DIDError> { + pub fn set_method_id(&mut self, value: impl AsRef) -> Result<(), Error> { Self::valid_method_id(value.as_ref())?; self.0.set_method_id(value); Ok(()) } /// Validates whether a string is a valid [`DID`] method-id. - pub fn valid_method_id(value: &str) -> Result<(), DIDError> { + pub fn valid_method_id(value: &str) -> Result<(), Error> { if !value.chars().all(is_char_method_id) { - return Err(DIDError::InvalidMethodId); + return Err(Error::InvalidMethodId); } Ok(()) } /// Checks if the given `did` is valid according to the base [`DID`] specification. - pub fn check_validity(did: &BaseDIDUrl) -> Result<(), DIDError> { + pub fn check_validity(did: &BaseDIDUrl) -> Result<(), Error> { // Validate basic DID constraints. Self::valid_method_name(did.method())?; Self::valid_method_id(did.method_id())?; if did.scheme() != Self::SCHEME { - return Err(DIDError::InvalidScheme); + return Err(Error::InvalidScheme); } // Ensure no DID Url segments are present. if !did.path().is_empty() || did.fragment().is_some() || did.query().is_some() { - return Err(DIDError::InvalidMethodId); + return Err(Error::InvalidMethodId); } Ok(()) @@ -167,7 +167,7 @@ impl DID for CoreDID { >::into(self) } - fn join(self, value: impl AsRef) -> Result, DIDError> { + fn join(self, value: impl AsRef) -> Result, Error> { self.into_url().join(value) } @@ -187,7 +187,7 @@ impl From for BaseDIDUrl { } impl TryFrom for CoreDID { - type Error = DIDError; + type Error = Error; fn try_from(base_did_url: BaseDIDUrl) -> Result { Self::try_from_base_did(base_did_url) @@ -213,7 +213,7 @@ impl AsRef for CoreDID { } impl FromStr for CoreDID { - type Err = DIDError; + type Err = Error; fn from_str(string: &str) -> Result { Self::parse(string) @@ -221,7 +221,7 @@ impl FromStr for CoreDID { } impl TryFrom<&str> for CoreDID { - type Error = DIDError; + type Error = Error; fn try_from(other: &str) -> Result { Self::parse(other) @@ -229,7 +229,7 @@ impl TryFrom<&str> for CoreDID { } impl TryFrom for CoreDID { - type Error = DIDError; + type Error = Error; fn try_from(other: String) -> Result { Self::parse(other) @@ -334,7 +334,7 @@ where fn to_url(&self) -> DIDUrl { DIDUrl::new(self.clone(), None) } - fn join(self, value: impl AsRef) -> Result, DIDError> + fn join(self, value: impl AsRef) -> Result, Error> where Self: Sized, { diff --git a/identity_did/src/did/error.rs b/identity_did/src/did/error.rs deleted file mode 100644 index 64aef47b98..0000000000 --- a/identity_did/src/did/error.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2020-2021 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use core::fmt::Debug; - -use did_url::Error; - -#[derive(Debug, thiserror::Error, strum::IntoStaticStr)] -#[non_exhaustive] -/// Error type caused by invalid DID handling. -pub enum DIDError { - #[error("Invalid Authority")] - InvalidAuthority, - #[error("Invalid Fragment")] - InvalidFragment, - #[error("Invalid Method Id")] - InvalidMethodId, - #[error("Invalid Method Name")] - InvalidMethodName, - #[error("Invalid Path")] - InvalidPath, - #[error("Invalid Query")] - InvalidQuery, - #[error("Invalid Scheme")] - InvalidScheme, - - #[error("{0}")] - Other(&'static str), -} - -impl From for DIDError { - fn from(error: Error) -> Self { - match error { - Error::InvalidAuthority => Self::InvalidAuthority, - Error::InvalidFragment => Self::InvalidFragment, - Error::InvalidMethodId => Self::InvalidMethodId, - Error::InvalidMethodName => Self::InvalidMethodName, - Error::InvalidPath => Self::InvalidPath, - Error::InvalidQuery => Self::InvalidQuery, - Error::InvalidScheme => Self::InvalidScheme, - error => Self::Other(error.as_str()), - } - } -} diff --git a/identity_did/src/did/mod.rs b/identity_did/src/did/mod.rs deleted file mode 100644 index e417c5d430..0000000000 --- a/identity_did/src/did/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020-2021 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! Provides generic types and traits for working with Decentralized Identifiers. - -#[allow(clippy::module_inception)] -mod did; -mod did_url; -mod error; - -pub use self::did::CoreDID; -pub use self::did::DID; -pub use self::did_url::CoreDIDUrl; -pub use self::did_url::DIDUrl; -pub use self::did_url::RelativeDIDUrl; -pub use self::error::DIDError; -pub use ::did_url::DID as BaseDIDUrl; diff --git a/identity_did/src/did/did_url.rs b/identity_did/src/did_url.rs similarity index 91% rename from identity_did/src/did/did_url.rs rename to identity_did/src/did_url.rs index bbb90798a3..e57a9390e5 100644 --- a/identity_did/src/did/did_url.rs +++ b/identity_did/src/did_url.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryFrom; @@ -18,10 +18,10 @@ use identity_core::common::Url; use identity_core::diff::Diff; use identity_core::diff::DiffString; -use crate::did::did::is_char_method_id; +use crate::did::is_char_method_id; use crate::did::CoreDID; -use crate::did::DIDError; use crate::did::DID; +use crate::Error; /// A method agnostic [`DID Url`](DIDUrl). pub type CoreDIDUrl = DIDUrl; @@ -96,20 +96,20 @@ impl RelativeDIDUrl { /// # Example /// /// ``` - /// # use identity_did::did::RelativeDIDUrl; + /// # use identity_did::RelativeDIDUrl; /// # let mut url = RelativeDIDUrl::new(); /// url.set_path(Some("/path/sub-path/resource")).unwrap(); /// assert_eq!(url.path().unwrap(), "/path/sub-path/resource"); /// assert_eq!(url.to_string(), "/path/sub-path/resource"); /// ``` - pub fn set_path(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_path(&mut self, value: Option<&str>) -> Result<(), Error> { self.path = value .filter(|s| !s.is_empty()) .map(|s| { if s.starts_with('/') && s.chars().all(is_char_path) { Ok(s.to_owned()) } else { - Err(DIDError::InvalidPath) + Err(Error::InvalidPath) } }) .transpose()?; @@ -130,7 +130,7 @@ impl RelativeDIDUrl { /// # Example /// /// ``` - /// # use identity_did::did::RelativeDIDUrl; + /// # use identity_did::RelativeDIDUrl; /// # let mut url = RelativeDIDUrl::new(); /// // Set the query with a leading '?' /// url.set_query(Some("?query1=a")).unwrap(); @@ -142,14 +142,14 @@ impl RelativeDIDUrl { /// assert_eq!(url.query().unwrap(), "query1=a&query2=b"); /// assert_eq!(url.to_string(), "?query1=a&query2=b"); /// ``` - pub fn set_query(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_query(&mut self, value: Option<&str>) -> Result<(), Error> { self.query = value .filter(|s| !s.is_empty()) .map(|mut s| { // Ignore leading '?' during validation. s = s.strip_prefix('?').unwrap_or(s); if s.is_empty() || !s.chars().all(is_char_query) { - return Err(DIDError::InvalidQuery); + return Err(Error::InvalidQuery); } Ok(format!("?{}", s)) }) @@ -180,7 +180,7 @@ impl RelativeDIDUrl { /// # Example /// /// ``` - /// # use identity_did::did::RelativeDIDUrl; + /// # use identity_did::RelativeDIDUrl; /// # let mut url = RelativeDIDUrl::new(); /// // Set the fragment with a leading '#' /// url.set_fragment(Some("#fragment1")).unwrap(); @@ -192,14 +192,14 @@ impl RelativeDIDUrl { /// assert_eq!(url.fragment().unwrap(), "fragment2"); /// assert_eq!(url.to_string(), "#fragment2"); /// ``` - pub fn set_fragment(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_fragment(&mut self, value: Option<&str>) -> Result<(), Error> { self.fragment = value .filter(|s| !s.is_empty()) .map(|mut s| { // Ignore leading '#' during validation. s = s.strip_prefix('#').unwrap_or(s); if s.is_empty() || !s.chars().all(is_char_fragment) { - return Err(DIDError::InvalidFragment); + return Err(Error::InvalidFragment); } Ok(format!("#{}", s)) }) @@ -295,12 +295,12 @@ where } /// Parse a [`DIDUrl`] from a string. - pub fn parse(input: impl AsRef) -> Result { + pub fn parse(input: impl AsRef) -> Result { let did_url: BaseDIDUrl = BaseDIDUrl::parse(input)?; Self::from_base_did_url(did_url) } - fn from_base_did_url(did_url: BaseDIDUrl) -> Result { + fn from_base_did_url(did_url: BaseDIDUrl) -> Result { // Extract relative DID URL let url: RelativeDIDUrl = { let mut url: RelativeDIDUrl = RelativeDIDUrl::new(); @@ -316,7 +316,7 @@ where base_did.set_path(""); base_did.set_query(None); base_did.set_fragment(None); - D::try_from(base_did).map_err(|_| DIDError::Other("invalid DID"))? + D::try_from(base_did).map_err(|_| Error::Other("invalid DID"))? }; Ok(Self { did, url }) @@ -347,7 +347,7 @@ where /// Sets the `fragment` component of the [`DIDUrl`]. /// /// See [`RelativeDIDUrl::set_fragment`]. - pub fn set_fragment(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_fragment(&mut self, value: Option<&str>) -> Result<(), Error> { self.url.set_fragment(value) } @@ -361,7 +361,7 @@ where /// Sets the `path` component of the [`DIDUrl`]. /// /// See [`RelativeDIDUrl::set_path`]. - pub fn set_path(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_path(&mut self, value: Option<&str>) -> Result<(), Error> { self.url.set_path(value) } @@ -375,7 +375,7 @@ where /// Sets the `query` component of the [`DIDUrl`]. /// /// See [`RelativeDIDUrl::set_query`]. - pub fn set_query(&mut self, value: Option<&str>) -> Result<(), DIDError> { + pub fn set_query(&mut self, value: Option<&str>) -> Result<(), Error> { self.url.set_query(value) } @@ -395,12 +395,12 @@ where /// - joining a path will overwrite the path and clear the query and fragment. /// - joining a query will overwrite the query and clear the fragment. /// - joining a fragment will only overwrite the fragment. - pub fn join(&self, segment: impl AsRef) -> Result { + pub fn join(&self, segment: impl AsRef) -> Result { let segment: &str = segment.as_ref(); // Accept only a relative path, query, or fragment to reject altering the method id segment. if !segment.starts_with('/') && !segment.starts_with('?') && !segment.starts_with('#') { - return Err(DIDError::InvalidPath); + return Err(Error::InvalidPath); } // Parse DID Url. @@ -466,7 +466,7 @@ impl FromStr for DIDUrl where D: DID, { - type Err = DIDError; + type Err = Error; fn from_str(string: &str) -> Result { Self::parse(string) @@ -477,7 +477,7 @@ impl TryFrom for DIDUrl where D: DID, { - type Error = DIDError; + type Error = Error; fn try_from(other: String) -> Result { Self::parse(other) @@ -751,31 +751,31 @@ mod tests { let mut relative_url = RelativeDIDUrl::new(); // Invalid symbols. - assert!(matches!(relative_url.set_path(Some("/white space")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/white\tspace")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/white\nspace")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path{invalid_brackets}")), Err(DIDError::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/white space")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/white\tspace")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/white\nspace")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path{invalid_brackets}")), Err(Error::InvalidPath))); // Missing leading '/'. - assert!(matches!(relative_url.set_path(Some("path")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("p/")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("p/ath")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("path/")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("path/sub-path/")), Err(DIDError::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("path")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("p/")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("p/ath")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("path/")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("path/sub-path/")), Err(Error::InvalidPath))); // Reject query delimiter '?'. - assert!(matches!(relative_url.set_path(Some("?query")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("some?query")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path?")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path?query")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path/query?")), Err(DIDError::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("?query")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("some?query")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path?")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path?query")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path/query?")), Err(Error::InvalidPath))); // Reject fragment delimiter '#'. - assert!(matches!(relative_url.set_path(Some("#fragment")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("some#fragment")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path#")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path#fragment")), Err(DIDError::InvalidPath))); - assert!(matches!(relative_url.set_path(Some("/path/fragment#")), Err(DIDError::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("#fragment")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("some#fragment")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path#")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path#fragment")), Err(Error::InvalidPath))); + assert!(matches!(relative_url.set_path(Some("/path/fragment#")), Err(Error::InvalidPath))); } #[test] @@ -809,22 +809,22 @@ mod tests { let mut relative_url = RelativeDIDUrl::new(); // Delimiter-only. - assert!(matches!(relative_url.set_query(Some("?")), Err(DIDError::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?")), Err(Error::InvalidQuery))); // Invalid symbols. - assert!(matches!(relative_url.set_query(Some("?white space")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?white\tspace")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?white\nspace")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query{invalid_brackets}")), Err(DIDError::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?white space")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?white\tspace")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?white\nspace")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query{invalid_brackets}")), Err(Error::InvalidQuery))); // Reject fragment delimiter '#'. - assert!(matches!(relative_url.set_query(Some("#fragment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("some#fragment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query#fragment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query=a#fragment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query=#fragment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query=frag#ment")), Err(DIDError::InvalidQuery))); - assert!(matches!(relative_url.set_query(Some("?query=fragment#")), Err(DIDError::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("#fragment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("some#fragment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query#fragment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query=a#fragment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query=#fragment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query=frag#ment")), Err(Error::InvalidQuery))); + assert!(matches!(relative_url.set_query(Some("?query=fragment#")), Err(Error::InvalidQuery))); } #[rustfmt::skip] @@ -857,14 +857,14 @@ mod tests { let mut relative_url = RelativeDIDUrl::new(); // Delimiter only. - assert!(matches!(relative_url.set_fragment(Some("#")), Err(DIDError::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#")), Err(Error::InvalidFragment))); // Invalid symbols. - assert!(matches!(relative_url.set_fragment(Some("#white space")), Err(DIDError::InvalidFragment))); - assert!(matches!(relative_url.set_fragment(Some("#white\tspace")), Err(DIDError::InvalidFragment))); - assert!(matches!(relative_url.set_fragment(Some("#white\nspace")), Err(DIDError::InvalidFragment))); - assert!(matches!(relative_url.set_fragment(Some("#fragment{invalid_brackets}")), Err(DIDError::InvalidFragment))); - assert!(matches!(relative_url.set_fragment(Some("#fragment\"other\"")), Err(DIDError::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#white space")), Err(Error::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#white\tspace")), Err(Error::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#white\nspace")), Err(Error::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#fragment{invalid_brackets}")), Err(Error::InvalidFragment))); + assert!(matches!(relative_url.set_fragment(Some("#fragment\"other\"")), Err(Error::InvalidFragment))); } proptest::proptest! { diff --git a/identity_did/src/error.rs b/identity_did/src/error.rs index 07e7bab9c4..f88165ecce 100644 --- a/identity_did/src/error.rs +++ b/identity_did/src/error.rs @@ -1,70 +1,42 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -//! Errors that may occur when working with Decentralized Identifiers. +use core::fmt::Debug; -/// Alias for a [`Result`][::core::result::Result] with the error type [Error]. -pub type Result = ::core::result::Result; - -/// This type represents all possible errors that can occur in the library. #[derive(Debug, thiserror::Error, strum::IntoStaticStr)] +#[non_exhaustive] +/// Error type caused by invalid DID handling. pub enum Error { - /// Caused by errors from the [identity_core] crate. - #[error("{0}")] - CoreError(#[from] ::identity_core::Error), - #[error("{0}")] - InvalidDID(#[from] crate::did::DIDError), - - #[error("Verification Method Not Found")] - MethodNotFound, - - /// Caused by invalid or missing properties when constructing a [`CoreDocument`](crate::document::CoreDocument). - #[error("invalid document property: {0}")] - InvalidDocument(&'static str, #[source] Option<::identity_core::Error>), - /// Caused by invalid or missing properties when constructing a [`Service`](crate::service::Service). - #[error("invalid service property: {0}")] - InvalidService(&'static str), - /// Caused by invalid or missing properties when constructing a - /// [`VerificationMethod`](crate::verification::VerificationMethod). - #[error("invalid verification method property: {0}")] - InvalidMethod(&'static str), - - #[error("invalid or empty `id` fragment")] - MissingIdFragment, - #[error("Invalid Verification Method Type")] - InvalidMethodType, - /// Caused by attempting to add a verification method to a document, where a method or service with the same fragment - /// already exists. - #[error("unable to insert method: the id is already in use")] - MethodInsertionError, - /// Caused by attempting to attach or detach a relationship on an embedded method. - #[error("unable to modify relationships on embedded methods, use insert or remove instead")] - InvalidMethodEmbedded, + #[error("Invalid Authority")] + InvalidAuthority, + #[error("Invalid Fragment")] + InvalidFragment, + #[error("Invalid Method Id")] + InvalidMethodId, + #[error("Invalid Method Name")] + InvalidMethodName, + #[error("Invalid Path")] + InvalidPath, + #[error("Invalid Query")] + InvalidQuery, + #[error("Invalid Scheme")] + InvalidScheme, - /// Caused by attempting to insert a service whose id overlaps with a verification method or an already existing - /// service. - #[error("unable to insert service: the id is already in use")] - InvalidServiceInsertion, - - #[error("Unknown Method Scope")] - UnknownMethodScope, - #[error("Unknown Method Type")] - UnknownMethodType, - - #[error("Invalid Key Data")] - InvalidKeyData, - #[error("Invalid Base58 Key Data")] - InvalidKeyDataBase58, - #[error("Invalid Multibase Key Data")] - InvalidKeyDataMultibase, - - #[error("signature verification failed: {0}")] - InvalidSignature(&'static str), + #[error("{0}")] + Other(&'static str), +} - #[error("unable to decode base64 string: `{0}`")] - Base64DecodingError(String, #[source] identity_core::error::Error), - #[error("revocation bitmap could not be deserialized or decompressed")] - BitmapDecodingError(#[source] std::io::Error), - #[error("revocation bitmap could not be serialized or compressed")] - BitmapEncodingError(#[source] std::io::Error), +impl From for Error { + fn from(error: did_url::Error) -> Self { + match error { + did_url::Error::InvalidAuthority => Self::InvalidAuthority, + did_url::Error::InvalidFragment => Self::InvalidFragment, + did_url::Error::InvalidMethodId => Self::InvalidMethodId, + did_url::Error::InvalidMethodName => Self::InvalidMethodName, + did_url::Error::InvalidPath => Self::InvalidPath, + did_url::Error::InvalidQuery => Self::InvalidQuery, + did_url::Error::InvalidScheme => Self::InvalidScheme, + error => Self::Other(error.as_str()), + } + } } diff --git a/identity_did/src/lib.rs b/identity_did/src/lib.rs index 566d9a74cf..52e556c8c9 100644 --- a/identity_did/src/lib.rs +++ b/identity_did/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![forbid(unsafe_code)] @@ -17,21 +17,15 @@ // clippy::missing_errors_doc )] -#[macro_use] -extern crate serde; +#[allow(clippy::module_inception)] +mod did; +mod did_url; +mod error; -#[deprecated(since = "0.5.0", note = "diff chain features are slated for removal")] -pub mod diff; - -pub mod did; -pub mod document; -pub mod error; -#[cfg(feature = "revocation-bitmap")] -pub mod revocation; -pub mod service; -pub mod utils; -pub mod verifiable; -pub mod verification; - -pub use self::error::Error; -pub use self::error::Result; +pub use crate::did_url::CoreDIDUrl; +pub use crate::did_url::DIDUrl; +pub use crate::did_url::RelativeDIDUrl; +pub use ::did_url::DID as BaseDIDUrl; +pub use did::CoreDID; +pub use did::DID; +pub use error::Error; diff --git a/identity_did/src/revocation/mod.rs b/identity_did/src/revocation/mod.rs deleted file mode 100644 index 7667575ef4..0000000000 --- a/identity_did/src/revocation/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2020-2022 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! Contains a bitmap for managing credential revocation. -mod bitmap; - -pub use self::bitmap::RevocationBitmap; diff --git a/identity_document/Cargo.toml b/identity_document/Cargo.toml new file mode 100644 index 0000000000..980845e86f --- /dev/null +++ b/identity_document/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "identity_document" +version = "0.7.0-alpha.4" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +keywords = ["iota", "tangle", "identity", "did"] +license.workspace = true +readme = "./README.md" +repository.workspace = true +rust-version.workspace = true +description = "Method-agnostic implementation of the Decentralized Identifiers (DID) standard." + +[dependencies] +did_url = { version = "0.1", default-features = false, features = ["std", "serde"] } +form_urlencoded = { version = "1.0.1", default-features = false } +identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core" } +identity_did = { version = "=0.7.0-alpha.4", path = "../identity_did" } +identity_verification = { version = "=0.7.0-alpha.4", path = "../identity_verification", default-features = false } +indexmap = { version = "1.7", default-features = false, features = ["std", "serde-1"] } +serde.workspace = true +strum.workspace = true +thiserror.workspace = true + +[dev-dependencies] +criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } +serde_json = { version = "1.0", default-features = false } + +[[bench]] +name = "deserialize_document" +harness = false diff --git a/identity_document/README.md b/identity_document/README.md new file mode 100644 index 0000000000..815d496623 --- /dev/null +++ b/identity_document/README.md @@ -0,0 +1,4 @@ +IOTA Identity - Document +=== + +Method-agnostic implementation of DID Documents from the Decentralized Identifiers (DID) standard from W3C. \ No newline at end of file diff --git a/identity_did/benches/deserialize_document.rs b/identity_document/benches/deserialize_document.rs similarity index 99% rename from identity_did/benches/deserialize_document.rs rename to identity_document/benches/deserialize_document.rs index ba92a50350..666e305796 100644 --- a/identity_did/benches/deserialize_document.rs +++ b/identity_document/benches/deserialize_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use criterion::Throughput; @@ -8,7 +8,7 @@ use criterion::criterion_group; use criterion::criterion_main; use criterion::BenchmarkId; use criterion::Criterion; -use identity_did::document::CoreDocument; +use identity_document::document::CoreDocument; const JSON_DOC_SHORT: &str = r#" { diff --git a/identity_did/src/diff/diff_document.rs b/identity_document/src/diff/diff_document.rs similarity index 98% rename from identity_did/src/diff/diff_document.rs rename to identity_document/src/diff/diff_document.rs index a381fef56c..a8622d07ba 100644 --- a/identity_did/src/diff/diff_document.rs +++ b/identity_document/src/diff/diff_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Deserialize; @@ -14,13 +14,13 @@ use identity_core::diff::DiffVec; use identity_core::diff::Error; use identity_core::diff::Result; -use crate::did::CoreDID; -use crate::did::DID; use crate::document::CoreDocument; use crate::document::CoreDocumentData; use crate::service::Service; -use crate::verification::MethodRef; -use crate::verification::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DID; +use identity_verification::MethodRef; +use identity_verification::VerificationMethod; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[serde(bound(deserialize = ""))] @@ -333,13 +333,13 @@ mod test { use identity_core::convert::ToJson; use identity_core::diff::DiffString; - use crate::did::CoreDIDUrl; - use crate::did::DID; use crate::service::ServiceBuilder; use crate::service::ServiceEndpoint; - use crate::verification::MethodBuilder; - use crate::verification::MethodData; - use crate::verification::MethodType; + use identity_did::CoreDIDUrl; + use identity_did::DID; + use identity_verification::MethodBuilder; + use identity_verification::MethodData; + use identity_verification::MethodType; use super::*; diff --git a/identity_did/src/diff/diff_service.rs b/identity_document/src/diff/diff_service.rs similarity index 98% rename from identity_did/src/diff/diff_service.rs rename to identity_document/src/diff/diff_service.rs index 4e2d78861a..5cfc40c480 100644 --- a/identity_did/src/diff/diff_service.rs +++ b/identity_document/src/diff/diff_service.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Deserialize; @@ -10,12 +10,12 @@ use identity_core::diff::Diff; use identity_core::diff::Error; use identity_core::diff::Result; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::service::Service; use crate::service::ServiceBuilder; use crate::service::ServiceEndpoint; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct DiffService @@ -175,7 +175,6 @@ impl Diff for ServiceEndpoint { mod test { use indexmap::IndexMap; - use crate::did::CoreDIDUrl; use identity_core::common::Object; use identity_core::common::OrderedSet; use identity_core::common::Url; @@ -183,6 +182,7 @@ mod test { use identity_core::convert::ToJson; use identity_core::diff::DiffString; use identity_core::diff::DiffVec; + use identity_did::CoreDIDUrl; use super::*; diff --git a/identity_document/src/diff/mod.rs b/identity_document/src/diff/mod.rs new file mode 100644 index 0000000000..89343abe4a --- /dev/null +++ b/identity_document/src/diff/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub use self::diff_document::DiffDocument; +pub use self::diff_service::DiffService; +pub use identity_verification::diff::DiffMethod; +pub use identity_verification::diff::DiffMethodData; +pub use identity_verification::diff::DiffMethodRef; + +mod diff_document; +mod diff_service; diff --git a/identity_did/src/document/builder.rs b/identity_document/src/document/builder.rs similarity index 95% rename from identity_did/src/document/builder.rs rename to identity_document/src/document/builder.rs index dfdce80e6b..445cd372fc 100644 --- a/identity_did/src/document/builder.rs +++ b/identity_document/src/document/builder.rs @@ -1,17 +1,17 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::KeyComparable; use identity_core::common::Object; use identity_core::common::Url; -use crate::did::CoreDID; -use crate::did::DID; use crate::document::CoreDocument; use crate::error::Result; use crate::service::Service; -use crate::verification::MethodRef; -use crate::verification::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DID; +use identity_verification::MethodRef; +use identity_verification::VerificationMethod; /// A `DocumentBuilder` is used to generate a customized [`Document`](crate::document::CoreDocument). #[derive(Clone, Debug)] @@ -142,9 +142,9 @@ where #[cfg(test)] mod tests { use super::*; - use crate::verification::MethodData; - use crate::verification::MethodType; use crate::Error; + use identity_verification::MethodData; + use identity_verification::MethodType; #[test] fn test_missing_id() { diff --git a/identity_did/src/document/core_document.rs b/identity_document/src/document/core_document.rs similarity index 93% rename from identity_did/src/document/core_document.rs rename to identity_document/src/document/core_document.rs index f062864280..bc10511ebc 100644 --- a/identity_did/src/document/core_document.rs +++ b/identity_document/src/document/core_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryInto as _; @@ -24,9 +24,6 @@ use identity_core::crypto::ProofPurpose; use identity_core::crypto::Verifier; use serde::Serializer; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::document::Document; use crate::document::DocumentBuilder; use crate::error::Error; @@ -36,13 +33,16 @@ use crate::utils::DIDUrlQuery; use crate::utils::Queryable; use crate::verifiable::DocumentSigner; use crate::verifiable::VerifierOptions; -use crate::verification::MethodRef; -use crate::verification::MethodRelationship; -use crate::verification::MethodScope; -use crate::verification::MethodType; -use crate::verification::MethodUriType; -use crate::verification::TryMethod; -use crate::verification::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; +use identity_verification::MethodRef; +use identity_verification::MethodRelationship; +use identity_verification::MethodScope; +use identity_verification::MethodType; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; +use identity_verification::VerificationMethod; #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[rustfmt::skip] @@ -316,6 +316,14 @@ where &self.data.service } + /// # Warning + /// + /// Changing a service's identifier can drastically alter the results of + /// [`Self::resolve_service`](CoreDocument::resolve_service()) and the related [DID URL dereferencing](https://w3c-ccg.github.io/did-resolution/#dereferencing) algorithm. + pub fn service_mut_unchecked(&mut self) -> &mut OrderedSet> { + &mut self.data.service + } + /// Returns a reference to the custom `CoreDocument` properties. pub fn properties(&self) -> &T { &self.data.properties @@ -896,7 +904,7 @@ where // Check method type. if let Some(ref method_types) = options.method_type { - if !method_types.is_empty() && !method_types.contains(&method.type_) { + if !method_types.is_empty() && !method_types.contains(&method.type_()) { return Err(Error::InvalidSignature("invalid method type")); } } @@ -938,7 +946,7 @@ where where X: Serialize + GetSignature + ?Sized, { - let public_key: Vec = method.data().try_decode()?; + let public_key: Vec = method.data().try_decode().map_err(Error::InvalidKeyData)?; match method.type_() { MethodType::Ed25519VerificationKey2018 => { @@ -1008,71 +1016,6 @@ where } } -#[cfg(feature = "revocation-bitmap")] -mod core_document_revocation { - use identity_core::common::KeyComparable; - - use crate::did::DID; - use crate::revocation::RevocationBitmap; - use crate::service::Service; - use crate::utils::DIDUrlQuery; - use crate::utils::Queryable; - use crate::Error; - use crate::Result; - - use super::CoreDocument; - - impl CoreDocument - where - D: DID + KeyComparable, - { - /// If the document has a [`RevocationBitmap`] service identified by `service_query`, - /// revoke all specified `indices`. - pub fn revoke_credentials<'query, 'me, Q>(&mut self, service_query: Q, indices: &[u32]) -> Result<()> - where - Q: Into>, - { - self.update_revocation_bitmap(service_query, |revocation_bitmap| { - for credential in indices { - revocation_bitmap.revoke(*credential); - } - }) - } - - /// If the document has a [`RevocationBitmap`] service identified by `service_query`, - /// unrevoke all specified `indices`. - pub fn unrevoke_credentials<'query, 'me, Q>(&'me mut self, service_query: Q, indices: &[u32]) -> Result<()> - where - Q: Into>, - { - self.update_revocation_bitmap(service_query, |revocation_bitmap| { - for credential in indices { - revocation_bitmap.unrevoke(*credential); - } - }) - } - - fn update_revocation_bitmap<'query, 'me, F, Q>(&'me mut self, service_query: Q, f: F) -> Result<()> - where - F: FnOnce(&mut RevocationBitmap), - Q: Into>, - { - let service: &mut Service = self - .data - .service - .query_mut(service_query) - .ok_or(Error::InvalidService("invalid id - service not found"))?; - - let mut revocation_bitmap: RevocationBitmap = RevocationBitmap::try_from(&*service)?; - f(&mut revocation_bitmap); - - std::mem::swap(service.service_endpoint_mut(), &mut revocation_bitmap.to_endpoint()?); - - Ok(()) - } - } -} - // ============================================================================= // Signature Extensions // ============================================================================= @@ -1113,8 +1056,8 @@ mod tests { use identity_core::convert::ToJson; use crate::service::ServiceBuilder; - use crate::verification::MethodBuilder; - use crate::verification::MethodData; + use identity_verification::MethodBuilder; + use identity_verification::MethodData; use super::*; @@ -1462,60 +1405,6 @@ mod tests { assert!(document.verification_method().query(method3.id()).is_none()); } - #[cfg(feature = "revocation-bitmap")] - #[test] - fn test_revocation() { - let mut document: CoreDocument = document(); - let indices_1 = [3, 9, 254, 65536]; - let indices_2 = [2, 15, 1337, 1000]; - - let service_id = document.id().to_url().join("#revocation-service").unwrap(); - - // The methods error if the service doesn't exist. - assert!(document.revoke_credentials(&service_id, &indices_2).is_err()); - assert!(document.unrevoke_credentials(&service_id, &indices_2).is_err()); - - // Add service with indices_1 already revoked. - let mut bitmap: crate::revocation::RevocationBitmap = crate::revocation::RevocationBitmap::new(); - for index in indices_1.iter() { - bitmap.revoke(*index); - } - assert!(document - .insert_service( - Service::builder(Object::new()) - .id(service_id.clone()) - .type_(crate::revocation::RevocationBitmap::TYPE) - .service_endpoint(bitmap.to_endpoint().unwrap()) - .build() - .unwrap() - ) - .is_ok()); - - // Revoke indices_2. - document.revoke_credentials(&service_id, &indices_2).unwrap(); - let service: &Service = document.resolve_service(&service_id).unwrap(); - let decoded_bitmap: crate::revocation::RevocationBitmap = service.try_into().unwrap(); - - // We expect all indices to be revoked now. - for index in indices_1.iter().chain(indices_2.iter()) { - assert!(decoded_bitmap.is_revoked(*index)); - } - - // Unrevoke indices_1. - document.unrevoke_credentials(&service_id, &indices_1).unwrap(); - - let service: &Service = document.resolve_service(&service_id).unwrap(); - let decoded_bitmap: crate::revocation::RevocationBitmap = service.try_into().unwrap(); - - // Expect indices_2 to be revoked, but not indices_1. - for index in indices_2 { - assert!(decoded_bitmap.is_revoked(index)); - } - for index in indices_1 { - assert!(!decoded_bitmap.is_revoked(index)); - } - } - #[test] fn test_service_updates() { let mut document = document(); diff --git a/identity_did/src/document/mod.rs b/identity_document/src/document/mod.rs similarity index 90% rename from identity_did/src/document/mod.rs rename to identity_document/src/document/mod.rs index 5571f327e1..6eeb2df917 100644 --- a/identity_did/src/document/mod.rs +++ b/identity_document/src/document/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Defines the core (implementation agnostic) DID Document type. diff --git a/identity_did/src/document/traits.rs b/identity_document/src/document/traits.rs similarity index 94% rename from identity_did/src/document/traits.rs rename to identity_document/src/document/traits.rs index 60a3e270e3..9f228b36f9 100644 --- a/identity_did/src/document/traits.rs +++ b/identity_document/src/document/traits.rs @@ -1,17 +1,17 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Serialize; use identity_core::crypto::GetSignature; -use crate::did::DID; use crate::service::Service; use crate::utils::DIDUrlQuery; use crate::verifiable::VerifierOptions; -use crate::verification::MethodScope; -use crate::verification::VerificationMethod; use crate::Result; +use identity_did::DID; +use identity_verification::MethodScope; +use identity_verification::VerificationMethod; // TODO: add sign_data, split sign/verify to separate trait as first step towards // supporting custom signature schemes. Replace DocumentSigner with trait? diff --git a/identity_document/src/error.rs b/identity_document/src/error.rs new file mode 100644 index 0000000000..8945f370f7 --- /dev/null +++ b/identity_document/src/error.rs @@ -0,0 +1,66 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! Errors that may occur when working with DID Documents. + +/// Alias for a [`Result`][::core::result::Result] with the error type [Error]. +pub type Result = ::core::result::Result; + +/// This type represents all possible errors that can occur in the library. +#[derive(Debug, thiserror::Error, strum::IntoStaticStr)] +pub enum Error { + /// Caused by errors from the [identity_core] crate. + #[error("{0}")] + CoreError(#[from] ::identity_core::Error), + #[error("{0}")] + InvalidDID(#[from] identity_did::Error), + + #[error("Verification Method Not Found")] + MethodNotFound, + + /// Caused by invalid or missing properties when constructing a [`CoreDocument`](crate::document::CoreDocument). + #[error("invalid document property: {0}")] + InvalidDocument(&'static str, #[source] Option<::identity_core::Error>), + /// Caused by invalid or missing properties when constructing a [`Service`](crate::service::Service). + #[error("invalid service property: {0}")] + InvalidService(&'static str), + /// Caused by invalid or missing properties when constructing a + /// [`VerificationMethod`](::identity_verification::VerificationMethod). + #[error("invalid verification method property: {0}")] + InvalidMethod(&'static str), + + #[error("invalid or empty `id` fragment")] + MissingIdFragment, + #[error("Invalid Verification Method Type")] + InvalidMethodType, + /// Caused by attempting to add a verification method to a document, where a method or service with the same fragment + /// already exists. + #[error("unable to insert method: the id is already in use")] + MethodInsertionError, + /// Caused by attempting to attach or detach a relationship on an embedded method. + #[error("unable to modify relationships on embedded methods, use insert or remove instead")] + InvalidMethodEmbedded, + + /// Caused by attempting to insert a service whose id overlaps with a verification method or an already existing + /// service. + #[error("unable to insert service: the id is already in use")] + InvalidServiceInsertion, + + #[error("Unknown Method Scope")] + UnknownMethodScope, + #[error("Unknown Method Type")] + UnknownMethodType, + + #[error("invalid key data")] + InvalidKeyData(#[source] identity_verification::Error), + + #[error("signature verification failed: {0}")] + InvalidSignature(&'static str), + + #[error("unable to decode base64 string: `{0}`")] + Base64DecodingError(String, #[source] identity_core::error::Error), + #[error("revocation bitmap could not be deserialized or decompressed")] + BitmapDecodingError(#[source] std::io::Error), + #[error("revocation bitmap could not be serialized or compressed")] + BitmapEncodingError(#[source] std::io::Error), +} diff --git a/identity_document/src/lib.rs b/identity_document/src/lib.rs new file mode 100644 index 0000000000..aac303b061 --- /dev/null +++ b/identity_document/src/lib.rs @@ -0,0 +1,33 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] +#![allow(deprecated)] +#![doc = include_str!("./../README.md")] +#![allow(clippy::upper_case_acronyms)] +#![warn( + rust_2018_idioms, + unreachable_pub, + // missing_docs, + rustdoc::missing_crate_level_docs, + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::private_doc_tests, + clippy::missing_safety_doc, + // clippy::missing_errors_doc +)] + +#[macro_use] +extern crate serde; + +#[deprecated(since = "0.5.0", note = "diff chain features are slated for removal")] +pub mod diff; + +pub mod document; +pub mod error; +pub mod service; +pub mod utils; +pub mod verifiable; + +pub use self::error::Error; +pub use self::error::Result; diff --git a/identity_did/src/service/builder.rs b/identity_document/src/service/builder.rs similarity index 96% rename from identity_did/src/service/builder.rs rename to identity_document/src/service/builder.rs index 70ea63cc4e..5202a3143b 100644 --- a/identity_did/src/service/builder.rs +++ b/identity_document/src/service/builder.rs @@ -1,14 +1,14 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Object; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::error::Result; use crate::service::Service; use crate::service::ServiceEndpoint; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; /// A `ServiceBuilder` is used to generate a customized `Service`. #[derive(Clone, Debug)] diff --git a/identity_did/src/service/mod.rs b/identity_document/src/service/mod.rs similarity index 89% rename from identity_did/src/service/mod.rs rename to identity_document/src/service/mod.rs index bc827aac34..0ae906fd58 100644 --- a/identity_did/src/service/mod.rs +++ b/identity_document/src/service/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Implements the DID Document Service specification. diff --git a/identity_did/src/service/service.rs b/identity_document/src/service/service.rs similarity index 98% rename from identity_did/src/service/service.rs rename to identity_document/src/service/service.rs index c176b2ccdd..c15d6db696 100644 --- a/identity_did/src/service/service.rs +++ b/identity_document/src/service/service.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -13,13 +13,13 @@ use identity_core::common::Object; use identity_core::common::OneOrSet; use identity_core::convert::FmtJson; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::error::Error; use crate::error::Result; use crate::service::ServiceBuilder; use crate::service::ServiceEndpoint; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; /// A DID Document Service used to enable trusted interactions associated with a DID subject. /// @@ -192,11 +192,11 @@ where #[cfg(test)] mod tests { use super::*; - use crate::did::CoreDIDUrl; use identity_core::common::OrderedSet; use identity_core::common::Url; use identity_core::convert::FromJson; use identity_core::convert::ToJson; + use identity_did::CoreDIDUrl; #[test] fn test_service_types_serde() { diff --git a/identity_did/src/service/service_endpoint.rs b/identity_document/src/service/service_endpoint.rs similarity index 99% rename from identity_did/src/service/service_endpoint.rs rename to identity_document/src/service/service_endpoint.rs index 7246b54e62..ee8aea70bf 100644 --- a/identity_did/src/service/service_endpoint.rs +++ b/identity_document/src/service/service_endpoint.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; diff --git a/identity_did/src/utils/did_url_query.rs b/identity_document/src/utils/did_url_query.rs similarity index 98% rename from identity_did/src/utils/did_url_query.rs rename to identity_document/src/utils/did_url_query.rs index 13b444ec2e..7c07c2c09f 100644 --- a/identity_did/src/utils/did_url_query.rs +++ b/identity_document/src/utils/did_url_query.rs @@ -1,14 +1,14 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::borrow::Cow; use identity_core::crypto::Proof; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::RelativeDIDUrl; -use crate::did::DID; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::RelativeDIDUrl; +use identity_did::DID; /// Specifies a DIDUrl or fragment to query a service or method in a DID Document. #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -113,7 +113,7 @@ impl<'query> From<&'query Proof> for DIDUrlQuery<'query> { #[cfg(test)] mod tests { - use crate::did::CoreDIDUrl; + use identity_did::CoreDIDUrl; use std::ops::Not; use super::*; diff --git a/identity_did/src/utils/mod.rs b/identity_document/src/utils/mod.rs similarity index 83% rename from identity_did/src/utils/mod.rs rename to identity_document/src/utils/mod.rs index 9745ad5f92..ae2e3b1f7b 100644 --- a/identity_did/src/utils/mod.rs +++ b/identity_document/src/utils/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Functionality for Querying DID Urls. diff --git a/identity_did/src/utils/queryable.rs b/identity_document/src/utils/queryable.rs similarity index 93% rename from identity_did/src/utils/queryable.rs rename to identity_document/src/utils/queryable.rs index 686436ec07..6a8132e50e 100644 --- a/identity_did/src/utils/queryable.rs +++ b/identity_document/src/utils/queryable.rs @@ -1,12 +1,12 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::KeyComparable; use identity_core::common::OrderedSet; -use crate::did::DIDUrl; -use crate::did::DID; use crate::utils::DIDUrlQuery; +use identity_did::DIDUrl; +use identity_did::DID; /// Allows retrieving an entry from a collection using a custom query type. /// diff --git a/identity_did/src/verifiable/document_signer.rs b/identity_document/src/verifiable/document_signer.rs similarity index 92% rename from identity_did/src/verifiable/document_signer.rs rename to identity_document/src/verifiable/document_signer.rs index d70f0133f1..289e12a933 100644 --- a/identity_did/src/verifiable/document_signer.rs +++ b/identity_document/src/verifiable/document_signer.rs @@ -1,10 +1,8 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Serialize; -use crate::did::CoreDID; -use crate::did::DID; use identity_core::common::KeyComparable; use identity_core::common::Object; use identity_core::common::Timestamp; @@ -15,14 +13,16 @@ use identity_core::crypto::ProofOptions; use identity_core::crypto::ProofPurpose; use identity_core::crypto::SetSignature; use identity_core::crypto::Signer; +use identity_did::CoreDID; +use identity_did::DID; use crate::document::CoreDocument; use crate::utils::DIDUrlQuery; -use crate::verification::MethodType; -use crate::verification::TryMethod; -use crate::verification::VerificationMethod; use crate::Error; use crate::Result; +use identity_verification::MethodType; +use identity_verification::TryMethod; +use identity_verification::VerificationMethod; // ============================================================================= // Document Signer - Simplifying Digital Signature Creation Since 2021 @@ -125,7 +125,7 @@ where { let query: DIDUrlQuery<'_> = self.method.clone().ok_or(Error::MethodNotFound)?; let method: &VerificationMethod = self.document.resolve_method(query, None).ok_or(Error::MethodNotFound)?; - let method_uri: String = X::try_method(method)?; + let method_uri: String = X::try_method(method).map_err(|_| Error::MissingIdFragment)?; match method.type_() { MethodType::Ed25519VerificationKey2018 => { diff --git a/identity_did/src/verifiable/mod.rs b/identity_document/src/verifiable/mod.rs similarity index 90% rename from identity_did/src/verifiable/mod.rs rename to identity_document/src/verifiable/mod.rs index ec4346086c..97f0488ab7 100644 --- a/identity_did/src/verifiable/mod.rs +++ b/identity_document/src/verifiable/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! Additional functionality for DID assisted digital signatures. diff --git a/identity_did/src/verifiable/properties.rs b/identity_document/src/verifiable/properties.rs similarity index 95% rename from identity_did/src/verifiable/properties.rs rename to identity_document/src/verifiable/properties.rs index 4d33c55b96..be8f6ef477 100644 --- a/identity_did/src/verifiable/properties.rs +++ b/identity_document/src/verifiable/properties.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::ops::Deref; @@ -11,8 +11,8 @@ use identity_core::crypto::Proof; use identity_core::crypto::SetSignature; use identity_core::diff::Diff; -use crate::verification::MethodUriType; -use crate::verification::TryMethod; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; /// A generic container for a [`digital signature`][Proof] and a set of properties. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] diff --git a/identity_did/src/verifiable/tests.rs b/identity_document/src/verifiable/tests.rs similarity index 96% rename from identity_did/src/verifiable/tests.rs rename to identity_document/src/verifiable/tests.rs index de590ff9cf..0a56a951c1 100644 --- a/identity_did/src/verifiable/tests.rs +++ b/identity_document/src/verifiable/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Timestamp; @@ -10,17 +10,17 @@ use identity_core::crypto::Proof; use identity_core::crypto::ProofPurpose; use identity_core::crypto::SetSignature; -use crate::did::CoreDID; -use crate::did::DID; use crate::document::CoreDocument; use crate::verifiable::VerifierOptions; -use crate::verification::MethodData; -use crate::verification::MethodRelationship; -use crate::verification::MethodScope; -use crate::verification::MethodType; -use crate::verification::MethodUriType; -use crate::verification::TryMethod; -use crate::verification::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DID; +use identity_verification::MethodData; +use identity_verification::MethodRelationship; +use identity_verification::MethodScope; +use identity_verification::MethodType; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; +use identity_verification::VerificationMethod; #[derive(Debug, Serialize)] struct MockObject { diff --git a/identity_did/src/verifiable/verifier_options.rs b/identity_document/src/verifiable/verifier_options.rs similarity index 94% rename from identity_did/src/verifiable/verifier_options.rs rename to identity_document/src/verifiable/verifier_options.rs index a13ecf25d5..ea619266df 100644 --- a/identity_did/src/verifiable/verifier_options.rs +++ b/identity_document/src/verifiable/verifier_options.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::crypto::ProofPurpose; @@ -6,8 +6,8 @@ use serde; use serde::Deserialize; use serde::Serialize; -use crate::verification::MethodScope; -use crate::verification::MethodType; +use identity_verification::MethodScope; +use identity_verification::MethodType; /// Holds additional options for verifying a proof with /// [`CoreDocument::verify_data`](crate::document::CoreDocument::verify_data). diff --git a/identity_iota/Cargo.toml b/identity_iota/Cargo.toml index 79e6b015ed..e6f3505227 100644 --- a/identity_iota/Cargo.toml +++ b/identity_iota/Cargo.toml @@ -1,22 +1,24 @@ [package] name = "identity_iota" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] -edition = "2021" -homepage = "https://www.iota.org" +authors.workspace = true +edition.workspace = true +homepage.workspace = true keywords = ["iota", "tangle", "identity", "did", "ssi"] -license = "Apache-2.0" +license.workspace = true readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" -rust-version = "1.62" +repository.workspace = true +rust-version.workspace = true description = "Framework for Self-Sovereign Identity with IOTA DID." [dependencies] identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core", default-features = false } identity_credential = { version = "=0.7.0-alpha.4", path = "../identity_credential", features = ["validator"], default-features = false } identity_did = { version = "=0.7.0-alpha.4", path = "../identity_did", default-features = false } +identity_document = { version = "=0.7.0-alpha.4", path = "../identity_document", default-features = false } identity_iota_core = { version = "=0.7.0-alpha.4", path = "../identity_iota_core", default-features = false } identity_resolver = { version = "=0.7.0-alpha.4", path = "../identity_resolver", default-features = false, optional = true } +identity_verification = { version = "=0.7.0-alpha.4", path = "../identity_verification", default-features = false } [dev-dependencies] anyhow = "1.0.64" diff --git a/identity_iota/README.md b/identity_iota/README.md index 2742ac8c5a..9eb3143456 100644 --- a/identity_iota/README.md +++ b/identity_iota/README.md @@ -92,7 +92,7 @@ _main.__rs_ use identity_iota::core::ToJson; use identity_iota::crypto::KeyPair; use identity_iota::crypto::KeyType; -use identity_iota::did::MethodScope; +use identity_iota::verification::MethodScope; use identity_iota::iota::IotaClientExt; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; diff --git a/identity_iota/src/lib.rs b/identity_iota/src/lib.rs index 6b4e8a8414..d0172b7653 100644 --- a/identity_iota/src/lib.rs +++ b/identity_iota/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 #![cfg_attr(docsrs, feature(doc_cfg))] @@ -48,6 +48,8 @@ pub mod credential { pub use identity_credential::credential::*; pub use identity_credential::error::*; pub use identity_credential::presentation::*; + #[cfg(feature = "revocation-bitmap")] + pub use identity_credential::revocation::*; pub use identity_credential::validator::*; } @@ -55,18 +57,20 @@ pub mod did { //! Decentralized Identifiers //! //! [Specification](https://www.w3.org/TR/did-core/) + pub use identity_did::*; +} +pub mod document { + //! DID Documents + //! + //! [Specification](https://www.w3.org/TR/did-core/) - pub use identity_did::document::*; - pub use identity_did::error::*; - #[cfg(feature = "revocation-bitmap")] - pub use identity_did::revocation::*; - pub use identity_did::service::*; - pub use identity_did::utils::*; - pub use identity_did::verification::*; + pub use identity_document::document::*; + pub use identity_document::error::*; - pub use identity_did::did::*; + pub use identity_document::service::*; + pub use identity_document::utils::*; - pub use identity_did::verifiable; + pub use identity_document::verifiable; } pub mod iota { @@ -118,3 +122,8 @@ pub mod resolver { pub use identity_resolver::*; } + +pub mod verification { + //! Types for verifiable data + pub use identity_verification::*; +} diff --git a/identity_iota_client_legacy/src/chain/diff_chain.rs b/identity_iota_client_legacy/src/chain/diff_chain.rs index ac94ca5e7e..63b20315fd 100644 --- a/identity_iota_client_legacy/src/chain/diff_chain.rs +++ b/identity_iota_client_legacy/src/chain/diff_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -274,7 +274,7 @@ mod tests { use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; use identity_core::json; - use identity_did::did::DID; + use identity_did::DID; use identity_did::service::Service; use identity_iota_core_legacy::diff::DiffMessage; use identity_iota_core_legacy::document::IotaDocument; diff --git a/identity_iota_client_legacy/src/chain/document_chain.rs b/identity_iota_client_legacy/src/chain/document_chain.rs index 0b2ec43830..c81f9d14dc 100644 --- a/identity_iota_client_legacy/src/chain/document_chain.rs +++ b/identity_iota_client_legacy/src/chain/document_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -170,7 +170,7 @@ mod test { use identity_core::crypto::KeyType; use identity_core::crypto::PrivateKey; use identity_core::crypto::ProofOptions; - use identity_did::did::DID; + use identity_did::DID; use identity_did::verification::MethodBuilder; use identity_did::verification::MethodData; use identity_did::verification::MethodRef; diff --git a/identity_iota_client_legacy/src/error.rs b/identity_iota_client_legacy/src/error.rs index c69f091773..8785f1abe8 100644 --- a/identity_iota_client_legacy/src/error.rs +++ b/identity_iota_client_legacy/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub type Result = core::result::Result; @@ -10,9 +10,9 @@ pub enum Error { #[error("{0}")] CredError(#[from] identity_credential::Error), #[error("{0}")] - InvalidDID(#[from] identity_did::did::DIDError), + InvalidDID(#[from] identity_did::Error), #[error("{0}")] - InvalidDoc(#[from] identity_did::Error), + InvalidDoc(#[from] identity_document::Error), #[error("{0}")] ClientError(#[from] iota_client::error::Error), #[error("{0}")] diff --git a/identity_iota_client_legacy/src/tangle/explorer.rs b/identity_iota_client_legacy/src/tangle/explorer.rs index a1640d8754..be0fbab9b1 100644 --- a/identity_iota_client_legacy/src/tangle/explorer.rs +++ b/identity_iota_client_legacy/src/tangle/explorer.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryFrom; @@ -7,7 +7,7 @@ use core::fmt::Formatter; use std::str::FromStr; use identity_core::common::Url; -use identity_did::did::DID; +use identity_did::DID; use identity_iota_core_legacy::tangle::MessageId; use serde; use serde::Deserialize; diff --git a/identity_iota_client_legacy/src/tangle/message/message_ext.rs b/identity_iota_client_legacy/src/tangle/message/message_ext.rs index 97ead9c051..a6f664603a 100644 --- a/identity_iota_client_legacy/src/tangle/message/message_ext.rs +++ b/identity_iota_client_legacy/src/tangle/message/message_ext.rs @@ -1,9 +1,9 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::convert::FromJson; use identity_core::convert::ToJson; -use identity_did::did::DID; +use identity_did::DID; use identity_iota_core_legacy::did::IotaDID; use identity_iota_core_legacy::diff::DiffMessage; use identity_iota_core_legacy::tangle::Message; diff --git a/identity_iota_client_legacy/src/tangle/publish.rs b/identity_iota_client_legacy/src/tangle/publish.rs index 3f6e220376..6641d69daa 100644 --- a/identity_iota_client_legacy/src/tangle/publish.rs +++ b/identity_iota_client_legacy/src/tangle/publish.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_iota_core_legacy::document::IotaDocument; @@ -38,7 +38,7 @@ impl PublishType { mod test { use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; - use identity_did::did::DID; + use identity_did::DID; use identity_did::verification::MethodScope; use identity_iota_core_legacy::did::IotaDIDUrl; use identity_iota_core_legacy::document::IotaVerificationMethod; diff --git a/identity_iota_client_legacy/src/tangle/resolver.rs b/identity_iota_client_legacy/src/tangle/resolver.rs index eb2312db89..d3ee40877e 100644 --- a/identity_iota_client_legacy/src/tangle/resolver.rs +++ b/identity_iota_client_legacy/src/tangle/resolver.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::collections::HashMap; @@ -287,9 +287,9 @@ mod tests { use identity_credential::credential::Subject; use identity_credential::validator::CredentialValidationOptions; use identity_credential::validator::SubjectHolderRelationship; - use identity_did::did::CoreDID; - use identity_did::did::DID; - use identity_did::document::CoreDocument; + use identity_did::CoreDID; + use identity_did::DID; + use identity_document::document::CoreDocument; use identity_did::verifiable::VerifierOptions; use identity_did::verification::VerificationMethod; use identity_iota_core_legacy::document::IotaDocument; diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml index 91b360752c..b7e94591c4 100644 --- a/identity_iota_core/Cargo.toml +++ b/identity_iota_core/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "identity_iota_core" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] -edition = "2021" -homepage = "https://www.iota.org" +authors.workspace = true +edition.workspace = true +homepage.workspace = true keywords = ["iota", "tangle", "utxo", "shimmer", "identity"] -license = "Apache-2.0" +license.workspace = true readme = "./README.md" -repository = "https://github.com/iotaledger/identity.rs" -rust-version = "1.62" +repository.workspace = true +rust-version.workspace = true description = "An IOTA Ledger integration for the IOTA DID Method." [dependencies] @@ -17,15 +17,17 @@ futures = { version = "0.3" } identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core", default-features = false } identity_credential = { version = "=0.7.0-alpha.4", path = "../identity_credential", default-features = false, features = ["validator"] } identity_did = { version = "=0.7.0-alpha.4", path = "../identity_did", default-features = false } +identity_document = { version = "=0.7.0-alpha.4", path = "../identity_document", default-features = false } +identity_verification = { version = "=0.7.0-alpha.4", path = "../identity_verification", default-features = false } iota-client = { version = "2.0.1-rc.4", default-features = false, features = ["tls"], optional = true } iota-types = { version = "1.0.0-rc.3", default-features = false, features = ["block", "std"], optional = true } num-derive = { version = "0.3", default-features = false } num-traits = { version = "0.2", default-features = false, features = ["std"] } once_cell = { version = "1", default-features = false, features = ["std"] } prefix-hex = { version = "0.4", default-features = false } -serde = { version = "1.0", default-features = false, features = ["std", "derive"] } -strum = { version = "0.21", features = ["derive"] } -thiserror = { version = "1.0", default-features = false } +serde.workspace = true +strum.workspace = true +thiserror.workspace = true [dev-dependencies] anyhow = { version = "1.0.57" } @@ -46,6 +48,6 @@ client = ["dep:async-trait", "dep:iota-types"] # Enables the iota-client dependency, the client trait implementations for it, and the `IotaClientExt` trait. iota-client = ["dep:iota-client", "client"] # Enables revocation with `RevocationBitmap2022`. -revocation-bitmap = ["identity_did/revocation-bitmap"] +revocation-bitmap = ["identity_credential/revocation-bitmap"] # Adds Send bounds on the futures produces by the client extension traits. send-sync-client-ext = [] diff --git a/identity_iota_core/src/did/iota_did.rs b/identity_iota_core/src/did/iota_did.rs index 12612efc1d..3abd3c811e 100644 --- a/identity_iota_core/src/did/iota_did.rs +++ b/identity_iota_core/src/did/iota_did.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryFrom; @@ -8,11 +8,11 @@ use core::fmt::Formatter; use core::str::FromStr; use identity_core::common::KeyComparable; -use identity_did::did::BaseDIDUrl; -use identity_did::did::CoreDID; -use identity_did::did::DIDError; -use identity_did::did::DIDUrl; -use identity_did::did::DID; +use identity_did::BaseDIDUrl; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::Error as DIDError; +use identity_did::DID; use serde::Deserialize; use serde::Serialize; @@ -62,7 +62,7 @@ impl IotaDID { /// # Example /// /// ``` - /// # use identity_did::did::DID; + /// # use identity_did::DID; /// # use identity_iota_core::NetworkName; /// # use identity_iota_core::IotaDID; /// # @@ -87,7 +87,7 @@ impl IotaDID { /// # Example /// /// ``` - /// # use identity_did::did::DID; + /// # use identity_did::DID; /// # use identity_iota_core::NetworkName; /// # use identity_iota_core::IotaDID; /// # @@ -103,7 +103,7 @@ impl IotaDID { /// # Example /// /// ``` - /// # use identity_did::did::DID; + /// # use identity_did::DID; /// # use identity_iota_core::NetworkName; /// # use identity_iota_core::IotaDID; /// # diff --git a/identity_iota_core/src/document/iota_document.rs b/identity_iota_core/src/document/iota_document.rs index e4d8f6de03..0ff88b138c 100644 --- a/identity_iota_core/src/document/iota_document.rs +++ b/identity_iota_core/src/document/iota_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt; @@ -17,17 +17,17 @@ use identity_core::crypto::GetSignature; use identity_core::crypto::PrivateKey; use identity_core::crypto::ProofOptions; use identity_core::crypto::SetSignature; -use identity_did::document::CoreDocument; -use identity_did::document::Document; -use identity_did::service::Service; -use identity_did::utils::DIDUrlQuery; -use identity_did::verifiable::DocumentSigner; -use identity_did::verifiable::VerifierOptions; -use identity_did::verification::MethodRelationship; -use identity_did::verification::MethodScope; -use identity_did::verification::MethodUriType; -use identity_did::verification::TryMethod; -use identity_did::verification::VerificationMethod; +use identity_document::document::CoreDocument; +use identity_document::document::Document; +use identity_document::service::Service; +use identity_document::utils::DIDUrlQuery; +use identity_document::verifiable::DocumentSigner; +use identity_document::verifiable::VerifierOptions; +use identity_verification::MethodRelationship; +use identity_verification::MethodScope; +use identity_verification::MethodUriType; +use identity_verification::TryMethod; +use identity_verification::VerificationMethod; use crate::error::Result; use crate::Error; @@ -411,7 +411,7 @@ impl Document for IotaDocument { self.document.resolve_method(query, scope) } - fn verify_data(&self, data: &X, options: &VerifierOptions) -> identity_did::Result<()> + fn verify_data(&self, data: &X, options: &VerifierOptions) -> identity_document::Result<()> where X: Serialize + GetSignature + ?Sized, { @@ -421,7 +421,8 @@ impl Document for IotaDocument { #[cfg(feature = "revocation-bitmap")] mod iota_document_revocation { - use identity_did::utils::DIDUrlQuery; + use identity_credential::revocation::RevocationDocumentExt; + use identity_document::utils::DIDUrlQuery; use crate::Error; use crate::Result; @@ -429,7 +430,7 @@ mod iota_document_revocation { use super::IotaDocument; impl IotaDocument { - /// If the document has a [`RevocationBitmap`](identity_did::revocation::RevocationBitmap) + /// If the document has a [`RevocationBitmap`](identity_credential::revocation::RevocationBitmap) /// service identified by `service_query`, revoke all specified `indices`. pub fn revoke_credentials<'query, 'me, Q>(&mut self, service_query: Q, indices: &[u32]) -> Result<()> where @@ -441,7 +442,7 @@ mod iota_document_revocation { .map_err(Error::RevocationError) } - /// If the document has a [`RevocationBitmap`](identity_did::revocation::RevocationBitmap) + /// If the document has a [`RevocationBitmap`](identity_credential::revocation::RevocationBitmap) /// service with an id by `service_query`, unrevoke all specified `indices`. pub fn unrevoke_credentials<'query, 'me, Q>(&'me mut self, service_query: Q, indices: &[u32]) -> Result<()> where @@ -490,10 +491,10 @@ mod tests { use identity_core::convert::ToJson; use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; - use identity_did::did::DID; - use identity_did::verifiable::VerifiableProperties; - use identity_did::verification::MethodData; - use identity_did::verification::MethodType; + use identity_did::DID; + use identity_document::verifiable::VerifiableProperties; + use identity_verification::MethodData; + use identity_verification::MethodType; use iota_types::block::protocol::ProtocolParameters; use crate::block::address::Address; diff --git a/identity_iota_core/src/error.rs b/identity_iota_core/src/error.rs index 1eee348275..dd592ac24a 100644 --- a/identity_iota_core/src/error.rs +++ b/identity_iota_core/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub type Result = core::result::Result; @@ -9,9 +9,9 @@ pub enum Error { #[error("serialization error")] SerializationError(&'static str, #[source] Option), #[error("invalid did")] - DIDSyntaxError(#[source] identity_did::did::DIDError), + DIDSyntaxError(#[source] identity_did::Error), #[error("invalid document")] - InvalidDoc(#[source] identity_did::error::Error), + InvalidDoc(#[source] identity_document::Error), #[cfg(feature = "iota-client")] #[error("DID update: {0}")] DIDUpdateError(&'static str, #[source] Option>), @@ -33,8 +33,9 @@ pub enum Error { ProtocolParametersError(#[source] iota_client::Error), #[error("invalid state metadata {0}")] InvalidStateMetadata(&'static str), + #[cfg(feature = "revocation-bitmap")] #[error("credential revocation error")] - RevocationError(#[source] identity_did::Error), + RevocationError(#[source] identity_credential::revocation::RevocationError), #[cfg(feature = "client")] #[error("alias output build error")] AliasOutputBuildError(#[source] crate::block::Error), diff --git a/identity_iota_core/src/state_metadata/document.rs b/identity_iota_core/src/state_metadata/document.rs index 9e95f7ee27..3b3dcdd25c 100644 --- a/identity_iota_core/src/state_metadata/document.rs +++ b/identity_iota_core/src/state_metadata/document.rs @@ -1,11 +1,11 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Object; use identity_core::convert::FromJson; use identity_core::convert::ToJson; -use identity_did::did::CoreDID; -use identity_did::document::CoreDocument; +use identity_did::CoreDID; +use identity_document::document::CoreDocument; use once_cell::sync::Lazy; use serde::Deserialize; use serde::Serialize; @@ -84,7 +84,7 @@ impl StateMetadataDocument { // Check marker. let marker: &[u8] = data .get(0..=2) - .ok_or(identity_did::Error::InvalidDocument( + .ok_or(identity_document::Error::InvalidDocument( "state metadata decoding: expected DID marker at offset [0..=2]", None, )) @@ -97,7 +97,7 @@ impl StateMetadataDocument { let version: StateMetadataVersion = StateMetadataVersion::try_from( *data .get(3) - .ok_or(identity_did::Error::InvalidDocument( + .ok_or(identity_document::Error::InvalidDocument( "state metadata decoding: expected version at offset 3", None, )) @@ -111,7 +111,7 @@ impl StateMetadataDocument { let encoding: StateMetadataEncoding = StateMetadataEncoding::try_from( *data .get(4) - .ok_or(identity_did::Error::InvalidDocument( + .ok_or(identity_document::Error::InvalidDocument( "state metadata decoding: expected encoding at offset 4", None, )) @@ -120,19 +120,21 @@ impl StateMetadataDocument { let data_len_packed: [u8; 2] = data .get(5..=6) - .ok_or(identity_did::Error::InvalidDocument( + .ok_or(identity_document::Error::InvalidDocument( "state metadata decoding: expected data length at offset [5..=6]", None, )) .map_err(Error::InvalidDoc)? .try_into() - .map_err(|_| identity_did::Error::InvalidDocument("state metadata decoding: data length conversion error", None)) + .map_err(|_| { + identity_document::Error::InvalidDocument("state metadata decoding: data length conversion error", None) + }) .map_err(Error::InvalidDoc)?; let data_len: u16 = u16::from_le_bytes(data_len_packed); let data: &[u8] = data .get(7..(7 + data_len as usize)) - .ok_or(identity_did::Error::InvalidDocument( + .ok_or(identity_document::Error::InvalidDocument( "state metadata decoding: encoded document shorter than length prefix", None, )) @@ -200,8 +202,8 @@ mod tests { use identity_core::common::Url; use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; - use identity_did::did::DID; - use identity_did::verification::MethodScope; + use identity_did::DID; + use identity_verification::MethodScope; use crate::state_metadata::document::DID_MARKER; use crate::state_metadata::PLACEHOLDER_DID; diff --git a/identity_iota_core_legacy/src/did/iota_did.rs b/identity_iota_core_legacy/src/did/iota_did.rs index 9f2ccd6b86..955aa8d64e 100644 --- a/identity_iota_core_legacy/src/did/iota_did.rs +++ b/identity_iota_core_legacy/src/did/iota_did.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::convert::TryFrom; @@ -16,11 +16,11 @@ use serde::Serialize; use identity_core::common::KeyComparable; use identity_core::utils::BaseEncoding; -use identity_did::did::BaseDIDUrl; -use identity_did::did::CoreDID; -use identity_did::did::DIDError; -use identity_did::did::DIDUrl; -use identity_did::did::DID; +use identity_did::BaseDIDUrl; +use identity_did::CoreDID; +use identity_did::DIDError; +use identity_did::DIDUrl; +use identity_did::DID; use crate::did::Segments; use crate::error::Error; @@ -293,8 +293,8 @@ impl KeyComparable for IotaDID { mod tests { use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; - use identity_did::did::CoreDID; - use identity_did::did::DID; + use identity_did::CoreDID; + use identity_did::DID; use crate::did::IotaDID; use crate::did::IotaDIDUrl; diff --git a/identity_iota_core_legacy/src/did/macros.rs b/identity_iota_core_legacy/src/did/macros.rs index f5082e506e..3c562de9fe 100644 --- a/identity_iota_core_legacy/src/did/macros.rs +++ b/identity_iota_core_legacy/src/did/macros.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Creates a new IOTA DID from a `public` key and optional `network`. @@ -10,7 +10,7 @@ /// # Example /// /// ``` -/// # use identity_did::did::DID; +/// # use identity_did::DID; /// # use identity_iota_core_legacy::try_construct_did; /// # /// let did = try_construct_did!(b"public-key")?; diff --git a/identity_iota_core_legacy/src/diff/diff_iota_document.rs b/identity_iota_core_legacy/src/diff/diff_iota_document.rs index 386ffe2a11..bc826ed0da 100644 --- a/identity_iota_core_legacy/src/diff/diff_iota_document.rs +++ b/identity_iota_core_legacy/src/diff/diff_iota_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Deserialize; @@ -8,7 +8,7 @@ use identity_core::diff::Diff; use identity_core::diff::Error; use identity_core::diff::Result; use identity_did::diff::DiffDocument; -use identity_did::document::CoreDocument; +use identity_document::document::CoreDocument; use crate::did::IotaDID; use crate::diff::DiffIotaDocumentMetadata; diff --git a/identity_iota_core_legacy/src/document/iota_document.rs b/identity_iota_core_legacy/src/document/iota_document.rs index 2bd471c88a..789c36e4a1 100644 --- a/identity_iota_core_legacy/src/document/iota_document.rs +++ b/identity_iota_core_legacy/src/document/iota_document.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt; @@ -25,10 +25,10 @@ use identity_core::crypto::ProofOptions; use identity_core::crypto::PublicKey; use identity_core::crypto::SetSignature; use identity_core::crypto::Signer; -use identity_did::document::CoreDocument; -use identity_did::document::Document; +use identity_document::document::CoreDocument; +use identity_document::document::Document; use identity_did::service::Service; -use identity_did::utils::DIDUrlQuery; +use identity_document::utils::DIDUrlQuery; use identity_did::verifiable::DocumentSigner; use identity_did::verifiable::VerifierOptions; use identity_did::verification::MethodRef; @@ -658,7 +658,7 @@ impl Document for IotaDocument { #[cfg(feature = "revocation-bitmap")] mod iota_document_revocation { - use identity_did::utils::DIDUrlQuery; + use identity_document::utils::DIDUrlQuery; use crate::Error; use crate::Result; @@ -666,7 +666,7 @@ mod iota_document_revocation { use super::IotaDocument; impl IotaDocument { - /// If the document has a [`RevocationBitmap`](identity_did::revocation::RevocationBitmap) + /// If the document has a [`RevocationBitmap`](identity_credential::revocation::RevocationBitmap) /// service identified by `service_query`, revoke all specified `indices`. pub fn revoke_credentials<'query, 'me, Q>(&mut self, service_query: Q, credential_indices: &[u32]) -> Result<()> where @@ -678,7 +678,7 @@ mod iota_document_revocation { .map_err(Error::RevocationError) } - /// If the document has a [`RevocationBitmap`](identity_did::revocation::RevocationBitmap) + /// If the document has a [`RevocationBitmap`](identity_credential::revocation::RevocationBitmap) /// service with an id by `service_query`, unrevoke all specified `indices`. pub fn unrevoke_credentials<'query, 'me, Q>( &'me mut self, @@ -757,7 +757,7 @@ mod tests { use identity_core::convert::ToJson; use identity_core::crypto::KeyType; use identity_core::utils::BaseEncoding; - use identity_did::did::DID; + use identity_did::DID; use identity_did::verifiable::VerifiableProperties; use identity_did::verification::MethodData; diff --git a/identity_iota_core_legacy/src/error.rs b/identity_iota_core_legacy/src/error.rs index 085e1ec2f3..5fbf8420d4 100644 --- a/identity_iota_core_legacy/src/error.rs +++ b/identity_iota_core_legacy/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 pub type Result = core::result::Result; @@ -9,9 +9,9 @@ pub enum Error { #[error("{0}")] DiffError(#[from] identity_core::diff::Error), #[error("{0}")] - InvalidDID(#[from] identity_did::did::DIDError), + InvalidDID(#[from] identity_did::Error), #[error("{0}")] - InvalidDoc(#[from] identity_did::Error), + InvalidDoc(#[from] identity_document::Error), #[error("Invalid Message: {0}")] InvalidMessage(#[from] bee_message::Error), diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml index 8472012371..05110c3e0e 100644 --- a/identity_resolver/Cargo.toml +++ b/identity_resolver/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "identity_resolver" version = "0.7.0-alpha.4" -authors = ["IOTA Stiftung"] -edition = "2021" -homepage = "https://www.iota.org" +authors.workspace = true +edition.workspace = true +homepage.workspace = true keywords = ["iota", "did", "identity", "resolver", "resolution"] -license = "Apache-2.0" +license.workspace = true readme = "../README.md" -repository = "https://github.com/iotaledger/identity.rs" -rust-version = "1.62" +repository.workspace = true +rust-version.workspace = true description = "DID Resolution utilities for the identity.rs library." [dependencies] @@ -18,6 +18,7 @@ futures = { version = "0.3" } identity_core = { version = "=0.7.0-alpha.4", path = "../identity_core", default-features = false } identity_credential = { version = "=0.7.0-alpha.4", path = "../identity_credential", default-features = false, features = ["validator"] } identity_did = { version = "=0.7.0-alpha.4", path = "../identity_did", default-features = false } +identity_document = { version = "=0.7.0-alpha.4", path = "../identity_document", default-features = false } serde = { version = "1.0", default-features = false, features = ["std", "derive"] } strum = { version = "0.21", features = ["derive"] } thiserror = { version = "1.0", default-features = false } @@ -35,6 +36,6 @@ tokio = { version = "1.17.0", default-features = false, features = ["rt-multi-th [features] default = ["revocation-bitmap", "iota"] -revocation-bitmap = ["identity_did/revocation-bitmap", "identity_iota_core?/revocation-bitmap"] +revocation-bitmap = ["identity_credential/revocation-bitmap", "identity_iota_core?/revocation-bitmap"] # Enables the IOTA integration for the resolver. iota = ["dep:identity_iota_core"] diff --git a/identity_resolver/src/resolution/commands.rs b/identity_resolver/src/resolution/commands.rs index 8a53e1d261..e516811816 100644 --- a/identity_resolver/src/resolution/commands.rs +++ b/identity_resolver/src/resolution/commands.rs @@ -1,9 +1,9 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::future::Future; use identity_credential::validator::ValidatorDocument; -use identity_did::did::DID; +use identity_did::DID; use crate::Error; use crate::ErrorCause; diff --git a/identity_resolver/src/resolution/resolver.rs b/identity_resolver/src/resolution/resolver.rs index 97c5d89dad..177af3c924 100644 --- a/identity_resolver/src/resolution/resolver.rs +++ b/identity_resolver/src/resolution/resolver.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::future::Future; @@ -14,8 +14,8 @@ use identity_credential::validator::FailFast; use identity_credential::validator::PresentationValidationOptions; use identity_credential::validator::PresentationValidator; use identity_credential::validator::ValidatorDocument; -use identity_did::did::CoreDID; -use identity_did::did::DID; +use identity_did::CoreDID; +use identity_did::DID; use serde::Serialize; @@ -54,10 +54,10 @@ where /// /// # Example /// Construct a `Resolver` that resolves DID documents of type - /// [`CoreDocument`](::identity_did::document::CoreDocument). + /// [`CoreDocument`](::identity_document::document::CoreDocument). /// ``` /// # use identity_resolver::Resolver; - /// # use identity_did::document::CoreDocument; + /// # use identity_document::document::CoreDocument; /// /// let mut resolver = Resolver::::new(); /// // Now attach some handlers whose output can be converted to a `CoreDocument`. @@ -72,9 +72,9 @@ where /// ``` /// /// # Tradeoffs - /// The default type agnostic [`Resolver`] is more convenient when working with document types whose implementations of the [`Document`](::identity_did::document::Document) - /// trait do not map well to a single representation (such as for instance [`CoreDocument`](::identity_did::document::CoreDocument)). - /// This is typically the case whenever custom cryptography is applied in implementations of the [`Document::verify_data`](::identity_did::document::Document::verify_data()) method. + /// The default type agnostic [`Resolver`] is more convenient when working with document types whose implementations of the [`Document`](::identity_document::document::Document) + /// trait do not map well to a single representation (such as for instance [`CoreDocument`](::identity_document::document::CoreDocument)). + /// This is typically the case whenever custom cryptography is applied in implementations of the [`Document::verify_data`](::identity_document::document::Document::verify_data()) method. /// The extra flexibility offered by the type agnostic resolver comes at the cost of less type information, hence specifying a concrete type in the constructor /// is recommended whenever a single representation is a good fit. pub fn new() -> Self { @@ -99,9 +99,9 @@ where /// ## Example /// ``` /// # use identity_resolver::Resolver; - /// # use identity_did::did::CoreDID; - /// # use identity_did::did::DID; - /// # use identity_did::document::CoreDocument; + /// # use identity_did::CoreDID; + /// # use identity_did::DID; + /// # use identity_document::document::CoreDocument; /// /// async fn resolve_and_cast( /// did: CoreDID, @@ -297,8 +297,8 @@ impl Resolver> { /// # Example /// ``` /// # use identity_resolver::Resolver; - /// # use identity_did::did::CoreDID; - /// # use identity_did::document::CoreDocument; + /// # use identity_did::CoreDID; + /// # use identity_document::document::CoreDocument; /// /// // A client that can resolve DIDs of our invented "foo" method. /// struct Client; @@ -356,8 +356,8 @@ impl Resolver> /// # Example /// ``` /// # use identity_resolver::SingleThreadedResolver; - /// # use identity_did::did::CoreDID; - /// # use identity_did::document::CoreDocument; + /// # use identity_did::CoreDID; + /// # use identity_document::document::CoreDocument; /// /// // A client that can resolve DIDs of our invented "foo" method. /// struct Client; diff --git a/identity_resolver/src/resolution/tests/presentation_validation_errors.rs b/identity_resolver/src/resolution/tests/presentation_validation_errors.rs index 4bfecf0ad9..d7ddc120a8 100644 --- a/identity_resolver/src/resolution/tests/presentation_validation_errors.rs +++ b/identity_resolver/src/resolution/tests/presentation_validation_errors.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use crate::ErrorCause; @@ -8,8 +8,8 @@ use identity_credential::presentation::Presentation; use identity_credential::validator::FailFast; use identity_credential::validator::PresentationValidationOptions; use identity_credential::validator::ValidatorDocument; -use identity_did::did::CoreDID; -use identity_did::document::CoreDocument; +use identity_did::CoreDID; +use identity_document::document::CoreDocument; use identity_iota_core::IotaDID; use identity_iota_core::IotaDocument; diff --git a/identity_resolver/src/resolution/tests/resolution_errors.rs b/identity_resolver/src/resolution/tests/resolution_errors.rs index 2b09317009..fae1e72ae3 100644 --- a/identity_resolver/src/resolution/tests/resolution_errors.rs +++ b/identity_resolver/src/resolution/tests/resolution_errors.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::error::Error; @@ -12,12 +12,12 @@ use identity_credential::presentation::PresentationBuilder; use identity_credential::validator::FailFast; use identity_credential::validator::PresentationValidationOptions; use identity_credential::validator::ValidatorDocument; -use identity_did::did::BaseDIDUrl; -use identity_did::did::CoreDID; -use identity_did::did::DIDError; -use identity_did::did::DID; -use identity_did::document::CoreDocument; -use identity_did::document::DocumentBuilder; +use identity_did::BaseDIDUrl; +use identity_did::CoreDID; +use identity_did::Error as DIDError; +use identity_did::DID; +use identity_document::document::CoreDocument; +use identity_document::document::DocumentBuilder; use crate::Error as ResolverError; use crate::ErrorCause; diff --git a/identity_resolver/src/resolution/tests/send_sync.rs b/identity_resolver/src/resolution/tests/send_sync.rs index e727d92e64..646efe937b 100644 --- a/identity_resolver/src/resolution/tests/send_sync.rs +++ b/identity_resolver/src/resolution/tests/send_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use super::*; @@ -8,7 +8,7 @@ use identity_credential::presentation::Presentation; use identity_credential::validator::FailFast; use identity_credential::validator::PresentationValidationOptions; use identity_credential::validator::ValidatorDocument; -use identity_did::did::DID; +use identity_did::DID; use serde::Serialize; fn is_send(_t: T) {} diff --git a/identity_resolver/src/resolution/tests/successful_presentation_validation.rs b/identity_resolver/src/resolution/tests/successful_presentation_validation.rs index 80c70c23d9..0bfcc224e1 100644 --- a/identity_resolver/src/resolution/tests/successful_presentation_validation.rs +++ b/identity_resolver/src/resolution/tests/successful_presentation_validation.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::convert::FromJson; @@ -7,11 +7,11 @@ use identity_credential::validator::FailFast; use identity_credential::validator::PresentationValidationOptions; use identity_credential::validator::SubjectHolderRelationship; use identity_credential::validator::ValidatorDocument; -use identity_did::did::CoreDID; -use identity_did::did::DID; -use identity_did::document::CoreDocument; -use identity_did::document::Document; -use identity_did::verifiable::VerifierOptions; +use identity_did::CoreDID; +use identity_did::DID; +use identity_document::document::CoreDocument; +use identity_document::document::Document; +use identity_document::verifiable::VerifierOptions; use identity_iota_core::IotaDID; use identity_iota_core::IotaDocument; use serde::de::DeserializeOwned; diff --git a/identity_verification/Cargo.toml b/identity_verification/Cargo.toml new file mode 100644 index 0000000000..e195a8ba73 --- /dev/null +++ b/identity_verification/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "identity_verification" +version = "0.7.0-alpha.4" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +rust-version.workspace = true +description = "Verification data types and functionality for identity.rs" + +[dependencies] +identity_core = { version = "=0.7.0-alpha.4", path = "./../identity_core", default-features = false } +identity_did = { version = "=0.7.0-alpha.4", path = "./../identity_did", default-features = false } +serde.workspace = true +strum.workspace = true +thiserror.workspace = true + +[dev-dependencies] +serde_json = { version = "1.0", default-features = false } diff --git a/identity_verification/README.md b/identity_verification/README.md new file mode 100644 index 0000000000..fdb7f39646 --- /dev/null +++ b/identity_verification/README.md @@ -0,0 +1 @@ +Verification data types and functionality for use with `identity_document`. \ No newline at end of file diff --git a/identity_verification/src/error.rs b/identity_verification/src/error.rs new file mode 100644 index 0000000000..5167507797 --- /dev/null +++ b/identity_verification/src/error.rs @@ -0,0 +1,28 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! Errors that may occur when working with Decentralized Identifiers. + +/// Alias for a [`Result`][::core::result::Result] with the error type [Error]. +pub type Result = ::core::result::Result; + +/// This type represents all possible errors that can occur in the crate. +#[derive(Debug, thiserror::Error, strum::IntoStaticStr)] +pub enum Error { + /// Caused by invalid or missing properties when constructing a + /// [`VerificationMethod`](crate::VerificationMethod). + #[error("invalid verification method property: {0}")] + InvalidMethod(&'static str), + #[error("invalid DID url")] + DIDUrlConstructionError(#[source] identity_did::Error), + #[error("invalid or empty `id` fragment")] + MissingIdFragment, + #[error("Unknown Method Scope")] + UnknownMethodScope, + #[error("Unknown Method Type")] + UnknownMethodType, + #[error("Invalid Base58 Key Data")] + InvalidKeyDataBase58, + #[error("Invalid Multibase Key Data")] + InvalidKeyDataMultibase, +} diff --git a/identity_verification/src/lib.rs b/identity_verification/src/lib.rs new file mode 100644 index 0000000000..45c765e57c --- /dev/null +++ b/identity_verification/src/lib.rs @@ -0,0 +1,27 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] +#![allow(deprecated)] +#![doc = include_str!("./../README.md")] +#![allow(clippy::upper_case_acronyms)] +#![warn( + rust_2018_idioms, + unreachable_pub, + // missing_docs, + rustdoc::missing_crate_level_docs, + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::private_doc_tests, + clippy::missing_safety_doc, + // clippy::missing_errors_doc +)] + +#[macro_use] +extern crate serde; + +mod error; +pub mod verification_method; +pub use error::Error; +pub use error::Result; +pub use verification_method::*; diff --git a/identity_did/src/verification/builder.rs b/identity_verification/src/verification_method/builder.rs similarity index 94% rename from identity_did/src/verification/builder.rs rename to identity_verification/src/verification_method/builder.rs index 66d5fc13d5..b8c278f75e 100644 --- a/identity_did/src/verification/builder.rs +++ b/identity_verification/src/verification_method/builder.rs @@ -1,15 +1,15 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Object; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::error::Result; -use crate::verification::MethodData; -use crate::verification::MethodType; -use crate::verification::VerificationMethod; +use crate::verification_method::MethodData; +use crate::verification_method::MethodType; +use crate::verification_method::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; /// A `MethodBuilder` is used to generate a customized `Method`. #[derive(Clone, Debug)] diff --git a/identity_did/src/diff/diff_method.rs b/identity_verification/src/verification_method/diff/diff_method.rs similarity index 97% rename from identity_did/src/diff/diff_method.rs rename to identity_verification/src/verification_method/diff/diff_method.rs index 90bd4a1cb9..5548c9a397 100644 --- a/identity_did/src/diff/diff_method.rs +++ b/identity_verification/src/verification_method/diff/diff_method.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use serde::Deserialize; @@ -9,14 +9,14 @@ use identity_core::diff::Diff; use identity_core::diff::Error; use identity_core::diff::Result; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; -use crate::diff::DiffMethodData; -use crate::verification::MethodBuilder; -use crate::verification::MethodData; -use crate::verification::MethodType; -use crate::verification::VerificationMethod; +use super::method_data::DiffMethodData; +use crate::verification_method::MethodBuilder; +use crate::verification_method::MethodData; +use crate::verification_method::MethodType; +use crate::verification_method::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct DiffMethod diff --git a/identity_did/src/diff/method_data.rs b/identity_verification/src/verification_method/diff/method_data.rs similarity index 96% rename from identity_did/src/diff/method_data.rs rename to identity_verification/src/verification_method/diff/method_data.rs index 121ffb7bbb..f462199f03 100644 --- a/identity_did/src/diff/method_data.rs +++ b/identity_verification/src/verification_method/diff/method_data.rs @@ -1,11 +1,11 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::diff::Diff; use identity_core::diff::DiffString; use identity_core::diff::Result; -use crate::verification::MethodData; +use crate::verification_method::MethodData; #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum DiffMethodData { diff --git a/identity_did/src/diff/method_ref.rs b/identity_verification/src/verification_method/diff/method_ref.rs similarity index 92% rename from identity_did/src/diff/method_ref.rs rename to identity_verification/src/verification_method/diff/method_ref.rs index 654283d9cf..4a3039649d 100644 --- a/identity_did/src/diff/method_ref.rs +++ b/identity_verification/src/verification_method/diff/method_ref.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::common::Object; @@ -8,11 +8,11 @@ use identity_core::diff::Result; use serde::Deserialize; use serde::Serialize; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; -use crate::diff::DiffMethod; -use crate::verification::MethodRef; +use super::diff_method::DiffMethod; +use crate::verification_method::MethodRef; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[serde(untagged)] diff --git a/identity_did/src/diff/method_type.rs b/identity_verification/src/verification_method/diff/method_type.rs similarity index 84% rename from identity_did/src/diff/method_type.rs rename to identity_verification/src/verification_method/diff/method_type.rs index 389de6e14f..054538380e 100644 --- a/identity_did/src/diff/method_type.rs +++ b/identity_verification/src/verification_method/diff/method_type.rs @@ -1,10 +1,10 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use identity_core::diff::Diff; use identity_core::diff::Result; -use crate::verification::MethodType; +use crate::verification_method::MethodType; impl Diff for MethodType { type Type = MethodType; diff --git a/identity_did/src/diff/mod.rs b/identity_verification/src/verification_method/diff/mod.rs similarity index 59% rename from identity_did/src/diff/mod.rs rename to identity_verification/src/verification_method/diff/mod.rs index 97349fc6e7..37c2751da6 100644 --- a/identity_did/src/diff/mod.rs +++ b/identity_verification/src/verification_method/diff/mod.rs @@ -1,15 +1,11 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -pub use self::diff_document::DiffDocument; -pub use self::diff_method::DiffMethod; -pub use self::diff_service::DiffService; -pub use self::method_data::DiffMethodData; -pub use self::method_ref::DiffMethodRef; - -mod diff_document; mod diff_method; -mod diff_service; mod method_data; mod method_ref; mod method_type; + +pub use self::diff_method::DiffMethod; +pub use self::method_data::DiffMethodData; +pub use self::method_ref::DiffMethodRef; diff --git a/identity_did/src/verification/method_data.rs b/identity_verification/src/verification_method/material.rs similarity index 98% rename from identity_did/src/verification/method_data.rs rename to identity_verification/src/verification_method/material.rs index 345c0e10a7..0d38792815 100644 --- a/identity_did/src/verification/method_data.rs +++ b/identity_verification/src/verification_method/material.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Debug; diff --git a/identity_did/src/verification/verification_method.rs b/identity_verification/src/verification_method/method.rs similarity index 94% rename from identity_did/src/verification/verification_method.rs rename to identity_verification/src/verification_method/method.rs index 53d2308939..2901b8194f 100644 --- a/identity_did/src/verification/verification_method.rs +++ b/identity_verification/src/verification_method/method.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; @@ -14,15 +14,15 @@ use identity_core::convert::FmtJson; use identity_core::crypto::KeyType; use identity_core::crypto::PublicKey; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; use crate::error::Error; use crate::error::Result; -use crate::verification::MethodBuilder; -use crate::verification::MethodData; -use crate::verification::MethodRef; -use crate::verification::MethodType; +use crate::verification_method::MethodBuilder; +use crate::verification_method::MethodData; +use crate::verification_method::MethodRef; +use crate::verification_method::MethodType; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; /// A DID Document Verification Method. /// @@ -201,7 +201,10 @@ where } else { fragment.to_owned() }; - let id: DIDUrl = did.to_url().join(method_fragment)?; + let id: DIDUrl = did + .to_url() + .join(method_fragment) + .map_err(Error::DIDUrlConstructionError)?; let mut builder: MethodBuilder = MethodBuilder::default().id(id).controller(did); match key_type { diff --git a/identity_did/src/verification/method_ref.rs b/identity_verification/src/verification_method/method_ref.rs similarity index 95% rename from identity_did/src/verification/method_ref.rs rename to identity_verification/src/verification_method/method_ref.rs index d1b7692e91..83f65930bf 100644 --- a/identity_did/src/verification/method_ref.rs +++ b/identity_verification/src/verification_method/method_ref.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Debug; @@ -7,10 +7,10 @@ use core::fmt::Formatter; use identity_core::common::KeyComparable; use identity_core::common::Object; -use crate::did::CoreDID; -use crate::did::DIDUrl; -use crate::did::DID; -use crate::verification::VerificationMethod; +use crate::verification_method::VerificationMethod; +use identity_did::CoreDID; +use identity_did::DIDUrl; +use identity_did::DID; /// A reference to a verification method, either a `DID` or embedded `Method`. #[derive(Clone, PartialEq, Eq, Deserialize, Serialize)] diff --git a/identity_did/src/verification/method_relationship.rs b/identity_verification/src/verification_method/method_relationship.rs similarity index 89% rename from identity_did/src/verification/method_relationship.rs rename to identity_verification/src/verification_method/method_relationship.rs index 66ce038431..653b454a59 100644 --- a/identity_did/src/verification/method_relationship.rs +++ b/identity_verification/src/verification_method/method_relationship.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// Verification relationships. diff --git a/identity_did/src/verification/method_scope.rs b/identity_verification/src/verification_method/method_scope.rs similarity index 96% rename from identity_did/src/verification/method_scope.rs rename to identity_verification/src/verification_method/method_scope.rs index f905528522..fb93f5eabb 100644 --- a/identity_did/src/verification/method_scope.rs +++ b/identity_verification/src/verification_method/method_scope.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt; @@ -9,7 +9,7 @@ use identity_core::convert::FmtJson; use crate::error::Error; use crate::error::Result; -use crate::verification::MethodRelationship; +use crate::verification_method::MethodRelationship; /// Verification method group used to refine the scope of a method query. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] diff --git a/identity_did/src/verification/method_type.rs b/identity_verification/src/verification_method/method_type.rs similarity index 97% rename from identity_did/src/verification/method_type.rs rename to identity_verification/src/verification_method/method_type.rs index f88c3dffd8..f38180a6c2 100644 --- a/identity_did/src/verification/method_type.rs +++ b/identity_verification/src/verification_method/method_type.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Display; diff --git a/identity_did/src/verification/mod.rs b/identity_verification/src/verification_method/mod.rs similarity index 73% rename from identity_did/src/verification/mod.rs rename to identity_verification/src/verification_method/mod.rs index 37a5783fde..0735ed2641 100644 --- a/identity_did/src/verification/mod.rs +++ b/identity_verification/src/verification_method/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 //! The `verification` module contains code for verifying the correctness of core DID-related types. @@ -7,20 +7,22 @@ //! `identity_iota_core_legacy` crate. mod builder; -mod method_data; +#[deprecated(since = "0.5.0", note = "diff chain features are slated for removal")] +pub mod diff; +mod material; +mod method; mod method_ref; mod method_relationship; mod method_scope; mod method_type; mod traits; -mod verification_method; pub use self::builder::MethodBuilder; -pub use self::method_data::MethodData; +pub use self::material::MethodData; +pub use self::method::VerificationMethod; pub use self::method_ref::MethodRef; pub use self::method_relationship::MethodRelationship; pub use self::method_scope::MethodScope; pub use self::method_type::MethodType; pub use self::traits::MethodUriType; pub use self::traits::TryMethod; -pub use self::verification_method::VerificationMethod; diff --git a/identity_did/src/verification/traits.rs b/identity_verification/src/verification_method/traits.rs similarity index 89% rename from identity_did/src/verification/traits.rs rename to identity_verification/src/verification_method/traits.rs index 67811b657f..144444d4b5 100644 --- a/identity_did/src/verification/traits.rs +++ b/identity_verification/src/verification_method/traits.rs @@ -1,10 +1,10 @@ -// Copyright 2020-2022 IOTA Stiftung +// Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crate::did::DID; use crate::error::Error; use crate::error::Result; -use crate::verification::VerificationMethod; +use crate::verification_method::VerificationMethod; +use identity_did::DID; /// Represents all possible verification method URI types /// @@ -21,7 +21,7 @@ pub enum MethodUriType { /// /// [More Info](https://www.w3.org/TR/did-core/#relative-did-urls) pub trait TryMethod { - /// Flag that determines whether absolute or rleative URI + /// Flag that determines whether absolute or relative URI const TYPE: MethodUriType; /// Returns an absolute or relative method URI, if any, depending on the [`MethodUriType`].