Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Account API to return IdentityState from find_identity and create_identity #414

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 6 additions & 7 deletions README.md
Expand Up @@ -29,7 +29,7 @@ IOTA Identity is a [Rust](https://www.rust-lang.org/) implementation of decentra
The individual libraries are developed to be agnostic about the utilized [Distributed Ledger Technology (DLT)](https://en.wikipedia.org/wiki/Distributed_ledger), with the exception of the [IOTA](https://www.iota.org) integration and higher level libraries. Written in stable Rust, it has strong guarantees of memory safety and process integrity while maintaining exceptional performance.

> :warning: **WARNING** :warning:
>
>
> This library is currently in its **beta stage** and **under development** and might undergo large changes!
> Until a formal third-party security audit has taken place, the [IOTA Foundation](https://www.iota.org/) makes no guarantees to the fitness of this library. As such, it is to be seen as **experimental** and not ready for real-world applications.
> Nevertheless, we are very interested in feedback about user experience, design and implementation, and encourage you to reach out with any concerns or suggestions you may have.
Expand Down Expand Up @@ -92,7 +92,7 @@ use std::path::PathBuf;
use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::IotaDocument;
Expand All @@ -112,13 +112,12 @@ async fn main() -> Result<()> {
.await?;

// Create a new Identity with default settings.
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
println!("[Example] Local Document = {:#?}", identity.to_document()?);
println!("[Example] Local Document List = {:#?}", account.list_identities().await);

// Fetch the DID Document from the Tangle
Expand Down Expand Up @@ -165,7 +164,7 @@ IOTA Identity is in heavy development, and will naturally change as it matures a

At the current state, the framework is in beta. As the framework matures we expect to support more and more types of applications. We recommend no use in real-world applications until the consumed libraries are audited, but experimentation and Proof-of-Concept projects are encouraged at the different stages.

The next milestone is the release of version 1.0, which will stabilize the APIs, support backwards compatibility and versioned identities. This makes updating to future versions much easier. In addition it will provide full documentation coverage and the release will be audited.
The next milestone is the release of version 1.0, which will stabilize the APIs, support backwards compatibility and versioned identities. This makes updating to future versions much easier. In addition it will provide full documentation coverage and the release will be audited.

Afterwards, we are already planning a future update containing privacy enhancing features such as Selective Disclosure and Zero Knowledge Proofs.

Expand Down
9 changes: 4 additions & 5 deletions examples/account/basic.rs
Expand Up @@ -5,7 +5,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::IotaDocument;
Expand All @@ -18,13 +18,12 @@ async fn main() -> Result<()> {
let account: Account = Account::builder().build().await?;

// Create a new Identity with default settings
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
println!("[Example] Local Document = {:#?}", identity.to_document()?);
println!("[Example] Local Document List = {:#?}", account.list_identities().await);

// Fetch the DID Document from the Tangle
Expand Down
6 changes: 3 additions & 3 deletions examples/account/lazy.rs
Expand Up @@ -5,7 +5,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::core::Url;
use identity::iota::IotaDID;
Expand All @@ -21,10 +21,10 @@ async fn main() -> Result<()> {

// Create a new Identity with default settings.
// The identity will only be written to the local storage - not published to the tangle.
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

account
.update_identity(did)
Expand Down
6 changes: 3 additions & 3 deletions examples/account/methods.rs
Expand Up @@ -5,7 +5,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::did::MethodScope;
use identity::iota::IotaDID;
Expand All @@ -18,10 +18,10 @@ async fn main() -> Result<()> {
let account: Account = Account::builder().build().await?;

// Create a new Identity with default settings
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

// Add a new Ed25519 (default) verification method to the identity - the
// verification method is included as an embedded authentication method.
Expand Down
11 changes: 5 additions & 6 deletions examples/account/private_tangle.rs
Expand Up @@ -11,7 +11,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::IotaDocument;
Expand Down Expand Up @@ -43,8 +43,8 @@ async fn main() -> Result<()> {
let id_create = IdentityCreate::new().network(network_name)?;

// Create a new Identity with the network name set.
let snapshot: IdentitySnapshot = match account.create_identity(id_create).await {
Ok(snapshot) => snapshot,
let identity: IdentityState = match account.create_identity(id_create).await {
Ok(identity) => identity,
Err(err) => {
eprintln!("[Example] Error: {:?} {}", err, err.to_string());
eprintln!(
Expand All @@ -56,10 +56,9 @@ async fn main() -> Result<()> {
};

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
println!("[Example] Local Document = {:#?}", identity.to_document()?);
println!("[Example] Local Document List = {:#?}", account.list_identities().await);

// Fetch the DID Document from the Tangle
Expand Down
6 changes: 3 additions & 3 deletions examples/account/services.rs
Expand Up @@ -5,7 +5,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::core::Url;
use identity::iota::IotaDID;
Expand All @@ -18,10 +18,10 @@ async fn main() -> Result<()> {
let account: Account = Account::builder().build().await?;

// Create a new Identity with default settings
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

// Add a new service to the identity.
account
Expand Down
9 changes: 4 additions & 5 deletions examples/account/signing.rs
Expand Up @@ -5,7 +5,7 @@

use identity::account::Account;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::core::json;
use identity::core::FromJson;
Expand All @@ -24,13 +24,12 @@ async fn main() -> Result<()> {
let account: Account = Account::builder().build().await?;

// Create a new Identity with default settings
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
println!("[Example] Local Document = {:#?}", identity.to_document()?);

// Add a new Ed25519 Verification Method to the identity
account
Expand Down
13 changes: 6 additions & 7 deletions examples/account/stronghold.rs
Expand Up @@ -8,7 +8,7 @@ use std::path::PathBuf;
use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::IdentityState;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::IotaDocument;
Expand All @@ -27,13 +27,12 @@ async fn main() -> Result<()> {
.await?;

// Create a new Identity with default settings
let snapshot1: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let identity1: IdentityState = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did1: &IotaDID = snapshot1.identity().try_did()?;
let did1: &IotaDID = identity1.try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot1);
println!("[Example] Local Document = {:#?}", snapshot1.identity().to_document()?);
println!("[Example] Local Document = {:#?}", identity1.to_document()?);
println!("[Example] Local Document List = {:#?}", account.list_identities().await);

// Fetch the DID Document from the Tangle
Expand All @@ -44,8 +43,8 @@ async fn main() -> Result<()> {
println!("[Example] Tangle Document = {:#?}", resolved);

// Create another new Identity
let snapshot2: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let did2: &IotaDID = snapshot2.identity().try_did()?;
let identity2: IdentityState = account.create_identity(IdentityCreate::default()).await?;
let did2: &IotaDID = identity2.try_did()?;

// Anndddd delete it
account.delete_identity(did2).await?;
Expand Down
17 changes: 11 additions & 6 deletions identity-account/src/account/account.rs
Expand Up @@ -111,15 +111,20 @@ impl Account {
self.index.read().await.tags()
}

/// Finds and returns the state snapshot for the identity specified by given `key`.
pub async fn find_identity<K: IdentityKey>(&self, key: K) -> Result<Option<IdentitySnapshot>> {
/// Finds and returns the identity state for the identity specified by given `key`.
pub async fn find_identity<K: IdentityKey>(&self, key: K) -> Result<Option<IdentityState>> {
match self.resolve_id(&key).await {
Some(identity) => self.load_snapshot(identity).await.map(Some),
Some(identity) => self
.load_snapshot(identity)
.await
.map(IdentitySnapshot::into_identity)
.map(Some),
None => Ok(None),
}
}

pub async fn create_identity(&self, input: IdentityCreate) -> Result<IdentitySnapshot> {
/// Create an identity from the specified configuration options.
pub async fn create_identity(&self, input: IdentityCreate) -> Result<IdentityState> {
// Acquire write access to the index.
let mut index: RwLockWriteGuard<'_, _> = self.index.write().await;

Expand Down Expand Up @@ -152,8 +157,8 @@ impl Account {
// Write the changes to disk
self.save(false).await?;

// Return the state snapshot
Ok(snapshot)
// Return the identity state
Ok(snapshot.into_identity())
}

/// Returns the `IdentityUpdater` for the given `key`.
Expand Down
5 changes: 5 additions & 0 deletions identity-account/src/identity/identity_snapshot.rs
Expand Up @@ -35,4 +35,9 @@ impl IdentitySnapshot {
pub fn identity(&self) -> &IdentityState {
&self.identity
}

/// Returns the identity state of the snapshot (consuming self).
pub fn into_identity(self) -> IdentityState {
self.identity
}
}
11 changes: 6 additions & 5 deletions identity-account/src/tests/commands.rs
Expand Up @@ -10,6 +10,7 @@ use crate::events::UpdateError;
use crate::identity::IdentityCreate;
use crate::identity::IdentityId;
use crate::identity::IdentitySnapshot;
use crate::identity::IdentityState;
use crate::identity::TinyMethod;
use crate::storage::MemStore;
use crate::types::Generation;
Expand Down Expand Up @@ -100,11 +101,11 @@ async fn test_create_identity_network() -> Result<()> {

// Create an identity with a valid network string
let create_identity: IdentityCreate = IdentityCreate::new().network("dev")?.key_type(KeyType::Ed25519);
let snapshot: IdentitySnapshot = account.create_identity(create_identity).await?;
let identity: IdentityState = account.create_identity(create_identity).await?;

// Ensure the identity creation was successful
assert!(snapshot.identity().did().is_some());
assert!(snapshot.identity().authentication().is_ok());
assert!(identity.did().is_some());
assert!(identity.authentication().is_ok());

Ok(())
}
Expand Down Expand Up @@ -180,8 +181,8 @@ async fn test_create_identity_from_private_key() -> Result<()> {
let ident2 = account.find_identity(identity).await.unwrap().unwrap();

// The same private key should result in the same did
assert_eq!(ident.identity().did(), ident2.identity().did());
assert_eq!(ident.identity().authentication()?, ident2.identity().authentication()?);
assert_eq!(ident.did(), ident2.did());
assert_eq!(ident.authentication()?, ident2.authentication()?);

Ok(())
}
Expand Down
10 changes: 5 additions & 5 deletions identity-account/src/tests/lazy.rs
Expand Up @@ -4,7 +4,7 @@
use std::pin::Pin;

use crate::account::Account;
use crate::identity::{IdentityCreate, IdentitySnapshot, IdentityUpdater};
use crate::identity::{IdentityCreate, IdentityState, IdentityUpdater};
use crate::{Error as AccountError, Result};
use futures::Future;
use identity_core::common::Url;
Expand All @@ -28,11 +28,11 @@ async fn test_lazy_updates() -> Result<()> {
Network::Mainnet
};

let snapshot: IdentitySnapshot = account
let identity: IdentityState = account
.create_identity(IdentityCreate::new().network(network.name()).unwrap())
.await?;

let did: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = identity.try_did()?;

let did_updater: IdentityUpdater<'_, '_, _> = account.update_identity(did);

Expand All @@ -58,7 +58,7 @@ async fn test_lazy_updates() -> Result<()> {
// First round of assertions
// ===========================================================================

let doc = account.resolve_identity(snapshot.identity().did().unwrap()).await?;
let doc = account.resolve_identity(identity.did().unwrap()).await?;

let services = doc.service();

Expand Down Expand Up @@ -92,7 +92,7 @@ async fn test_lazy_updates() -> Result<()> {
// Second round of assertions
// ===========================================================================

let doc = account.resolve_identity(snapshot.identity().did().unwrap()).await?;
let doc = account.resolve_identity(identity.did().unwrap()).await?;
let methods = doc.methods().collect::<Vec<&IotaVerificationMethod>>();

assert_eq!(doc.service().len(), 0);
Expand Down