diff --git a/runtime/src/attestation.rs b/runtime/src/attestation.rs index 663018a7e..2448d7219 100644 --- a/runtime/src/attestation.rs +++ b/runtime/src/attestation.rs @@ -1,3 +1,5 @@ + +use rstd::result; use rstd::prelude::*; use support::{dispatch::Result, StorageMap, decl_module, decl_storage}; use {system, super::delegation, super::ctype, system::ensure_signed}; @@ -19,13 +21,13 @@ decl_module! { let delegation = >::get(d.clone()); if delegation.4 { return Err("delegation revoked") - } else if delegation.2 != sender { + } else if !delegation.2.eq(&sender) { return Err("not delegated to attester") - } else if delegation.3 & delegation::Permissions::ATTEST != delegation::Permissions::ATTEST { + } else if (delegation.3 & delegation::Permissions::ATTEST) != delegation::Permissions::ATTEST { return Err("delegation not authorized to attest") } else { let root = >::get(delegation.0.clone()); - if root.0 != ctype_hash { + if !root.0.eq(&ctype_hash) { return Err("CTYPE of delegation does not match") } } @@ -47,6 +49,14 @@ decl_module! { ::runtime_io::print("insert Attestation"); existing_attestations_for_claim.push((ctype_hash.clone(), sender.clone(), delegation_id.clone(), false)); >::insert(claim_hash.clone(), existing_attestations_for_claim); + match delegation_id { + Some(d) => { + let mut delegated_attestations = >::get(d); + delegated_attestations.push(claim_hash.clone()); + >::insert(d.clone(), delegated_attestations); + }, + None => {} + } Ok(()) }, } @@ -58,9 +68,22 @@ decl_module! { let mut last_attested : bool = false; let mut existing_attestations_for_claim = >::get(claim_hash.clone()); for v in existing_attestations_for_claim.iter_mut() { - if v.1.eq(&sender) && !v.3 { - last_attested = true; - v.3 = true; + if !v.3 { + if v.1.eq(&sender) { + last_attested = true; + v.3 = true; + } else { + // check delegator in case of delegation + match v.2 { + Some(d) => { + if Self::is_delegating(&sender, &d)? { + last_attested = true; + v.3 = true; + } + }, + None => {} + } + } } } if last_attested { @@ -73,10 +96,18 @@ decl_module! { } } +impl Module { + fn is_delegating(account: &T::AccountId, delegation: &T::DelegationNodeId) -> result::Result { + >::is_delegating(account, delegation) + } +} + decl_storage! { trait Store for Module as Attestation { // Attestations: claim-hash -> [(ctype-hash, account, delegation-id?, revoked)] Attestations get(attestations): map T::Hash => Vec<(T::Hash,T::AccountId,Option,bool)>; + // DelegatedAttestations: delegation-id -> [claim-hash] + DelegatedAttestations get(delegated_attestations): map T::DelegationNodeId => Vec; } } diff --git a/runtime/src/delegation.rs b/runtime/src/delegation.rs index bb4a1166e..34c3827fd 100644 --- a/runtime/src/delegation.rs +++ b/runtime/src/delegation.rs @@ -1,4 +1,5 @@ +use rstd::result; use rstd::prelude::*; use runtime_primitives::traits::{Hash, CheckEqual, SimpleBitOps, Member, Verify, MaybeDisplay}; use support::{dispatch::Result, StorageMap, Parameter, decl_module, decl_storage}; @@ -89,25 +90,27 @@ decl_module! { Some(p) => { if >::exists(p) { let parent = >::get(p.clone()); - if parent.2 != sender { + if !parent.2.eq(&sender) { return Err("not owner of parent") - } else if parent.3 & Permissions::DELEGATE != Permissions::DELEGATE { + } else if (parent.3 & Permissions::DELEGATE) != Permissions::DELEGATE { return Err("not authorized to delegate") } else { - // TODO: check for cycles + // TODO: check for cycles? ::runtime_io::print("insert Delegation with parent"); >::insert(delegation_id.clone(), (root_id.clone(), Some(p.clone()), delegate, permissions, false)); + Self::add_child(delegation_id.clone(), p.clone()); } } else { return Err("parent not found") } }, None => { - if root.1 != sender { + if !root.1.eq(&sender) { return Err("not owner of root") } ::runtime_io::print("insert Delegation without parent"); >::insert(delegation_id.clone(), (root_id.clone(), None, delegate, permissions, false)); + Self::add_child(delegation_id.clone(), root_id.clone()); } } } else { @@ -115,6 +118,79 @@ decl_module! { } return Ok(()); } + + pub fn revoke_root(origin, root_id: T::DelegationNodeId) -> Result { + let sender = ensure_signed(origin)?; + if !>::exists(root_id) { + return Err("root not found") + } + let mut r = >::get(root_id.clone()); + if !r.1.eq(&sender) { + return Err("not permitted to revoke") + } + if !r.2 { + r.2 = true; + >::insert(root_id.clone(), r); + Self::revoke_children(&root_id); + } + + return Ok(()); + } + + pub fn revoke_delegation(origin, delegation_id: T::DelegationNodeId) -> Result { + let sender = ensure_signed(origin)?; + if !Self::is_delegating(&sender, &delegation_id)? { + return Err("not permitted to revoke") + } + Self::revoke(&delegation_id); + return Ok(()); + } + } +} + +impl Module { + pub fn is_delegating(account: &T::AccountId, delegation: &T::DelegationNodeId) -> result::Result { + if !>::exists(delegation) { + return Err("delegation not found") + } + let d = >::get(delegation); + if d.2.eq(account) { + Ok(true) + } else { + match d.1 { + None => { + let r = >::get(d.0.clone()); + Ok(r.1.eq(account)) + }, + Some(p) => { + return Self::is_delegating(account, &p) + } + } + } + } + + fn revoke(delegation: &T::DelegationNodeId) { + let mut d = >::get(delegation.clone()); + if !d.4 { + d.4 = true; + >::insert(delegation.clone(), d); + Self::revoke_children(delegation); + } + } + + fn revoke_children(delegation: &T::DelegationNodeId) { + if >::exists(delegation) { + let children = >::get(delegation); + for child in children { + Self::revoke(&child); + } + } + } + + fn add_child(child: T::DelegationNodeId, parent: T::DelegationNodeId) { + let mut children = >::get(parent.clone()); + children.push(child); + >::insert(parent, children); } } diff --git a/runtime/src/did.rs b/runtime/src/did.rs index 9b91c1639..946044338 100644 --- a/runtime/src/did.rs +++ b/runtime/src/did.rs @@ -19,6 +19,12 @@ decl_module! { >::insert(sender.clone(), (sign_key, box_key, doc_ref)); Ok(()) } + + pub fn remove(origin) -> Result { + let sender = ensure_signed(origin)?; + >::remove(sender.clone()); + Ok(()) + } } }