Skip to content

Commit

Permalink
Improve Proof (#1209)
Browse files Browse the repository at this point in the history
  • Loading branch information
abdulmth authored Jul 31, 2023
1 parent 6406f3f commit ec1b8ad
Show file tree
Hide file tree
Showing 19 changed files with 218 additions and 54 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<a href="https://github.com/iotaledger/identity.rs/blob/HEAD/LICENSE" style="text-decoration:none;"><img src="https://img.shields.io/github/license/iotaledger/identity.rs.svg" alt="Apache 2.0 license"></a>
<img src="https://deps.rs/repo/github/iotaledger/identity.rs/status.svg" alt="Dependencies">
<a href='https://coveralls.io/github/iotaledger/identity.rs?branch=main'><img src='https://coveralls.io/repos/github/iotaledger/identity.rs/badge.svg?branch=main' alt='Coverage Status' /></a>

</p>

<p align="center">
Expand Down
15 changes: 0 additions & 15 deletions bindings/wasm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions bindings/wasm/src/credential/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::credential::ArrayStatus;
use crate::credential::ArraySubject;
use crate::credential::ICredential;
use crate::credential::UrlOrIssuer;
use crate::credential::WasmProof;
use crate::error::Result;
use crate::error::WasmResult;

Expand Down Expand Up @@ -195,18 +196,25 @@ impl WasmCredential {
self.0.non_transferable
}

/// Returns a copy of the proof used to verify the {@link Credential}.
/// Optional cryptographic proof, unrelated to JWT.
#[wasm_bindgen]
pub fn proof(&self) -> Result<JsValue> {
// TODO: Update with proof.
JsValue::from_serde(&self.0.proof).wasm_result()
pub fn proof(&self) -> Option<WasmProof> {
self.0.proof.clone().map(WasmProof)
}

/// Returns a copy of the miscellaneous properties on the {@link Credential}.
#[wasm_bindgen]
pub fn properties(&self) -> Result<MapStringAny> {
MapStringAny::try_from(&self.0.properties)
}

/// Sets the `proof` property of the {@link Credential}.
///
/// Note that this proof is not related to JWT.
#[wasm_bindgen(js_name = "setProof")]
pub fn set_proof(&mut self, proof: Option<WasmProof>) {
self.0.set_proof(proof.map(|wasm_proof| wasm_proof.0))
}
}

impl_wasm_json!(WasmCredential, Credential);
Expand Down
8 changes: 8 additions & 0 deletions bindings/wasm/src/credential/credential_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use identity_iota::credential::CredentialBuilder;
use identity_iota::credential::Evidence;
use identity_iota::credential::Issuer;
use identity_iota::credential::Policy;
use identity_iota::credential::Proof;
use identity_iota::credential::RefreshService;
use identity_iota::credential::Schema;
use identity_iota::credential::Status;
Expand Down Expand Up @@ -38,6 +39,7 @@ impl TryFrom<ICredential> for CredentialBuilder {
terms_of_use,
evidence,
non_transferable,
proof,
properties,
} = values.into_serde::<ICredentialHelper>().wasm_result()?;

Expand Down Expand Up @@ -96,6 +98,9 @@ impl TryFrom<ICredential> for CredentialBuilder {
if let Some(non_transferable) = non_transferable {
builder = builder.non_transferable(non_transferable);
}
if let Some(proof) = proof {
builder = builder.proof(proof);
}

Ok(builder)
}
Expand Down Expand Up @@ -152,6 +157,9 @@ struct ICredentialHelper {
/// from the {@link Credential} subject.
#[typescript(name = "nonTransferable", type = "boolean")]
non_transferable: Option<bool>,
// The `proof` property of the {@link Credential}.
#[typescript(type = "Proof")]
proof: Option<Proof>,
/// Miscellaneous properties.
#[serde(flatten)]
#[typescript(optional = false, name = "[properties: string]", type = "unknown")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use identity_iota::credential::DecodedJwtPresentation;
use wasm_bindgen::prelude::*;

use crate::common::WasmTimestamp;
use crate::credential::jwt_presentation::WasmPresentation;
use crate::credential::UnknownCredential;
use crate::credential::WasmPresentation;
use crate::jose::WasmJwsHeader;

/// A cryptographically verified and decoded presentation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use super::decoded_jwt_presentation::WasmDecodedJwtPresentation;
use super::options::WasmJwtPresentationValidationOptions;
use crate::common::ImportedDocumentLock;
use crate::credential::jwt_presentation::WasmPresentation;
use crate::credential::WasmJwt;
use crate::credential::WasmPresentation;
use crate::did::IToCoreDocument;
use crate::did::WasmCoreDID;
use crate::error::Result;
Expand Down
6 changes: 4 additions & 2 deletions bindings/wasm/src/credential/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ pub use self::domain_linkage_configuration::WasmDomainLinkageConfiguration;
pub use self::jws::WasmJws;
pub use self::jwt::WasmJwt;
pub use self::jwt_credential_validation::*;
pub use self::jwt_presentation::*;
pub use self::jwt_presentation_validation::*;
pub use self::options::WasmFailFast;
pub use self::options::WasmSubjectHolderRelationship;
pub use self::presentation::*;
pub use self::proof::WasmProof;
pub use self::types::*;

mod credential;
Expand All @@ -23,8 +24,9 @@ mod domain_linkage_validator;
mod jws;
mod jwt;
mod jwt_credential_validation;
mod jwt_presentation;
mod jwt_presentation_validation;
mod linked_domain_service;
mod options;
mod presentation;
mod proof;
mod types;
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::credential::ArrayRefreshService;
use crate::credential::ArrayUnknownCredential;
use crate::credential::IPresentation;
use crate::credential::UnknownCredential;
use crate::credential::WasmProof;
use crate::credential::WasmUnknownCredentialContainer;
use crate::error::Result;
use crate::error::WasmResult;
Expand Down Expand Up @@ -126,10 +127,18 @@ impl WasmPresentation {
.map(|value| value.unchecked_into::<ArrayPolicy>())
}

/// Optional proof that can be verified by users in addition to JWS.
/// Optional cryptographic proof, unrelated to JWT.
#[wasm_bindgen]
pub fn proof(&self) -> Result<Option<MapStringAny>> {
self.0.proof.clone().map(MapStringAny::try_from).transpose()
pub fn proof(&self) -> Option<WasmProof> {
self.0.proof.clone().map(WasmProof)
}

/// Sets the proof property of the {@link Presentation}.
///
/// Note that this proof is not related to JWT.
#[wasm_bindgen(js_name = "setProof")]
pub fn set_proof(&mut self, proof: Option<WasmProof>) {
self.0.set_proof(proof.map(|wasm_proof| wasm_proof.0))
}

/// Returns a copy of the miscellaneous properties on the presentation.
Expand Down
45 changes: 45 additions & 0 deletions bindings/wasm/src/credential/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use identity_iota::core::Object;
use identity_iota::credential::Proof;
use wasm_bindgen::prelude::*;

use crate::error::Result;
use crate::error::WasmResult;

/// Represents a cryptographic proof that can be used to validate verifiable credentials and
/// presentations.
///
/// This representation does not inherently implement any standard; instead, it
/// can be utilized to implement standards or user-defined proofs. The presence of the
/// `type` field is necessary to accommodate different types of cryptographic proofs.
///
/// Note that this proof is not related to JWT and can be used in combination or as an alternative
/// to it.
#[wasm_bindgen(js_name = Proof)]
pub struct WasmProof(pub(crate) Proof);

#[wasm_bindgen(js_class = Proof)]
impl WasmProof {
#[wasm_bindgen(constructor)]
pub fn constructor(type_: String, properties: JsValue) -> Result<WasmProof> {
let properties: Object = properties.into_serde().wasm_result()?;
Ok(WasmProof(Proof::new(type_, properties)))
}

/// Returns the type of proof.
#[wasm_bindgen(js_name = "type")]
pub fn type_(&self) -> String {
self.0.type_.clone()
}

/// Returns the properties of the proof.
#[wasm_bindgen]
pub fn properties(&self) -> Result<JsValue> {
JsValue::from_serde(&self.0.properties).wasm_result()
}
}

impl_wasm_json!(WasmProof, Proof);
impl_wasm_clone!(WasmProof, Proof);
2 changes: 1 addition & 1 deletion bindings/wasm/tests/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ describe("Credential", function() {
properties.set("custom1", "asdf");
properties.set("custom2", 1234);
assert.deepStrictEqual(credential.properties(), properties);
assert.deepStrictEqual(credential.proof(), null);
assert.deepStrictEqual(credential.proof(), undefined);
});
});
});
Expand Down
15 changes: 15 additions & 0 deletions identity_credential/src/credential/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use crate::credential::Status;
use crate::credential::Subject;
use crate::error::Result;

use super::Proof;

/// A `CredentialBuilder` is used to create a customized `Credential`.
#[derive(Clone, Debug)]
pub struct CredentialBuilder<T = Object> {
Expand All @@ -33,6 +35,7 @@ pub struct CredentialBuilder<T = Object> {
pub(crate) terms_of_use: Vec<Policy>,
pub(crate) evidence: Vec<Evidence>,
pub(crate) non_transferable: Option<bool>,
pub(crate) proof: Option<Proof>,
pub(crate) properties: T,
}

Expand All @@ -53,6 +56,7 @@ impl<T> CredentialBuilder<T> {
terms_of_use: Vec::new(),
evidence: Vec::new(),
non_transferable: None,
proof: None,
properties,
}
}
Expand Down Expand Up @@ -157,6 +161,13 @@ impl<T> CredentialBuilder<T> {
self
}

/// Sets the value of the `proof` property.
#[must_use]
pub fn proof(mut self, value: Proof) -> Self {
self.proof = Some(value);
self
}

/// Returns a new `Credential` based on the `CredentialBuilder` configuration.
pub fn build(self) -> Result<Credential<T>> {
Credential::from_builder(self)
Expand Down Expand Up @@ -210,6 +221,7 @@ mod tests {

use crate::credential::Credential;
use crate::credential::CredentialBuilder;
use crate::credential::Proof;
use crate::credential::Subject;

fn subject() -> Subject {
Expand All @@ -230,13 +242,15 @@ mod tests {

#[test]
fn test_credential_builder_valid() {
let proof = Proof::new("test-type".to_owned(), Object::new());
let credential: Credential = CredentialBuilder::default()
.context(Url::parse("https://www.w3.org/2018/credentials/examples/v1").unwrap())
.id(Url::parse("http://example.edu/credentials/3732").unwrap())
.type_("UniversityDegreeCredential")
.subject(subject())
.issuer(issuer())
.issuance_date(Timestamp::parse("2010-01-01T00:00:00Z").unwrap())
.proof(proof)
.build()
.unwrap();

Expand Down Expand Up @@ -265,6 +279,7 @@ mod tests {
credential.credential_subject.get(0).unwrap().properties["degree"]["name"],
"Bachelor of Science and Arts"
);
assert_eq!(credential.proof.unwrap().type_, "test-type");
}

#[test]
Expand Down
24 changes: 11 additions & 13 deletions identity_credential/src/credential/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::error::Error;
use crate::error::Result;

use super::jwt_serialization::CredentialJwtClaims;
use super::Proof;

lazy_static::lazy_static! {
static ref BASE_CONTEXT: Context = Context::Url(Url::parse("https://www.w3.org/2018/credentials/v1").unwrap());
Expand Down Expand Up @@ -77,9 +78,9 @@ pub struct Credential<T = Object> {
/// Miscellaneous properties.
#[serde(flatten)]
pub properties: T,
/// Proof(s) used to verify a `Credential`
/// Optional cryptographic proof, unrelated to JWT.
#[serde(skip_serializing_if = "Option::is_none")]
pub proof: Option<Object>,
pub proof: Option<Proof>,
}

impl<T> Credential<T> {
Expand Down Expand Up @@ -117,7 +118,7 @@ impl<T> Credential<T> {
evidence: builder.evidence.into(),
non_transferable: builder.non_transferable,
properties: builder.properties,
proof: None,
proof: builder.proof,
};

this.check_structure()?;
Expand Down Expand Up @@ -153,6 +154,13 @@ impl<T> Credential<T> {
Ok(())
}

/// Sets the proof property of the `Credential`.
///
/// Note that this proof is not related to JWT.
pub fn set_proof(&mut self, proof: Option<Proof>) {
self.proof = proof;
}

/// Serializes the [`Credential`] as a JWT claims set
/// in accordance with [VC-JWT version 1.1](https://w3c.github.io/vc-jwt/#version-1.1).
///
Expand All @@ -166,16 +174,6 @@ impl<T> Credential<T> {
.to_json()
.map_err(|err| Error::JwtClaimsSetSerializationError(err.into()))
}

/// Returns a reference to the proof.
pub fn proof(&self) -> Option<&Object> {
self.proof.as_ref()
}

/// Returns a mutable reference to the proof.
pub fn proof_mut(&mut self) -> Option<&mut Object> {
self.proof.as_mut()
}
}

impl<T> Display for Credential<T>
Expand Down
3 changes: 2 additions & 1 deletion identity_credential/src/credential/jwt_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::credential::Credential;
use crate::credential::Evidence;
use crate::credential::Issuer;
use crate::credential::Policy;
use crate::credential::Proof;
use crate::credential::RefreshService;
use crate::credential::Schema;
use crate::credential::Status;
Expand Down Expand Up @@ -334,7 +335,7 @@ where
properties: Cow<'credential, T>,
/// Proof(s) used to verify a `Credential`
#[serde(skip_serializing_if = "Option::is_none")]
proof: Option<Cow<'credential, Object>>,
proof: Option<Cow<'credential, Proof>>,
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit ec1b8ad

Please sign in to comment.