From 00a18416b2a307490152ef30e3d8be30d533efda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Thu, 18 Jan 2024 17:40:38 +0100
Subject: [PATCH 01/23] Fix cargo release invocation (#1278)
---
.github/actions/publish/publish-rust/action.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/actions/publish/publish-rust/action.yml b/.github/actions/publish/publish-rust/action.yml
index c19319ac9b..3143267414 100644
--- a/.github/actions/publish/publish-rust/action.yml
+++ b/.github/actions/publish/publish-rust/action.yml
@@ -29,4 +29,4 @@ runs:
echo "dry-run: '${{ inputs.dry-run }}'"
echo "version: '${{ inputs.version }}'"
cargo login ${{ inputs.crates-token }}
- cargo release --workspace --isolated --no-dev-version --no-push --no-tag --dependent-version error --verbose $(if [ "${{ inputs.dry-run }}" = "false" ]; then echo --execute --no-confirm; fi) ${{ inputs.version }}
+ cargo release --workspace --isolated --no-push --no-tag --verbose $(if [ "${{ inputs.dry-run }}" = "false" ]; then echo --execute --no-confirm; fi) ${{ inputs.version }}
From 8bc3ab74fee373e9bde228c1fb2bbcf34f6fbd3c Mon Sep 17 00:00:00 2001
From: Enrico Marconi <31142849+UMR1352@users.noreply.github.com>
Date: Wed, 24 Jan 2024 16:54:19 +0100
Subject: [PATCH 02/23] Feat/status list 2021 (#1273)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* StatusList2021
* StatusList2021Credential
* StatusList2021Entry
* Multiple CredentialStatuses
* conversions between statuses, fix test
* StatusList2021Credential deserializable
* test revocation checking with statuslist2021
* WASM bindings
* example
* example enhancement
* wasm bindings example
* License
* docs
* make clippy happy
* clippy again
* fmt
* fmt & clippy
* license template
* revocation feature gate
* review comments
* fix bindings
* dprint fmt
* credential status refactor
* clippy + fmt
* better example
* status list review comment
* status list credential PR comments
* Review comments
* Fix WASM bindings
* Fix merge issue
* dprint fmt
* cargo clippy
* bindings tests
* review comments
* wasm example
* Update bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts
Co-authored-by: Eike Haß
* review comments
* clippy
* review comments
---------
Co-authored-by: Eike Haß
---
bindings/wasm/Cargo.toml | 2 +-
.../e2e/1_advanced/7_status_list_2021.cy.js | 11 +
bindings/wasm/docs/api-reference.md | 690 ++++++++++++++----
bindings/wasm/examples/README.md | 1 +
.../src/1_advanced/7_status_list_2021.ts | 169 +++++
bindings/wasm/examples/src/main.ts | 3 +
.../examples/src/tests/7_status_list_2021.ts | 8 +
bindings/wasm/src/credential/credential.rs | 1 +
.../jwt_credential_validator.rs | 18 +-
bindings/wasm/src/credential/mod.rs | 2 +
.../wasm/src/credential/revocation/mod.rs | 4 +
.../revocation/status_list_2021/credential.rs | 244 +++++++
.../revocation/status_list_2021/entry.rs | 72 ++
.../revocation/status_list_2021/mod.rs | 10 +
.../status_list_2021/status_list.rs | 58 ++
bindings/wasm/src/credential/types.rs | 3 +
bindings/wasm/src/error.rs | 4 +-
examples/1_advanced/8_status_list_2021.rs | 192 +++++
examples/Cargo.toml | 6 +-
examples/README.md | 3 +-
identity_credential/Cargo.toml | 3 +
identity_credential/src/credential/builder.rs | 4 +-
identity_credential/src/credential/status.rs | 4 +-
identity_credential/src/revocation/mod.rs | 13 +-
.../{ => revocation_bitmap_2022}/bitmap.rs | 2 +-
.../document_ext.rs | 4 +-
.../revocation/revocation_bitmap_2022/mod.rs | 8 +
.../revocation/status_list_2021/credential.rs | 406 +++++++++++
.../src/revocation/status_list_2021/entry.rs | 145 ++++
.../src/revocation/status_list_2021/mod.rs | 13 +
.../status_list_2021/status_list.rs | 174 +++++
.../jwt_credential_validation/error.rs | 3 +
.../jwt_credential_validator_utils.rs | 44 +-
identity_iota/Cargo.toml | 3 +
34 files changed, 2163 insertions(+), 164 deletions(-)
create mode 100644 bindings/wasm/cypress/e2e/1_advanced/7_status_list_2021.cy.js
create mode 100644 bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts
create mode 100644 bindings/wasm/examples/src/tests/7_status_list_2021.ts
create mode 100644 bindings/wasm/src/credential/revocation/mod.rs
create mode 100644 bindings/wasm/src/credential/revocation/status_list_2021/credential.rs
create mode 100644 bindings/wasm/src/credential/revocation/status_list_2021/entry.rs
create mode 100644 bindings/wasm/src/credential/revocation/status_list_2021/mod.rs
create mode 100644 bindings/wasm/src/credential/revocation/status_list_2021/status_list.rs
create mode 100644 examples/1_advanced/8_status_list_2021.rs
rename identity_credential/src/revocation/{ => revocation_bitmap_2022}/bitmap.rs (99%)
rename identity_credential/src/revocation/{ => revocation_bitmap_2022}/document_ext.rs (98%)
create mode 100644 identity_credential/src/revocation/revocation_bitmap_2022/mod.rs
create mode 100644 identity_credential/src/revocation/status_list_2021/credential.rs
create mode 100644 identity_credential/src/revocation/status_list_2021/entry.rs
create mode 100644 identity_credential/src/revocation/status_list_2021/mod.rs
create mode 100644 identity_credential/src/revocation/status_list_2021/status_list.rs
diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml
index 40d8057caf..09f0d7aa43 100644
--- a/bindings/wasm/Cargo.toml
+++ b/bindings/wasm/Cargo.toml
@@ -34,7 +34,7 @@ wasm-bindgen-futures = { version = "0.4", default-features = false }
version = "1.0.0"
path = "../../identity_iota"
default-features = false
-features = ["client", "revocation-bitmap", "resolver", "domain-linkage", "sd-jwt"]
+features = ["client", "revocation-bitmap", "resolver", "domain-linkage", "sd-jwt", "status-list-2021"]
[dev-dependencies]
rand = "0.8.5"
diff --git a/bindings/wasm/cypress/e2e/1_advanced/7_status_list_2021.cy.js b/bindings/wasm/cypress/e2e/1_advanced/7_status_list_2021.cy.js
new file mode 100644
index 0000000000..11a0a4617c
--- /dev/null
+++ b/bindings/wasm/cypress/e2e/1_advanced/7_status_list_2021.cy.js
@@ -0,0 +1,11 @@
+import { statusList2021 } from "../../../examples/dist/web/1_advanced/7_status_list_2021";
+import { setup } from "../../support/setup";
+
+describe(
+ "statusList2021",
+ () => {
+ it("Status List 2021", async () => {
+ await setup(statusList2021);
+ });
+ },
+);
diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index 0ed364a27c..e17fcf0c2c 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -159,6 +159,18 @@ with their corresponding disclosure digests.
Service
A DID Document Service used to enable trusted interactions associated with a DID subject.
+StatusList2021
+StatusList2021 data structure as described in W3C's VC status list 2021.
+
+StatusList2021Credential
+A parsed StatusList2021Credential.
+
+StatusList2021CredentialBuilder
+Builder type to construct valid StatusList2021Credential istances.
+
+StatusList2021Entry
+StatusList2021Entry implementation.
+
Storage
A type wrapping a JwkStorage
and KeyIdStorage
that should always be used together when
working with storage backed DID documents.
@@ -175,22 +187,10 @@ working with storage backed DID documents.
## Members
-- StatusCheck
-Controls validation behaviour when checking whether or not a credential has been revoked by its
-credentialStatus
.
-
-- Strict
-Validate the status if supported, reject any unsupported
-credentialStatus
types.
-Only RevocationBitmap2022
is currently supported.
-This is the default.
-
-- SkipUnsupported
-Validate the status if supported, skip any unsupported
-credentialStatus
types.
-
-- SkipAll
-Skip all status checks.
+- StateMetadataEncoding
+
+- StatusPurpose
+Purpose of a StatusList2021.
- SubjectHolderRelationship
Declares how credential subjects must relate to the presentation holder.
@@ -215,7 +215,24 @@ This variant is the default.
- FirstError
Return after the first error occurs.
-- StateMetadataEncoding
+- StatusCheck
+Controls validation behaviour when checking whether or not a credential has been revoked by its
+credentialStatus
.
+
+- Strict
+Validate the status if supported, reject any unsupported
+credentialStatus
types.
+Only RevocationBitmap2022
is currently supported.
+This is the default.
+
+- SkipUnsupported
+Validate the status if supported, skip any unsupported
+credentialStatus
types.
+
+- SkipAll
+Skip all status checks.
+
+- CredentialStatus
- MethodRelationship
@@ -232,15 +249,15 @@ This variant is the default.
This function does not check whether alg = EdDSA
in the protected header. Callers are expected to assert this
prior to calling the function.
-start()
-Initializes the console error panic hook for better error messages
-
encodeB64(data) ⇒ string
Encode the given bytes in url-safe base64.
decodeB64(data) ⇒ Uint8Array
Decode the given url-safe base64-encoded slice into its raw bytes.
+start()
+Initializes the console error panic hook for better error messages
+
@@ -457,14 +474,14 @@ if the object is being concurrently modified.
* [.insertService(service)](#CoreDocument+insertService)
* [.removeService(didUrl)](#CoreDocument+removeService) ⇒ [Service
](#Service) \| undefined
* [.resolveService(query)](#CoreDocument+resolveService) ⇒ [Service
](#Service) \| undefined
- * [.methods(scope)](#CoreDocument+methods) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
+ * [.methods([scope])](#CoreDocument+methods) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
* [.verificationRelationships()](#CoreDocument+verificationRelationships) ⇒ Array.<(DIDUrl\|VerificationMethod)>
* [.insertMethod(method, scope)](#CoreDocument+insertMethod)
* [.removeMethod(did)](#CoreDocument+removeMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
- * [.resolveMethod(query, scope)](#CoreDocument+resolveMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
+ * [.resolveMethod(query, [scope])](#CoreDocument+resolveMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
* [.attachMethodRelationship(didUrl, relationship)](#CoreDocument+attachMethodRelationship) ⇒ boolean
* [.detachMethodRelationship(didUrl, relationship)](#CoreDocument+detachMethodRelationship) ⇒ boolean
- * [.verifyJws(jws, options, signatureVerifier, detachedPayload)](#CoreDocument+verifyJws) ⇒ [DecodedJws
](#DecodedJws)
+ * [.verifyJws(jws, options, signatureVerifier, [detachedPayload])](#CoreDocument+verifyJws) ⇒ [DecodedJws
](#DecodedJws)
* [.revokeCredentials(serviceQuery, indices)](#CoreDocument+revokeCredentials)
* [.unrevokeCredentials(serviceQuery, indices)](#CoreDocument+unrevokeCredentials)
* [.clone()](#CoreDocument+clone) ⇒ [CoreDocument
](#CoreDocument)
@@ -474,7 +491,7 @@ if the object is being concurrently modified.
* [.generateMethod(storage, keyType, alg, fragment, scope)](#CoreDocument+generateMethod) ⇒ Promise.<string>
* [.purgeMethod(storage, id)](#CoreDocument+purgeMethod) ⇒ Promise.<void>
* [.createJws(storage, fragment, payload, options)](#CoreDocument+createJws) ⇒ [Promise.<Jws>
](#Jws)
- * [.createCredentialJwt(storage, fragment, credential, options, custom_claims)](#CoreDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
+ * [.createCredentialJwt(storage, fragment, credential, options, [custom_claims])](#CoreDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#CoreDocument+createPresentationJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* _static_
* [.fromJSON(json)](#CoreDocument.fromJSON) ⇒ [CoreDocument
](#CoreDocument)
@@ -654,7 +671,7 @@ if present.
-### coreDocument.methods(scope) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
+### coreDocument.methods([scope]) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
Returns a list of all [VerificationMethod](#VerificationMethod) in the DID Document,
whose verification relationship matches `scope`.
@@ -664,7 +681,7 @@ If `scope` is not set, a list over the **embedded** methods is returned.
| Param | Type |
| --- | --- |
-| scope | [MethodScope
](#MethodScope) \| undefined
|
+| [scope] | [MethodScope
](#MethodScope) \| undefined
|
@@ -697,7 +714,7 @@ Removes all references to the specified Verification Method.
-### coreDocument.resolveMethod(query, scope) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
+### coreDocument.resolveMethod(query, [scope]) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
Returns a copy of the first verification method with an `id` property
matching the provided `query` and the verification relationship
specified by `scope`, if present.
@@ -707,7 +724,7 @@ specified by `scope`, if present.
| Param | Type |
| --- | --- |
| query | [DIDUrl
](#DIDUrl) \| string
|
-| scope | [MethodScope
](#MethodScope) \| undefined
|
+| [scope] | [MethodScope
](#MethodScope) \| undefined
|
@@ -722,7 +739,7 @@ so it cannot be an embedded one.
| Param | Type |
| --- | --- |
| didUrl | [DIDUrl
](#DIDUrl) |
-| relationship | number
|
+| relationship | [MethodRelationship
](#MethodRelationship) |
@@ -734,11 +751,11 @@ Detaches the given relationship from the given method, if the method exists.
| Param | Type |
| --- | --- |
| didUrl | [DIDUrl
](#DIDUrl) |
-| relationship | number
|
+| relationship | [MethodRelationship
](#MethodRelationship) |
-### coreDocument.verifyJws(jws, options, signatureVerifier, detachedPayload) ⇒ [DecodedJws
](#DecodedJws)
+### coreDocument.verifyJws(jws, options, signatureVerifier, [detachedPayload]) ⇒ [DecodedJws
](#DecodedJws)
Decodes and verifies the provided JWS according to the passed `options` and `signatureVerifier`.
If no `signatureVerifier` argument is provided a default verifier will be used that is (only) capable of
verifying EdDSA signatures.
@@ -756,7 +773,7 @@ or set explicitly in the `options`.
| jws | [Jws
](#Jws) |
| options | [JwsVerificationOptions
](#JwsVerificationOptions) |
| signatureVerifier | IJwsVerifier
|
-| detachedPayload | string
\| undefined
|
+| [detachedPayload] | string
\| undefined
|
@@ -865,7 +882,7 @@ See [RFC7515 section 3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1).
-### coreDocument.createCredentialJwt(storage, fragment, credential, options, custom_claims) ⇒ [Promise.<Jwt>
](#Jwt)
+### coreDocument.createCredentialJwt(storage, fragment, credential, options, [custom_claims]) ⇒ [Promise.<Jwt>
](#Jwt)
Produces a JWT where the payload is produced from the given `credential`
in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
@@ -883,7 +900,7 @@ The `custom_claims` can be used to set additional claims on the resulting JWT.
| fragment | string
|
| credential | [Credential
](#Credential) |
| options | [JwsSignatureOptions
](#JwsSignatureOptions) |
-| custom_claims | Record.<string, any>
\| undefined
|
+| [custom_claims] | Record.<string, any>
\| undefined
|
@@ -939,8 +956,8 @@ Deserializes an instance from a plain JS representation.
* [.nonTransferable()](#Credential+nonTransferable) ⇒ boolean
\| undefined
* [.proof()](#Credential+proof) ⇒ [Proof
](#Proof) \| undefined
* [.properties()](#Credential+properties) ⇒ Map.<string, any>
- * [.setProof(proof)](#Credential+setProof)
- * [.toJwtClaims(custom_claims)](#Credential+toJwtClaims) ⇒ Record.<string, any>
+ * [.setProof([proof])](#Credential+setProof)
+ * [.toJwtClaims([custom_claims])](#Credential+toJwtClaims) ⇒ Record.<string, any>
* [.toJSON()](#Credential+toJSON) ⇒ any
* [.clone()](#Credential+clone) ⇒ [Credential
](#Credential)
* _static_
@@ -1052,7 +1069,7 @@ Returns a copy of the miscellaneous properties on the [Credential](#Credential).
**Kind**: instance method of [Credential
](#Credential)
-### credential.setProof(proof)
+### credential.setProof([proof])
Sets the `proof` property of the [Credential](#Credential).
Note that this proof is not related to JWT.
@@ -1061,11 +1078,11 @@ Note that this proof is not related to JWT.
| Param | Type |
| --- | --- |
-| proof | [Proof
](#Proof) \| undefined
|
+| [proof] | [Proof
](#Proof) \| undefined
|
-### credential.toJwtClaims(custom_claims) ⇒ Record.<string, any>
+### credential.toJwtClaims([custom_claims]) ⇒ Record.<string, any>
Serializes the `Credential` as a JWT claims set
in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
@@ -1075,7 +1092,7 @@ The resulting object can be used as the payload of a JWS when issuing the creden
| Param | Type |
| --- | --- |
-| custom_claims | Record.<string, any>
\| undefined
|
+| [custom_claims] | Record.<string, any>
\| undefined
|
@@ -1133,11 +1150,11 @@ A method agnostic DID Url.
* [.did()](#DIDUrl+did) ⇒ [CoreDID
](#CoreDID)
* [.urlStr()](#DIDUrl+urlStr) ⇒ string
* [.fragment()](#DIDUrl+fragment) ⇒ string
\| undefined
- * [.setFragment(value)](#DIDUrl+setFragment)
+ * [.setFragment([value])](#DIDUrl+setFragment)
* [.path()](#DIDUrl+path) ⇒ string
\| undefined
- * [.setPath(value)](#DIDUrl+setPath)
+ * [.setPath([value])](#DIDUrl+setPath)
* [.query()](#DIDUrl+query) ⇒ string
\| undefined
- * [.setQuery(value)](#DIDUrl+setQuery)
+ * [.setQuery([value])](#DIDUrl+setQuery)
* [.join(segment)](#DIDUrl+join) ⇒ [DIDUrl
](#DIDUrl)
* [.toString()](#DIDUrl+toString) ⇒ string
* [.toJSON()](#DIDUrl+toJSON) ⇒ any
@@ -1166,14 +1183,14 @@ Returns a copy of the [DIDUrl](#DIDUrl) method fragment, if any. Excludes the le
**Kind**: instance method of [DIDUrl
](#DIDUrl)
-### didUrl.setFragment(value)
+### didUrl.setFragment([value])
Sets the `fragment` component of the [DIDUrl](#DIDUrl).
**Kind**: instance method of [DIDUrl
](#DIDUrl)
| Param | Type |
| --- | --- |
-| value | string
\| undefined
|
+| [value] | string
\| undefined
|
@@ -1183,14 +1200,14 @@ Returns a copy of the [DIDUrl](#DIDUrl) path.
**Kind**: instance method of [DIDUrl
](#DIDUrl)
-### didUrl.setPath(value)
+### didUrl.setPath([value])
Sets the `path` component of the [DIDUrl](#DIDUrl).
**Kind**: instance method of [DIDUrl
](#DIDUrl)
| Param | Type |
| --- | --- |
-| value | string
\| undefined
|
+| [value] | string
\| undefined
|
@@ -1200,14 +1217,14 @@ Returns a copy of the [DIDUrl](#DIDUrl) method query, if any. Excludes the leadi
**Kind**: instance method of [DIDUrl
](#DIDUrl)
-### didUrl.setQuery(value)
+### didUrl.setQuery([value])
Sets the `query` component of the [DIDUrl](#DIDUrl).
**Kind**: instance method of [DIDUrl
](#DIDUrl)
| Param | Type |
| --- | --- |
-| value | string
\| undefined
|
+| [value] | string
\| undefined
|
@@ -1958,13 +1975,13 @@ if the object is being concurrently modified.
* [.insertService(service)](#IotaDocument+insertService)
* [.removeService(did)](#IotaDocument+removeService) ⇒ [Service
](#Service) \| undefined
* [.resolveService(query)](#IotaDocument+resolveService) ⇒ [Service
](#Service) \| undefined
- * [.methods(scope)](#IotaDocument+methods) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
+ * [.methods([scope])](#IotaDocument+methods) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
* [.insertMethod(method, scope)](#IotaDocument+insertMethod)
* [.removeMethod(did)](#IotaDocument+removeMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
- * [.resolveMethod(query, scope)](#IotaDocument+resolveMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
+ * [.resolveMethod(query, [scope])](#IotaDocument+resolveMethod) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
* [.attachMethodRelationship(didUrl, relationship)](#IotaDocument+attachMethodRelationship) ⇒ boolean
* [.detachMethodRelationship(didUrl, relationship)](#IotaDocument+detachMethodRelationship) ⇒ boolean
- * [.verifyJws(jws, options, signatureVerifier, detachedPayload)](#IotaDocument+verifyJws) ⇒ [DecodedJws
](#DecodedJws)
+ * [.verifyJws(jws, options, signatureVerifier, [detachedPayload])](#IotaDocument+verifyJws) ⇒ [DecodedJws
](#DecodedJws)
* [.pack()](#IotaDocument+pack) ⇒ Uint8Array
* [.packWithEncoding(encoding)](#IotaDocument+packWithEncoding) ⇒ Uint8Array
* [.metadata()](#IotaDocument+metadata) ⇒ [IotaDocumentMetadata
](#IotaDocumentMetadata)
@@ -1973,7 +1990,7 @@ if the object is being concurrently modified.
* [.metadataUpdated()](#IotaDocument+metadataUpdated) ⇒ [Timestamp
](#Timestamp) \| undefined
* [.setMetadataUpdated(timestamp)](#IotaDocument+setMetadataUpdated)
* [.metadataDeactivated()](#IotaDocument+metadataDeactivated) ⇒ boolean
\| undefined
- * [.setMetadataDeactivated(deactivated)](#IotaDocument+setMetadataDeactivated)
+ * [.setMetadataDeactivated([deactivated])](#IotaDocument+setMetadataDeactivated)
* [.metadataStateControllerAddress()](#IotaDocument+metadataStateControllerAddress) ⇒ string
\| undefined
* [.metadataGovernorAddress()](#IotaDocument+metadataGovernorAddress) ⇒ string
\| undefined
* [.setMetadataPropertyUnchecked(key, value)](#IotaDocument+setMetadataPropertyUnchecked)
@@ -1988,7 +2005,7 @@ if the object is being concurrently modified.
* [.purgeMethod(storage, id)](#IotaDocument+purgeMethod) ⇒ Promise.<void>
* ~~[.createJwt(storage, fragment, payload, options)](#IotaDocument+createJwt) ⇒ [Promise.<Jws>
](#Jws)~~
* [.createJws(storage, fragment, payload, options)](#IotaDocument+createJws) ⇒ [Promise.<Jws>
](#Jws)
- * [.createCredentialJwt(storage, fragment, credential, options, custom_claims)](#IotaDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
+ * [.createCredentialJwt(storage, fragment, credential, options, [custom_claims])](#IotaDocument+createCredentialJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* [.createPresentationJwt(storage, fragment, presentation, signature_options, presentation_options)](#IotaDocument+createPresentationJwt) ⇒ [Promise.<Jwt>
](#Jwt)
* _static_
* [.newWithId(id)](#IotaDocument.newWithId) ⇒ [IotaDocument
](#IotaDocument)
@@ -2108,7 +2125,7 @@ if present.
-### iotaDocument.methods(scope) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
+### iotaDocument.methods([scope]) ⇒ [Array.<VerificationMethod>
](#VerificationMethod)
Returns a list of all [VerificationMethod](#VerificationMethod) in the DID Document,
whose verification relationship matches `scope`.
@@ -2118,7 +2135,7 @@ If `scope` is not set, a list over the **embedded** methods is returned.
| Param | Type |
| --- | --- |
-| scope | [MethodScope
](#MethodScope) \| undefined
|
+| [scope] | [MethodScope
](#MethodScope) \| undefined
|
@@ -2145,7 +2162,7 @@ Removes all references to the specified Verification Method.
-### iotaDocument.resolveMethod(query, scope) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
+### iotaDocument.resolveMethod(query, [scope]) ⇒ [VerificationMethod
](#VerificationMethod) \| undefined
Returns a copy of the first verification method with an `id` property
matching the provided `query` and the verification relationship
specified by `scope`, if present.
@@ -2155,7 +2172,7 @@ specified by `scope`, if present.
| Param | Type |
| --- | --- |
| query | [DIDUrl
](#DIDUrl) \| string
|
-| scope | [MethodScope
](#MethodScope) \| undefined
|
+| [scope] | [MethodScope
](#MethodScope) \| undefined
|
@@ -2170,7 +2187,7 @@ so it cannot be an embedded one.
| Param | Type |
| --- | --- |
| didUrl | [DIDUrl
](#DIDUrl) |
-| relationship | number
|
+| relationship | [MethodRelationship
](#MethodRelationship) |
@@ -2182,11 +2199,11 @@ Detaches the given relationship from the given method, if the method exists.
| Param | Type |
| --- | --- |
| didUrl | [DIDUrl
](#DIDUrl) |
-| relationship | number
|
+| relationship | [MethodRelationship
](#MethodRelationship) |
-### iotaDocument.verifyJws(jws, options, signatureVerifier, detachedPayload) ⇒ [DecodedJws
](#DecodedJws)
+### iotaDocument.verifyJws(jws, options, signatureVerifier, [detachedPayload]) ⇒ [DecodedJws
](#DecodedJws)
Decodes and verifies the provided JWS according to the passed `options` and `signatureVerifier`.
If no `signatureVerifier` argument is provided a default verifier will be used that is (only) capable of
verifying EdDSA signatures.
@@ -2203,7 +2220,7 @@ take place.
| jws | [Jws
](#Jws) |
| options | [JwsVerificationOptions
](#JwsVerificationOptions) |
| signatureVerifier | IJwsVerifier
|
-| detachedPayload | string
\| undefined
|
+| [detachedPayload] | string
\| undefined
|
@@ -2221,7 +2238,7 @@ Serializes the document for inclusion in an Alias Output's state metadata.
| Param | Type |
| --- | --- |
-| encoding | number
|
+| encoding | [StateMetadataEncoding
](#StateMetadataEncoding) |
@@ -2274,14 +2291,14 @@ Returns a copy of the deactivated status of the DID document.
**Kind**: instance method of [IotaDocument
](#IotaDocument)
-### iotaDocument.setMetadataDeactivated(deactivated)
+### iotaDocument.setMetadataDeactivated([deactivated])
Sets the deactivated status of the DID document.
**Kind**: instance method of [IotaDocument
](#IotaDocument)
| Param | Type |
| --- | --- |
-| deactivated | boolean
\| undefined
|
+| [deactivated] | boolean
\| undefined
|
@@ -2441,7 +2458,7 @@ See [RFC7515 section 3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1).
-### iotaDocument.createCredentialJwt(storage, fragment, credential, options, custom_claims) ⇒ [Promise.<Jwt>
](#Jwt)
+### iotaDocument.createCredentialJwt(storage, fragment, credential, options, [custom_claims]) ⇒ [Promise.<Jwt>
](#Jwt)
Produces a JWS where the payload is produced from the given `credential`
in accordance with [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
@@ -2459,7 +2476,7 @@ The `custom_claims` can be used to set additional claims on the resulting JWT.
| fragment | string
|
| credential | [Credential
](#Credential) |
| options | [JwsSignatureOptions
](#JwsSignatureOptions) |
-| custom_claims | Record.<string, any>
\| undefined
|
+| [custom_claims] | Record.<string, any>
\| undefined
|
@@ -2628,7 +2645,7 @@ and resolution of DID documents in Alias Outputs.
**Kind**: global class
* [IotaIdentityClientExt](#IotaIdentityClientExt)
- * [.newDidOutput(client, address, document, rentStructure)](#IotaIdentityClientExt.newDidOutput) ⇒ Promise.<AliasOutputBuilderParams>
+ * [.newDidOutput(client, address, document, [rentStructure])](#IotaIdentityClientExt.newDidOutput) ⇒ Promise.<AliasOutputBuilderParams>
* [.updateDidOutput(client, document)](#IotaIdentityClientExt.updateDidOutput) ⇒ Promise.<AliasOutputBuilderParams>
* [.deactivateDidOutput(client, did)](#IotaIdentityClientExt.deactivateDidOutput) ⇒ Promise.<AliasOutputBuilderParams>
* [.resolveDid(client, did)](#IotaIdentityClientExt.resolveDid) ⇒ [Promise.<IotaDocument>
](#IotaDocument)
@@ -2636,7 +2653,7 @@ and resolution of DID documents in Alias Outputs.
-### IotaIdentityClientExt.newDidOutput(client, address, document, rentStructure) ⇒ Promise.<AliasOutputBuilderParams>
+### IotaIdentityClientExt.newDidOutput(client, address, document, [rentStructure]) ⇒ Promise.<AliasOutputBuilderParams>
Create a DID with a new Alias Output containing the given `document`.
The `address` will be set as the state controller and governor unlock conditions.
@@ -2653,7 +2670,7 @@ NOTE: this does *not* publish the Alias Output.
| client | IIotaIdentityClient
|
| address | Address
|
| document | [IotaDocument
](#IotaDocument) |
-| rentStructure | IRent
\| undefined
|
+| [rentStructure] | IRent
\| undefined
|
@@ -3302,7 +3319,7 @@ Deserializes an instance from a JSON object.
**Kind**: global class
* [JwsSignatureOptions](#JwsSignatureOptions)
- * [new JwsSignatureOptions(options)](#new_JwsSignatureOptions_new)
+ * [new JwsSignatureOptions([options])](#new_JwsSignatureOptions_new)
* _instance_
* [.setAttachJwk(value)](#JwsSignatureOptions+setAttachJwk)
* [.setB64(value)](#JwsSignatureOptions+setB64)
@@ -3320,11 +3337,11 @@ Deserializes an instance from a JSON object.
-### new JwsSignatureOptions(options)
+### new JwsSignatureOptions([options])
| Param | Type |
| --- | --- |
-| options | IJwsSignatureOptions
\| undefined
|
+| [options] | IJwsSignatureOptions
\| undefined
|
@@ -3454,7 +3471,7 @@ Deserializes an instance from a JSON object.
**Kind**: global class
* [JwsVerificationOptions](#JwsVerificationOptions)
- * [new JwsVerificationOptions(options)](#new_JwsVerificationOptions_new)
+ * [new JwsVerificationOptions([options])](#new_JwsVerificationOptions_new)
* _instance_
* [.setNonce(value)](#JwsVerificationOptions+setNonce)
* [.setMethodScope(value)](#JwsVerificationOptions+setMethodScope)
@@ -3466,13 +3483,13 @@ Deserializes an instance from a JSON object.
-### new JwsVerificationOptions(options)
+### new JwsVerificationOptions([options])
Creates a new [JwsVerificationOptions](#JwsVerificationOptions) from the given fields.
| Param | Type |
| --- | --- |
-| options | IJwsVerificationOptions
\| undefined
|
+| [options] | IJwsVerificationOptions
\| undefined
|
@@ -3593,7 +3610,7 @@ Options to declare validation criteria when validating credentials.
**Kind**: global class
* [JwtCredentialValidationOptions](#JwtCredentialValidationOptions)
- * [new JwtCredentialValidationOptions(options)](#new_JwtCredentialValidationOptions_new)
+ * [new JwtCredentialValidationOptions([options])](#new_JwtCredentialValidationOptions_new)
* _instance_
* [.toJSON()](#JwtCredentialValidationOptions+toJSON) ⇒ any
* [.clone()](#JwtCredentialValidationOptions+clone) ⇒ [JwtCredentialValidationOptions
](#JwtCredentialValidationOptions)
@@ -3602,11 +3619,11 @@ Options to declare validation criteria when validating credentials.
-### new JwtCredentialValidationOptions(options)
+### new JwtCredentialValidationOptions([options])
| Param | Type |
| --- | --- |
-| options | IJwtCredentialValidationOptions
\| undefined
|
+| [options] | IJwtCredentialValidationOptions
\| undefined
|
@@ -3648,6 +3665,7 @@ A type for decoding and validating [Credential](#Credential).
* [.checkIssuedOnOrBefore(credential, timestamp)](#JwtCredentialValidator.checkIssuedOnOrBefore)
* [.checkSubjectHolderRelationship(credential, holder, relationship)](#JwtCredentialValidator.checkSubjectHolderRelationship)
* [.checkStatus(credential, trustedIssuers, statusCheck)](#JwtCredentialValidator.checkStatus)
+ * [.checkStatusWithStatusList2021(credential, status_list, status_check)](#JwtCredentialValidator.checkStatusWithStatusList2021)
* [.extractIssuer(credential)](#JwtCredentialValidator.extractIssuer) ⇒ [CoreDID
](#CoreDID)
* [.extractIssuerFromJwt(credential)](#JwtCredentialValidator.extractIssuerFromJwt) ⇒ [CoreDID
](#CoreDID)
@@ -3698,7 +3716,7 @@ An error is returned whenever a validated condition is not satisfied.
| credential_jwt | [Jwt
](#Jwt) |
| issuer | [CoreDocument
](#CoreDocument) \| IToCoreDocument
|
| options | [JwtCredentialValidationOptions
](#JwtCredentialValidationOptions) |
-| fail_fast | number
|
+| fail_fast | [FailFast
](#FailFast) |
@@ -3764,7 +3782,7 @@ Validate that the relationship between the `holder` and the credential subjects
| --- | --- |
| credential | [Credential
](#Credential) |
| holder | string
|
-| relationship | number
|
+| relationship | [SubjectHolderRelationship
](#SubjectHolderRelationship) |
@@ -3779,7 +3797,20 @@ Only supports `RevocationBitmap2022`.
| --- | --- |
| credential | [Credential
](#Credential) |
| trustedIssuers | Array.<(CoreDocument\|IToCoreDocument)>
|
-| statusCheck | number
|
+| statusCheck | [StatusCheck
](#StatusCheck) |
+
+
+
+### JwtCredentialValidator.checkStatusWithStatusList2021(credential, status_list, status_check)
+Checks wheter the credential status has been revoked using `StatusList2021`.
+
+**Kind**: static method of [JwtCredentialValidator
](#JwtCredentialValidator)
+
+| Param | Type |
+| --- | --- |
+| credential | [Credential
](#Credential) |
+| status_list | [StatusList2021Credential
](#StatusList2021Credential) |
+| status_check | [StatusCheck
](#StatusCheck) |
@@ -3885,7 +3916,7 @@ Error will be thrown in case the validation fails.
**Kind**: global class
* [JwtPresentationOptions](#JwtPresentationOptions)
- * [new JwtPresentationOptions(options)](#new_JwtPresentationOptions_new)
+ * [new JwtPresentationOptions([options])](#new_JwtPresentationOptions_new)
* _instance_
* [.toJSON()](#JwtPresentationOptions+toJSON) ⇒ any
* [.clone()](#JwtPresentationOptions+clone) ⇒ [JwtPresentationOptions
](#JwtPresentationOptions)
@@ -3894,7 +3925,7 @@ Error will be thrown in case the validation fails.
-### new JwtPresentationOptions(options)
+### new JwtPresentationOptions([options])
Creates a new [JwtPresentationOptions](#JwtPresentationOptions) from the given fields.
Throws an error if any of the options are invalid.
@@ -3902,7 +3933,7 @@ Throws an error if any of the options are invalid.
| Param | Type |
| --- | --- |
-| options | IJwtPresentationOptions
\| undefined
|
+| [options] | IJwtPresentationOptions
\| undefined
|
@@ -3935,7 +3966,7 @@ Options to declare validation criteria when validating presentation.
**Kind**: global class
* [JwtPresentationValidationOptions](#JwtPresentationValidationOptions)
- * [new JwtPresentationValidationOptions(options)](#new_JwtPresentationValidationOptions_new)
+ * [new JwtPresentationValidationOptions([options])](#new_JwtPresentationValidationOptions_new)
* _instance_
* [.toJSON()](#JwtPresentationValidationOptions+toJSON) ⇒ any
* [.clone()](#JwtPresentationValidationOptions+clone) ⇒ [JwtPresentationValidationOptions
](#JwtPresentationValidationOptions)
@@ -3944,7 +3975,7 @@ Options to declare validation criteria when validating presentation.
-### new JwtPresentationValidationOptions(options)
+### new JwtPresentationValidationOptions([options])
Creates a new [JwtPresentationValidationOptions](#JwtPresentationValidationOptions) from the given fields.
Throws an error if any of the options are invalid.
@@ -3952,7 +3983,7 @@ Throws an error if any of the options are invalid.
| Param | Type |
| --- | --- |
-| options | IJwtPresentationValidationOptions
\| undefined
|
+| [options] | IJwtPresentationValidationOptions
\| undefined
|
@@ -4072,7 +4103,7 @@ Options to declare validation criteria when validating credentials.
**Kind**: global class
* [KeyBindingJWTValidationOptions](#KeyBindingJWTValidationOptions)
- * [new KeyBindingJWTValidationOptions(options)](#new_KeyBindingJWTValidationOptions_new)
+ * [new KeyBindingJWTValidationOptions([options])](#new_KeyBindingJWTValidationOptions_new)
* _instance_
* [.toJSON()](#KeyBindingJWTValidationOptions+toJSON) ⇒ any
* [.clone()](#KeyBindingJWTValidationOptions+clone) ⇒ [KeyBindingJWTValidationOptions
](#KeyBindingJWTValidationOptions)
@@ -4081,11 +4112,11 @@ Options to declare validation criteria when validating credentials.
-### new KeyBindingJWTValidationOptions(options)
+### new KeyBindingJWTValidationOptions([options])
| Param | Type |
| --- | --- |
-| options | IKeyBindingJWTValidationOptions
\| undefined
|
+| [options] | IKeyBindingJWTValidationOptions
\| undefined
|
@@ -4118,7 +4149,7 @@ Claims set for key binding JWT.
**Kind**: global class
* [KeyBindingJwtClaims](#KeyBindingJwtClaims)
- * [new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, issued_at, custom_properties)](#new_KeyBindingJwtClaims_new)
+ * [new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, [issued_at], [custom_properties])](#new_KeyBindingJwtClaims_new)
* _instance_
* [.toString()](#KeyBindingJwtClaims+toString) ⇒ string
* [.iat()](#KeyBindingJwtClaims+iat) ⇒ bigint
@@ -4134,7 +4165,7 @@ Claims set for key binding JWT.
-### new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, issued_at, custom_properties)
+### new KeyBindingJwtClaims(jwt, disclosures, nonce, aud, [issued_at], [custom_properties])
Creates a new [`KeyBindingJwtClaims`].
When `issued_at` is left as None, it will automatically default to the current time.
@@ -4148,8 +4179,8 @@ When `issued_at` is set to `None` and the system returns time earlier than `Syst
| disclosures | Array.<string>
|
| nonce | string
|
| aud | string
|
-| issued_at | [Timestamp
](#Timestamp) \| undefined
|
-| custom_properties | Record.<string, any>
\| undefined
|
+| [issued_at] | [Timestamp
](#Timestamp) \| undefined
|
+| [custom_properties] | Record.<string, any>
\| undefined
|
@@ -4586,7 +4617,7 @@ Deserializes an instance from a JSON object.
* [.refreshService()](#Presentation+refreshService) ⇒ Array.<RefreshService>
* [.termsOfUse()](#Presentation+termsOfUse) ⇒ Array.<Policy>
* [.proof()](#Presentation+proof) ⇒ [Proof
](#Proof) \| undefined
- * [.setProof(proof)](#Presentation+setProof)
+ * [.setProof([proof])](#Presentation+setProof)
* [.properties()](#Presentation+properties) ⇒ Map.<string, any>
* [.toJSON()](#Presentation+toJSON) ⇒ any
* [.clone()](#Presentation+clone) ⇒ [Presentation
](#Presentation)
@@ -4655,7 +4686,7 @@ Optional cryptographic proof, unrelated to JWT.
**Kind**: instance method of [Presentation
](#Presentation)
-### presentation.setProof(proof)
+### presentation.setProof([proof])
Sets the proof property of the [Presentation](#Presentation).
Note that this proof is not related to JWT.
@@ -4664,7 +4695,7 @@ Note that this proof is not related to JWT.
| Param | Type |
| --- | --- |
-| proof | [Proof
](#Proof) \| undefined
|
+| [proof] | [Proof
](#Proof) \| undefined
|
@@ -4953,7 +4984,7 @@ Representation of an SD-JWT of the format
**Kind**: global class
* [SdJwt](#SdJwt)
- * [new SdJwt(jwt, disclosures, key_binding_jwt)](#new_SdJwt_new)
+ * [new SdJwt(jwt, disclosures, [key_binding_jwt])](#new_SdJwt_new)
* _instance_
* [.presentation()](#SdJwt+presentation) ⇒ string
* [.toString()](#SdJwt+toString) ⇒ string
@@ -4968,7 +4999,7 @@ Representation of an SD-JWT of the format
-### new SdJwt(jwt, disclosures, key_binding_jwt)
+### new SdJwt(jwt, disclosures, [key_binding_jwt])
Creates a new `SdJwt` from its components.
@@ -4976,7 +5007,7 @@ Creates a new `SdJwt` from its components.
| --- | --- |
| jwt | string
|
| disclosures | Array.<string>
|
-| key_binding_jwt | string
\| undefined
|
+| [key_binding_jwt] | string
\| undefined
|
@@ -5108,7 +5139,7 @@ An error is returned whenever a validated condition is not satisfied.
| sd_jwt | [SdJwt
](#SdJwt) |
| issuer | [CoreDocument
](#CoreDocument) \| IToCoreDocument
|
| options | [JwtCredentialValidationOptions
](#JwtCredentialValidationOptions) |
-| fail_fast | number
|
+| fail_fast | [FailFast
](#FailFast) |
@@ -5201,8 +5232,8 @@ Note: digests are created using the sha-256 algorithm.
* [SdObjectEncoder](#SdObjectEncoder)
* [new SdObjectEncoder(object)](#new_SdObjectEncoder_new)
- * [.conceal(path, salt)](#SdObjectEncoder+conceal) ⇒ [Disclosure
](#Disclosure)
- * [.concealArrayEntry(path, element_index, salt)](#SdObjectEncoder+concealArrayEntry) ⇒ [Disclosure
](#Disclosure)
+ * [.conceal(path, [salt])](#SdObjectEncoder+conceal) ⇒ [Disclosure
](#Disclosure)
+ * [.concealArrayEntry(path, element_index, [salt])](#SdObjectEncoder+concealArrayEntry) ⇒ [Disclosure
](#Disclosure)
* [.addSdAlgProperty()](#SdObjectEncoder+addSdAlgProperty)
* [.encodeToString()](#SdObjectEncoder+encodeToString) ⇒ string
* [.toString()](#SdObjectEncoder+toString) ⇒ string
@@ -5222,7 +5253,7 @@ Creates a new `SdObjectEncoder` with `sha-256` hash function.
-### sdObjectEncoder.conceal(path, salt) ⇒ [Disclosure
](#Disclosure)
+### sdObjectEncoder.conceal(path, [salt]) ⇒ [Disclosure
](#Disclosure)
Substitutes a value with the digest of its disclosure.
If no salt is provided, the disclosure will be created with a random salt value.
@@ -5241,11 +5272,11 @@ Use `concealArrayEntry` for values in arrays.
| Param | Type |
| --- | --- |
| path | Array.<string>
|
-| salt | string
\| undefined
|
+| [salt] | string
\| undefined
|
-### sdObjectEncoder.concealArrayEntry(path, element_index, salt) ⇒ [Disclosure
](#Disclosure)
+### sdObjectEncoder.concealArrayEntry(path, element_index, [salt]) ⇒ [Disclosure
](#Disclosure)
Substitutes a value within an array with the digest of its disclosure.
If no salt is provided, the disclosure will be created with random salt value.
@@ -5263,7 +5294,7 @@ the index of the element to be concealed (index start at 0).
| --- | --- |
| path | Array.<string>
|
| element_index | number
|
-| salt | string
\| undefined
|
+| [salt] | string
\| undefined
|
@@ -5383,6 +5414,365 @@ Deserializes an instance from a JSON object.
| --- | --- |
| json | any
|
+
+
+## StatusList2021
+StatusList2021 data structure as described in [W3C's VC status list 2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/).
+
+**Kind**: global class
+
+* [StatusList2021](#StatusList2021)
+ * [new StatusList2021([size])](#new_StatusList2021_new)
+ * _instance_
+ * [.clone()](#StatusList2021+clone) ⇒ [StatusList2021
](#StatusList2021)
+ * [.len()](#StatusList2021+len) ⇒ number
+ * [.get(index)](#StatusList2021+get) ⇒ boolean
+ * [.set(index, value)](#StatusList2021+set)
+ * [.intoEncodedStr()](#StatusList2021+intoEncodedStr) ⇒ string
+ * _static_
+ * [.fromEncodedStr(s)](#StatusList2021.fromEncodedStr) ⇒ [StatusList2021
](#StatusList2021)
+
+
+
+### new StatusList2021([size])
+Creates a new [StatusList2021](#StatusList2021) of `size` entries.
+
+
+| Param | Type |
+| --- | --- |
+| [size] | number
\| undefined
|
+
+
+
+### statusList2021.clone() ⇒ [StatusList2021
](#StatusList2021)
+Deep clones the object.
+
+**Kind**: instance method of [StatusList2021
](#StatusList2021)
+
+
+### statusList2021.len() ⇒ number
+Returns the number of entries in this [StatusList2021](#StatusList2021).
+
+**Kind**: instance method of [StatusList2021
](#StatusList2021)
+
+
+### statusList2021.get(index) ⇒ boolean
+Returns whether the entry at `index` is set.
+
+**Kind**: instance method of [StatusList2021
](#StatusList2021)
+
+| Param | Type |
+| --- | --- |
+| index | number
|
+
+
+
+### statusList2021.set(index, value)
+Sets the value of the `index`-th entry.
+
+**Kind**: instance method of [StatusList2021
](#StatusList2021)
+
+| Param | Type |
+| --- | --- |
+| index | number
|
+| value | boolean
|
+
+
+
+### statusList2021.intoEncodedStr() ⇒ string
+Encodes this [StatusList2021](#StatusList2021) into its compressed
+base64 string representation.
+
+**Kind**: instance method of [StatusList2021
](#StatusList2021)
+
+
+### StatusList2021.fromEncodedStr(s) ⇒ [StatusList2021
](#StatusList2021)
+Attempts to decode a [StatusList2021](#StatusList2021) from a string.
+
+**Kind**: static method of [StatusList2021
](#StatusList2021)
+
+| Param | Type |
+| --- | --- |
+| s | string
|
+
+
+
+## StatusList2021Credential
+A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021credential).
+
+**Kind**: global class
+
+* [StatusList2021Credential](#StatusList2021Credential)
+ * [new StatusList2021Credential(credential)](#new_StatusList2021Credential_new)
+ * _instance_
+ * [.id()](#StatusList2021Credential+id) ⇒ string
+ * [.setCredentialStatus(credential, index, value)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+ * [.purpose()](#StatusList2021Credential+purpose) ⇒ [StatusPurpose
](#StatusPurpose)
+ * [.entry(index)](#StatusList2021Credential+entry) ⇒ [CredentialStatus
](#CredentialStatus)
+ * [.clone()](#StatusList2021Credential+clone) ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+ * [.toJSON()](#StatusList2021Credential+toJSON) ⇒ any
+ * _static_
+ * [.fromJSON(json)](#StatusList2021Credential.fromJSON) ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+
+
+
+### new StatusList2021Credential(credential)
+Creates a new [StatusList2021Credential](#StatusList2021Credential).
+
+
+| Param | Type |
+| --- | --- |
+| credential | [Credential
](#Credential) |
+
+
+
+### statusList2021Credential.id() ⇒ string
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+
+### statusList2021Credential.setCredentialStatus(credential, index, value) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+Sets the given credential's status using the `index`-th entry of this status list.
+Returns the created `credentialStatus`.
+
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+| Param | Type |
+| --- | --- |
+| credential | [Credential
](#Credential) |
+| index | number
|
+| value | boolean
|
+
+
+
+### statusList2021Credential.purpose() ⇒ [StatusPurpose
](#StatusPurpose)
+Returns the [StatusPurpose](#StatusPurpose) of this [StatusList2021Credential](#StatusList2021Credential).
+
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+
+### statusList2021Credential.entry(index) ⇒ [CredentialStatus
](#CredentialStatus)
+Returns the state of the `index`-th entry, if any.
+
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+| Param | Type |
+| --- | --- |
+| index | number
|
+
+
+
+### statusList2021Credential.clone() ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+
+### statusList2021Credential.toJSON() ⇒ any
+**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
+
+
+### StatusList2021Credential.fromJSON(json) ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+**Kind**: static method of [StatusList2021Credential
](#StatusList2021Credential)
+
+| Param | Type |
+| --- | --- |
+| json | any
|
+
+
+
+## StatusList2021CredentialBuilder
+Builder type to construct valid [StatusList2021Credential](#StatusList2021Credential) istances.
+
+**Kind**: global class
+
+* [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder)
+ * [new StatusList2021CredentialBuilder([status_list])](#new_StatusList2021CredentialBuilder_new)
+ * [.purpose(purpose)](#StatusList2021CredentialBuilder+purpose) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.subjectId(id)](#StatusList2021CredentialBuilder+subjectId) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.expirationDate(time)](#StatusList2021CredentialBuilder+expirationDate) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.issuer(issuer)](#StatusList2021CredentialBuilder+issuer) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.context(context)](#StatusList2021CredentialBuilder+context) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.type(t)](#StatusList2021CredentialBuilder+type) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.proof(proof)](#StatusList2021CredentialBuilder+proof) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+ * [.build()](#StatusList2021CredentialBuilder+build) ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+
+
+
+### new StatusList2021CredentialBuilder([status_list])
+Creates a new [StatusList2021CredentialBuilder](#StatusList2021CredentialBuilder).
+
+
+| Param | Type |
+| --- | --- |
+| [status_list] | [StatusList2021
](#StatusList2021) \| undefined
|
+
+
+
+### statusList2021CredentialBuilder.purpose(purpose) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Sets the purpose of the [StatusList2021Credential](#StatusList2021Credential) that is being created.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| purpose | [StatusPurpose
](#StatusPurpose) |
+
+
+
+### statusList2021CredentialBuilder.subjectId(id) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Sets `credentialSubject.id`.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| id | string
|
+
+
+
+### statusList2021CredentialBuilder.expirationDate(time) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Sets the expiration date of the credential.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| time | [Timestamp
](#Timestamp) |
+
+
+
+### statusList2021CredentialBuilder.issuer(issuer) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Sets the issuer of the credential.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| issuer | string
|
+
+
+
+### statusList2021CredentialBuilder.context(context) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Sets the context of the credential.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| context | string
|
+
+
+
+### statusList2021CredentialBuilder.type(t) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Adds a credential type.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| t | string
|
+
+
+
+### statusList2021CredentialBuilder.proof(proof) ⇒ [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+Adds a credential's proof.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+| Param | Type |
+| --- | --- |
+| proof | [Proof
](#Proof) |
+
+
+
+### statusList2021CredentialBuilder.build() ⇒ [StatusList2021Credential
](#StatusList2021Credential)
+Attempts to build a valid [StatusList2021Credential](#StatusList2021Credential) with the previously provided data.
+
+**Kind**: instance method of [StatusList2021CredentialBuilder
](#StatusList2021CredentialBuilder)
+
+
+## StatusList2021Entry
+[StatusList2021Entry](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021entry) implementation.
+
+**Kind**: global class
+
+* [StatusList2021Entry](#StatusList2021Entry)
+ * [new StatusList2021Entry(status_list, purpose, index, [id])](#new_StatusList2021Entry_new)
+ * _instance_
+ * [.id()](#StatusList2021Entry+id) ⇒ string
+ * [.purpose()](#StatusList2021Entry+purpose) ⇒ [StatusPurpose
](#StatusPurpose)
+ * [.index()](#StatusList2021Entry+index) ⇒ number
+ * [.status_list_credential()](#StatusList2021Entry+status_list_credential) ⇒ string
+ * [.toStatus()](#StatusList2021Entry+toStatus) ⇒ Status
+ * [.clone()](#StatusList2021Entry+clone) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+ * [.toJSON()](#StatusList2021Entry+toJSON) ⇒ any
+ * _static_
+ * [.fromJSON(json)](#StatusList2021Entry.fromJSON) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+
+
+
+### new StatusList2021Entry(status_list, purpose, index, [id])
+Creates a new [StatusList2021Entry](#StatusList2021Entry).
+
+
+| Param | Type |
+| --- | --- |
+| status_list | string
|
+| purpose | [StatusPurpose
](#StatusPurpose) |
+| index | number
|
+| [id] | string
\| undefined
|
+
+
+
+### statusList2021Entry.id() ⇒ string
+Returns this `credentialStatus`'s `id`.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.purpose() ⇒ [StatusPurpose
](#StatusPurpose)
+Returns the purpose of this entry.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.index() ⇒ number
+Returns the index of this entry.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.status\_list\_credential() ⇒ string
+Returns the referenced [StatusList2021Credential](#StatusList2021Credential)'s url.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.toStatus() ⇒ Status
+Downcasts [this](this) to [Status](Status)
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.clone() ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+Deep clones the object.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### statusList2021Entry.toJSON() ⇒ any
+Serializes this to a JSON object.
+
+**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
+
+
+### StatusList2021Entry.fromJSON(json) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+Deserializes an instance from a JSON object.
+
+**Kind**: static method of [StatusList2021Entry
](#StatusList2021Entry)
+
+| Param | Type |
+| --- | --- |
+| json | any
|
+
## Storage
@@ -5585,7 +5975,7 @@ A DID Document Verification Method.
* [.toJSON()](#VerificationMethod+toJSON) ⇒ any
* [.clone()](#VerificationMethod+clone) ⇒ [VerificationMethod
](#VerificationMethod)
* _static_
- * [.newFromJwk(did, key, fragment)](#VerificationMethod.newFromJwk) ⇒ [VerificationMethod
](#VerificationMethod)
+ * [.newFromJwk(did, key, [fragment])](#VerificationMethod.newFromJwk) ⇒ [VerificationMethod
](#VerificationMethod)
* [.fromJSON(json)](#VerificationMethod.fromJSON) ⇒ [VerificationMethod
](#VerificationMethod)
@@ -5693,7 +6083,7 @@ Deep clones the object.
**Kind**: instance method of [VerificationMethod
](#VerificationMethod)
-### VerificationMethod.newFromJwk(did, key, fragment) ⇒ [VerificationMethod
](#VerificationMethod)
+### VerificationMethod.newFromJwk(did, key, [fragment]) ⇒ [VerificationMethod
](#VerificationMethod)
Creates a new [VerificationMethod](#VerificationMethod) from the given `did` and [Jwk](#Jwk). If `fragment` is not given
the `kid` value of the given `key` will be used, if present, otherwise an error is returned.
@@ -5710,7 +6100,7 @@ done automatically if `None` is passed in as the fragment.
| --- | --- |
| did | [CoreDID
](#CoreDID) \| IToCoreDID
|
| key | [Jwk
](#Jwk) |
-| fragment | string
\| undefined
|
+| [fragment] | string
\| undefined
|
@@ -5723,35 +6113,14 @@ Deserializes an instance from a JSON object.
| --- | --- |
| json | any
|
-
-
-## StatusCheck
-Controls validation behaviour when checking whether or not a credential has been revoked by its
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status).
-
-**Kind**: global variable
-
-
-## Strict
-Validate the status if supported, reject any unsupported
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
-
-Only `RevocationBitmap2022` is currently supported.
-
-This is the default.
-
-**Kind**: global variable
-
-
-## SkipUnsupported
-Validate the status if supported, skip any unsupported
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+
+## StateMetadataEncoding
**Kind**: global variable
-
+
-## SkipAll
-Skip all status checks.
+## StatusPurpose
+Purpose of a [StatusList2021](#StatusList2021).
**Kind**: global variable
@@ -5799,9 +6168,40 @@ Return all errors that occur during validation.
Return after the first error occurs.
**Kind**: global variable
-
+
+
+## StatusCheck
+Controls validation behaviour when checking whether or not a credential has been revoked by its
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status).
-## StateMetadataEncoding
+**Kind**: global variable
+
+
+## Strict
+Validate the status if supported, reject any unsupported
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+
+Only `RevocationBitmap2022` is currently supported.
+
+This is the default.
+
+**Kind**: global variable
+
+
+## SkipUnsupported
+Validate the status if supported, skip any unsupported
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+
+**Kind**: global variable
+
+
+## SkipAll
+Skip all status checks.
+
+**Kind**: global variable
+
+
+## CredentialStatus
**Kind**: global variable
@@ -5829,12 +6229,6 @@ prior to calling the function.
| decodedSignature | Uint8Array
|
| publicKey | [Jwk
](#Jwk) |
-
-
-## start()
-Initializes the console error panic hook for better error messages
-
-**Kind**: global function
## encodeB64(data) ⇒ string
@@ -5857,3 +6251,9 @@ Decode the given url-safe base64-encoded slice into its raw bytes.
| --- | --- |
| data | Uint8Array
|
+
+
+## start()
+Initializes the console error panic hook for better error messages
+
+**Kind**: global function
diff --git a/bindings/wasm/examples/README.md b/bindings/wasm/examples/README.md
index 98cec6b1f7..74914481b9 100644
--- a/bindings/wasm/examples/README.md
+++ b/bindings/wasm/examples/README.md
@@ -60,6 +60,7 @@ The following advanced examples are available:
| [4_custom_resolution](src/1_advanced/4_custom_resolution.ts) | Demonstrates how to set up a resolver using custom handlers. |
| [5_domain_linkage](src/1_advanced/5_domain_linkage.ts) | Demonstrates how to link a domain and a DID and verify the linkage. |
| [6_sd_jwt](src/1_advanced/6_sd_jwt.ts) | Demonstrates how to create a selective disclosure verifiable credential |
+| [7_domain_linkage](src/1_advanced/7_status_list_2021.ts) | Demonstrates how to revoke a credential using `StatusList2021`. |
## Browser
diff --git a/bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts b/bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts
new file mode 100644
index 0000000000..4e70d8fa19
--- /dev/null
+++ b/bindings/wasm/examples/src/1_advanced/7_status_list_2021.ts
@@ -0,0 +1,169 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+import {
+ Credential,
+ EdDSAJwsVerifier,
+ FailFast,
+ JwkMemStore,
+ JwsSignatureOptions,
+ JwtCredentialValidationOptions,
+ JwtCredentialValidator,
+ KeyIdMemStore,
+ StatusCheck,
+ StatusList2021,
+ StatusList2021Credential,
+ StatusList2021CredentialBuilder,
+ StatusList2021Entry,
+ StatusPurpose,
+ Storage,
+} from "@iota/identity-wasm/node";
+import { Client, MnemonicSecretManager, Utils } from "@iota/sdk-wasm/node";
+import { API_ENDPOINT, createDid } from "../util";
+
+export async function statusList2021() {
+ // ===========================================================================
+ // Create a Verifiable Credential.
+ // ===========================================================================
+
+ const client = new Client({
+ primaryNode: API_ENDPOINT,
+ localPow: true,
+ });
+
+ // Generate a random mnemonic for the issuer.
+ const issuerSecretManager: MnemonicSecretManager = {
+ mnemonic: Utils.generateMnemonic(),
+ };
+
+ // Create an identity for the issuer with one verification method `key-1`.
+ const issuerStorage: Storage = new Storage(
+ new JwkMemStore(),
+ new KeyIdMemStore(),
+ );
+ let { document: issuerDocument, fragment: issuerFragment } = await createDid(
+ client,
+ issuerSecretManager,
+ issuerStorage,
+ );
+
+ // Generate a random mnemonic for Alice.
+ const aliceSecretManager: MnemonicSecretManager = {
+ mnemonic: Utils.generateMnemonic(),
+ };
+
+ // Create an identity for the holder, in this case also the subject.
+ const aliceStorage: Storage = new Storage(
+ new JwkMemStore(),
+ new KeyIdMemStore(),
+ );
+ let { document: aliceDocument } = await createDid(
+ client,
+ aliceSecretManager,
+ aliceStorage,
+ );
+
+ // Create a new empty status list. No credentials have been revoked yet.
+ const statusList = new StatusList2021();
+
+ // Create a status list credential so that the status list can be stored anywhere.
+ // The issuer makes this credential available on `http://example.com/credential/status`.
+ // For the purposes of this example, the credential will be used directly without fetching.
+ const statusListCredential = new StatusList2021CredentialBuilder(statusList)
+ .purpose(StatusPurpose.Revocation)
+ .subjectId("http://example.com/credential/status")
+ .issuer(issuerDocument.id().toString())
+ .build();
+ const statusListCredentialJSON = statusListCredential.toJSON();
+ console.log("Status list credential > " + statusListCredential);
+
+ // Create a credential subject indicating the degree earned by Alice, linked to their DID.
+ const subject = {
+ id: aliceDocument.id(),
+ name: "Alice",
+ degreeName: "Bachelor of Science and Arts",
+ degreeType: "BachelorDegree",
+ GPA: "4.0",
+ };
+
+ // Create an unsigned `UniversityDegree` credential for Alice.
+ // The issuer also chooses a unique `StatusList2021` index to be able to revoke it later.
+ const CREDENTIAL_INDEX = 5;
+ const status = new StatusList2021Entry(statusListCredential.id(), statusListCredential.purpose(), CREDENTIAL_INDEX)
+ .toStatus();
+ const credential = new Credential({
+ id: "https://example.edu/credentials/3732",
+ type: "UniversityDegreeCredential",
+ credentialStatus: status,
+ issuer: issuerDocument.id(),
+ credentialSubject: subject,
+ });
+
+ // Create signed JWT credential.
+ const credentialJwt = await issuerDocument.createCredentialJwt(
+ issuerStorage,
+ issuerFragment,
+ credential,
+ new JwsSignatureOptions(),
+ );
+ console.log(`Credential JWT > ${credentialJwt.toString()}`);
+
+ // Validate the credential using the issuer's DID Document.
+ const validationOptions = new JwtCredentialValidationOptions({ status: StatusCheck.SkipUnsupported });
+ // The validator has no way of retrieving the status list to check for the
+ // revocation of the credential. Let's skip that pass and perform the operation manually.
+ let jwtCredentialValidator = new JwtCredentialValidator(new EdDSAJwsVerifier());
+
+ try {
+ jwtCredentialValidator.validate(
+ credentialJwt,
+ issuerDocument,
+ validationOptions,
+ FailFast.FirstError,
+ );
+ // Check manually for revocation
+ JwtCredentialValidator.checkStatusWithStatusList2021(
+ credential,
+ statusListCredential,
+ StatusCheck.Strict,
+ );
+ } catch (e) {
+ // This line shouldn't be called as the credential is valid and unrevoked
+ console.log("Something went wrong: " + e);
+ }
+
+ // ===========================================================================
+ // Revocation of the Verifiable Credential.
+ // ===========================================================================
+
+ // At a later time, the issuer university found out that Alice cheated in her final exam.
+ // The issuer will revoke Alice's credential.
+
+ // The issuer retrieves the status list credential.
+ const refetchedStatusListCredential = new StatusList2021Credential(new Credential(statusListCredentialJSON as any));
+
+ // Update the status list credential.
+ // This revokes the credential's unique index.
+ refetchedStatusListCredential.setCredentialStatus(credential, CREDENTIAL_INDEX, true);
+
+ // Credential verification now fails.
+ try {
+ jwtCredentialValidator.validate(
+ credentialJwt,
+ issuerDocument,
+ validationOptions,
+ FailFast.FirstError,
+ );
+ /// Since the credential has been revoked, this validation step will throw an error.
+ JwtCredentialValidator.checkStatusWithStatusList2021(
+ credential,
+ refetchedStatusListCredential,
+ StatusCheck.Strict,
+ );
+ // In case the revocation failed for some reason we will hit this point
+ console.log("Revocation Failed!");
+ } catch (e) {
+ /// The credential has been revoked.
+ console.log("The credential has been successfully revoked.");
+ }
+}
diff --git a/bindings/wasm/examples/src/main.ts b/bindings/wasm/examples/src/main.ts
index bf71211e3e..145980e649 100644
--- a/bindings/wasm/examples/src/main.ts
+++ b/bindings/wasm/examples/src/main.ts
@@ -16,6 +16,7 @@ import { didIssuesTokens } from "./1_advanced/3_did_issues_tokens";
import { customResolution } from "./1_advanced/4_custom_resolution";
import { domainLinkage } from "./1_advanced/5_domain_linkage";
import { sdJwt } from "./1_advanced/6_sd_jwt";
+import { statusList2021 } from "./1_advanced/7_status_list_2021";
async function main() {
// Extract example name.
@@ -55,6 +56,8 @@ async function main() {
return await domainLinkage();
case "6_sd_jwt":
return await sdJwt();
+ case "7_status_list_2021":
+ return await statusList2021();
default:
throw "Unknown example name: '" + argument + "'";
}
diff --git a/bindings/wasm/examples/src/tests/7_status_list_2021.ts b/bindings/wasm/examples/src/tests/7_status_list_2021.ts
new file mode 100644
index 0000000000..2698e210c4
--- /dev/null
+++ b/bindings/wasm/examples/src/tests/7_status_list_2021.ts
@@ -0,0 +1,8 @@
+import { statusList2021 } from "../1_advanced/7_status_list_2021";
+
+// Only verifies that no uncaught exceptions are thrown, including syntax errors etc.
+describe("Test node examples", function() {
+ it("StatusList2021", async () => {
+ await statusList2021();
+ });
+});
diff --git a/bindings/wasm/src/credential/credential.rs b/bindings/wasm/src/credential/credential.rs
index 98158bd97e..69ef827834 100644
--- a/bindings/wasm/src/credential/credential.rs
+++ b/bindings/wasm/src/credential/credential.rs
@@ -30,6 +30,7 @@ use crate::error::Result;
use crate::error::WasmResult;
#[wasm_bindgen(js_name = Credential, inspectable)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WasmCredential(pub(crate) Credential);
#[wasm_bindgen(js_class = Credential)]
diff --git a/bindings/wasm/src/credential/jwt_credential_validation/jwt_credential_validator.rs b/bindings/wasm/src/credential/jwt_credential_validation/jwt_credential_validator.rs
index 74682d3e0d..9434a6d521 100644
--- a/bindings/wasm/src/credential/jwt_credential_validation/jwt_credential_validator.rs
+++ b/bindings/wasm/src/credential/jwt_credential_validation/jwt_credential_validator.rs
@@ -1,4 +1,4 @@
-// Copyright 2020-2023 IOTA Stiftung
+// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
use identity_iota::core::Object;
@@ -13,6 +13,7 @@ use crate::common::ImportedDocumentLock;
use crate::common::ImportedDocumentReadGuard;
use crate::common::WasmTimestamp;
use crate::credential::options::WasmStatusCheck;
+use crate::credential::revocation::status_list_2021::WasmStatusList2021Credential;
use crate::credential::WasmCredential;
use crate::credential::WasmDecodedJwtCredential;
use crate::credential::WasmFailFast;
@@ -170,6 +171,21 @@ impl WasmJwtCredentialValidator {
JwtCredentialValidatorUtils::check_status(&credential.0, &trusted_issuers, status_check).wasm_result()
}
+ /// Checks wheter the credential status has been revoked using `StatusList2021`.
+ #[wasm_bindgen(js_name = checkStatusWithStatusList2021)]
+ pub fn check_status_with_status_list_2021(
+ credential: &WasmCredential,
+ status_list: &WasmStatusList2021Credential,
+ status_check: WasmStatusCheck,
+ ) -> Result<()> {
+ JwtCredentialValidatorUtils::check_status_with_status_list_2021(
+ &credential.0,
+ &status_list.inner,
+ status_check.into(),
+ )
+ .wasm_result()
+ }
+
/// Utility for extracting the issuer field of a {@link Credential} as a DID.
///
/// ### Errors
diff --git a/bindings/wasm/src/credential/mod.rs b/bindings/wasm/src/credential/mod.rs
index 755ce11afe..832eac1cd4 100644
--- a/bindings/wasm/src/credential/mod.rs
+++ b/bindings/wasm/src/credential/mod.rs
@@ -14,6 +14,7 @@ pub use self::options::WasmFailFast;
pub use self::options::WasmSubjectHolderRelationship;
pub use self::presentation::*;
pub use self::proof::WasmProof;
+pub use self::revocation::*;
pub use self::types::*;
mod credential;
@@ -29,4 +30,5 @@ mod linked_domain_service;
mod options;
mod presentation;
mod proof;
+mod revocation;
mod types;
diff --git a/bindings/wasm/src/credential/revocation/mod.rs b/bindings/wasm/src/credential/revocation/mod.rs
new file mode 100644
index 0000000000..7ad04980b4
--- /dev/null
+++ b/bindings/wasm/src/credential/revocation/mod.rs
@@ -0,0 +1,4 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+pub mod status_list_2021;
diff --git a/bindings/wasm/src/credential/revocation/status_list_2021/credential.rs b/bindings/wasm/src/credential/revocation/status_list_2021/credential.rs
new file mode 100644
index 0000000000..d440dc8814
--- /dev/null
+++ b/bindings/wasm/src/credential/revocation/status_list_2021/credential.rs
@@ -0,0 +1,244 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use std::ops::Deref;
+
+use identity_iota::core::Context;
+use identity_iota::core::Url;
+use identity_iota::credential::status_list_2021::CredentialStatus;
+use identity_iota::credential::status_list_2021::StatusList2021Credential;
+use identity_iota::credential::status_list_2021::StatusList2021CredentialBuilder;
+use identity_iota::credential::status_list_2021::StatusPurpose;
+use identity_iota::credential::Issuer;
+use wasm_bindgen::prelude::*;
+
+use crate::common::WasmTimestamp;
+use crate::credential::WasmCredential;
+use crate::credential::WasmProof;
+use crate::error::Result;
+use crate::error::WasmResult;
+
+use super::WasmStatusList2021;
+use super::WasmStatusList2021Entry;
+
+#[wasm_bindgen(js_name = CredentialStatus)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub enum WasmCredentialStatus {
+ Revoked = 0,
+ Suspended = 1,
+ Valid = 2,
+}
+
+impl From for WasmCredentialStatus {
+ fn from(value: CredentialStatus) -> Self {
+ match value {
+ CredentialStatus::Revoked => Self::Revoked,
+ CredentialStatus::Suspended => Self::Suspended,
+ CredentialStatus::Valid => Self::Valid,
+ }
+ }
+}
+
+impl From for CredentialStatus {
+ fn from(value: WasmCredentialStatus) -> Self {
+ match value {
+ WasmCredentialStatus::Revoked => Self::Revoked,
+ WasmCredentialStatus::Suspended => Self::Suspended,
+ WasmCredentialStatus::Valid => Self::Valid,
+ }
+ }
+}
+
+/// Purpose of a {@link StatusList2021}.
+#[wasm_bindgen(js_name = StatusPurpose)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub enum WasmStatusPurpose {
+ Revocation = 0,
+ Suspension = 1,
+}
+
+impl From for WasmStatusPurpose {
+ fn from(value: StatusPurpose) -> Self {
+ match value {
+ StatusPurpose::Revocation => Self::Revocation,
+ StatusPurpose::Suspension => Self::Suspension,
+ }
+ }
+}
+
+impl From for StatusPurpose {
+ fn from(value: WasmStatusPurpose) -> Self {
+ match value {
+ WasmStatusPurpose::Revocation => Self::Revocation,
+ WasmStatusPurpose::Suspension => Self::Suspension,
+ }
+ }
+}
+
+/// A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021credential).
+#[wasm_bindgen(js_name = "StatusList2021Credential", inspectable)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+#[serde(from = "StatusList2021Credential", into = "StatusList2021Credential")]
+pub struct WasmStatusList2021Credential {
+ pub(crate) inner: StatusList2021Credential,
+ wasm_credential: WasmCredential,
+}
+
+impl Deref for WasmStatusList2021Credential {
+ type Target = WasmCredential;
+ fn deref(&self) -> &Self::Target {
+ &self.wasm_credential
+ }
+}
+
+impl From for WasmStatusList2021Credential {
+ fn from(value: StatusList2021Credential) -> Self {
+ Self {
+ wasm_credential: WasmCredential(value.clone().into_inner()),
+ inner: value,
+ }
+ }
+}
+
+impl From for StatusList2021Credential {
+ fn from(value: WasmStatusList2021Credential) -> Self {
+ value.inner
+ }
+}
+
+#[wasm_bindgen(js_class = StatusList2021Credential)]
+impl WasmStatusList2021Credential {
+ /// Creates a new {@link StatusList2021Credential}.
+ #[wasm_bindgen(constructor)]
+ pub fn new(credential: WasmCredential) -> Result {
+ StatusList2021Credential::try_from(credential.0)
+ .map(Into::into)
+ .wasm_result()
+ }
+
+ #[wasm_bindgen]
+ pub fn id(&self) -> String {
+ self.inner.id.as_deref().map(ToString::to_string).unwrap()
+ }
+
+ /// Sets the given credential's status using the `index`-th entry of this status list.
+ /// Returns the created `credentialStatus`.
+ #[wasm_bindgen(js_name = "setCredentialStatus")]
+ pub fn set_credential_status(
+ &mut self,
+ credential: &mut WasmCredential,
+ index: usize,
+ revoked_or_suspended: bool,
+ ) -> Result {
+ let entry = self
+ .inner
+ .set_credential_status(&mut credential.0, index, revoked_or_suspended)
+ .wasm_result()?;
+ self.wasm_credential = WasmCredential(self.inner.clone().into_inner());
+
+ Ok(WasmStatusList2021Entry(entry))
+ }
+
+ /// Returns the {@link StatusPurpose} of this {@link StatusList2021Credential}.
+ #[wasm_bindgen]
+ pub fn purpose(&self) -> WasmStatusPurpose {
+ self.inner.purpose().into()
+ }
+
+ /// Returns the state of the `index`-th entry, if any.
+ #[wasm_bindgen]
+ pub fn entry(&self, index: usize) -> Result {
+ self.inner.entry(index).map(WasmCredentialStatus::from).wasm_result()
+ }
+
+ #[wasm_bindgen(js_name = "clone")]
+ pub fn wasm_clone(&self) -> WasmStatusList2021Credential {
+ self.clone()
+ }
+
+ #[wasm_bindgen(js_name = "fromJSON")]
+ pub fn from_json(json: JsValue) -> Result {
+ json.into_serde::().wasm_result()
+ }
+
+ #[wasm_bindgen(js_name = "toJSON")]
+ pub fn to_json(&self) -> Result {
+ JsValue::from_serde(self).wasm_result()
+ }
+}
+
+/// Builder type to construct valid {@link StatusList2021Credential} istances.
+#[wasm_bindgen(js_name = StatusList2021CredentialBuilder)]
+pub struct WasmStatusList2021CredentialBuilder(StatusList2021CredentialBuilder);
+
+#[wasm_bindgen(js_class = StatusList2021CredentialBuilder)]
+impl WasmStatusList2021CredentialBuilder {
+ /// Creates a new {@link StatusList2021CredentialBuilder}.
+ #[wasm_bindgen(constructor)]
+ pub fn new(status_list: Option) -> WasmStatusList2021CredentialBuilder {
+ Self(StatusList2021CredentialBuilder::new(status_list.unwrap_or_default().0))
+ }
+
+ /// Sets the purpose of the {@link StatusList2021Credential} that is being created.
+ #[wasm_bindgen]
+ pub fn purpose(mut self, purpose: WasmStatusPurpose) -> WasmStatusList2021CredentialBuilder {
+ self.0 = self.0.purpose(purpose.into());
+ self
+ }
+
+ /// Sets `credentialSubject.id`.
+ #[wasm_bindgen(js_name = "subjectId")]
+ pub fn subject_id(mut self, id: String) -> Result {
+ let id = Url::parse(id).wasm_result()?;
+ self.0 = self.0.subject_id(id);
+
+ Ok(self)
+ }
+
+ /// Sets the expiration date of the credential.
+ #[wasm_bindgen(js_name = "expirationDate")]
+ pub fn expiration_date(mut self, time: WasmTimestamp) -> WasmStatusList2021CredentialBuilder {
+ self.0 = self.0.expiration_date(time.0);
+ self
+ }
+
+ /// Sets the issuer of the credential.
+ #[wasm_bindgen]
+ pub fn issuer(mut self, issuer: String) -> Result {
+ let issuer = Url::parse(issuer).wasm_result()?;
+ self.0 = self.0.issuer(Issuer::Url(issuer));
+
+ Ok(self)
+ }
+
+ /// Sets the context of the credential.
+ #[wasm_bindgen]
+ pub fn context(mut self, context: String) -> Result {
+ let ctx = Context::Url(Url::parse(context).wasm_result()?);
+ self.0 = self.0.context(ctx);
+
+ Ok(self)
+ }
+
+ /// Adds a credential type.
+ #[wasm_bindgen(js_name = "type")]
+ pub fn r#type(mut self, t: String) -> WasmStatusList2021CredentialBuilder {
+ self.0 = self.0.add_type(t);
+ self
+ }
+
+ /// Adds a credential's proof.
+ #[wasm_bindgen]
+ pub fn proof(mut self, proof: WasmProof) -> WasmStatusList2021CredentialBuilder {
+ self.0 = self.0.proof(proof.0);
+ self
+ }
+
+ /// Attempts to build a valid {@link StatusList2021Credential} with the previously provided data.
+ #[wasm_bindgen]
+ pub fn build(self) -> Result {
+ let credential = self.0.build().wasm_result()?;
+
+ WasmStatusList2021Credential::new(WasmCredential(credential.into_inner()))
+ }
+}
diff --git a/bindings/wasm/src/credential/revocation/status_list_2021/entry.rs b/bindings/wasm/src/credential/revocation/status_list_2021/entry.rs
new file mode 100644
index 0000000000..85ecb2eafe
--- /dev/null
+++ b/bindings/wasm/src/credential/revocation/status_list_2021/entry.rs
@@ -0,0 +1,72 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use super::WasmStatusPurpose;
+use crate::credential::types::WasmStatus;
+use crate::error::Result;
+use crate::error::WasmResult;
+use identity_iota::core::Url;
+use identity_iota::credential::status_list_2021::StatusList2021Entry;
+use identity_iota::credential::Status;
+use wasm_bindgen::prelude::*;
+
+/// [StatusList2021Entry](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021entry) implementation.
+#[wasm_bindgen(js_name = StatusList2021Entry, inspectable)]
+pub struct WasmStatusList2021Entry(pub(crate) StatusList2021Entry);
+
+#[wasm_bindgen(js_class = StatusList2021Entry)]
+impl WasmStatusList2021Entry {
+ /// Creates a new {@link StatusList2021Entry}.
+ #[wasm_bindgen(constructor)]
+ pub fn new(
+ status_list: &str,
+ purpose: WasmStatusPurpose,
+ index: usize,
+ id: Option,
+ ) -> Result {
+ let status_list = Url::parse(status_list).map_err(|e| JsError::new(&e.to_string()))?;
+ let id = if let Some(id) = id {
+ Some(Url::parse(id).map_err(|e| JsError::new(&e.to_string()))?)
+ } else {
+ None
+ };
+ Ok(Self(StatusList2021Entry::new(status_list, purpose.into(), index, id)))
+ }
+
+ /// Returns this `credentialStatus`'s `id`.
+ #[wasm_bindgen]
+ pub fn id(&self) -> String {
+ self.0.id().to_string()
+ }
+
+ /// Returns the purpose of this entry.
+ #[wasm_bindgen]
+ pub fn purpose(&self) -> WasmStatusPurpose {
+ self.0.purpose().into()
+ }
+
+ /// Returns the index of this entry.
+ #[wasm_bindgen]
+ pub fn index(&self) -> usize {
+ self.0.index()
+ }
+
+ /// Returns the referenced {@link StatusList2021Credential}'s url.
+ #[wasm_bindgen(js_name = "statusListCredential")]
+ pub fn status_list_credential(&self) -> String {
+ self.0.status_list_credential().to_string()
+ }
+
+ /// Downcasts {@link this} to {@link Status}
+ #[wasm_bindgen(js_name = "toStatus")]
+ pub fn to_status(self) -> Result {
+ Ok(
+ JsValue::from_serde(&Status::from(self.0))
+ .wasm_result()?
+ .unchecked_into(),
+ )
+ }
+}
+
+impl_wasm_clone!(WasmStatusList2021Entry, StatusList2021Entry);
+impl_wasm_json!(WasmStatusList2021Entry, StatusList2021Entry);
diff --git a/bindings/wasm/src/credential/revocation/status_list_2021/mod.rs b/bindings/wasm/src/credential/revocation/status_list_2021/mod.rs
new file mode 100644
index 0000000000..62ef3590f1
--- /dev/null
+++ b/bindings/wasm/src/credential/revocation/status_list_2021/mod.rs
@@ -0,0 +1,10 @@
+// Copyright 2020-2023 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+mod credential;
+mod entry;
+mod status_list;
+
+pub use credential::*;
+pub use entry::*;
+pub use status_list::WasmStatusList2021;
diff --git a/bindings/wasm/src/credential/revocation/status_list_2021/status_list.rs b/bindings/wasm/src/credential/revocation/status_list_2021/status_list.rs
new file mode 100644
index 0000000000..8e3cb763d8
--- /dev/null
+++ b/bindings/wasm/src/credential/revocation/status_list_2021/status_list.rs
@@ -0,0 +1,58 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::error::Result;
+use crate::error::WasmResult;
+use identity_iota::credential::status_list_2021::StatusList2021;
+use wasm_bindgen::prelude::*;
+
+/// StatusList2021 data structure as described in [W3C's VC status list 2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/).
+#[wasm_bindgen(js_name = StatusList2021, inspectable)]
+#[derive(Default, Debug)]
+pub struct WasmStatusList2021(pub(crate) StatusList2021);
+
+impl_wasm_clone!(WasmStatusList2021, StatusList2021);
+
+#[wasm_bindgen(js_class = StatusList2021)]
+impl WasmStatusList2021 {
+ /// Creates a new {@link StatusList2021} of `size` entries.
+ #[wasm_bindgen(constructor)]
+ pub fn new(size: Option) -> Result {
+ Ok(Self(match size {
+ Some(size) => StatusList2021::new(size).map_err(|e| JsError::new(&e.to_string()))?,
+ None => StatusList2021::default(),
+ }))
+ }
+
+ /// Returns the number of entries in this {@link StatusList2021}.
+ #[wasm_bindgen]
+ #[allow(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ /// Returns whether the entry at `index` is set.
+ #[wasm_bindgen]
+ pub fn get(&self, index: usize) -> Result {
+ self.0.get(index).wasm_result()
+ }
+
+ /// Sets the value of the `index`-th entry.
+ #[wasm_bindgen]
+ pub fn set(&mut self, index: usize, value: bool) -> Result<()> {
+ self.0.set(index, value).wasm_result()
+ }
+
+ /// Encodes this {@link StatusList2021} into its compressed
+ /// base64 string representation.
+ #[wasm_bindgen(js_name = "intoEncodedStr")]
+ pub fn into_encoded_str(self) -> String {
+ self.0.into_encoded_str()
+ }
+
+ #[wasm_bindgen(js_name = "fromEncodedStr")]
+ /// Attempts to decode a {@link StatusList2021} from a string.
+ pub fn from_encoded_str(s: &str) -> Result {
+ StatusList2021::try_from_encoded_str(s).map(Self).wasm_result()
+ }
+}
diff --git a/bindings/wasm/src/credential/types.rs b/bindings/wasm/src/credential/types.rs
index 4255bb75df..3ca291d9a9 100644
--- a/bindings/wasm/src/credential/types.rs
+++ b/bindings/wasm/src/credential/types.rs
@@ -43,6 +43,9 @@ extern "C" {
#[wasm_bindgen(typescript_type = "Array")]
pub type ArrayCoreDID;
+
+ #[wasm_bindgen(typescript_type = "Status")]
+ pub type WasmStatus;
}
#[wasm_bindgen(typescript_custom_section)]
diff --git a/bindings/wasm/src/error.rs b/bindings/wasm/src/error.rs
index 44fc571946..d7e8dfa3d8 100644
--- a/bindings/wasm/src/error.rs
+++ b/bindings/wasm/src/error.rs
@@ -106,7 +106,9 @@ impl_wasm_error_from!(
identity_iota::verification::Error,
identity_iota::credential::DomainLinkageValidationError,
identity_iota::sd_jwt_payload::Error,
- identity_iota::credential::KeyBindingJwtError
+ identity_iota::credential::KeyBindingJwtError,
+ identity_iota::credential::status_list_2021::StatusListError,
+ identity_iota::credential::status_list_2021::StatusList2021CredentialError
);
// Similar to `impl_wasm_error_from`, but uses the types name instead of requiring/calling Into &'static str
diff --git a/examples/1_advanced/8_status_list_2021.rs b/examples/1_advanced/8_status_list_2021.rs
new file mode 100644
index 0000000000..3f41823bfe
--- /dev/null
+++ b/examples/1_advanced/8_status_list_2021.rs
@@ -0,0 +1,192 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use examples::create_did;
+use examples::random_stronghold_path;
+use examples::MemStorage;
+use examples::API_ENDPOINT;
+use identity_eddsa_verifier::EdDSAJwsVerifier;
+
+use identity_iota::core::FromJson;
+use identity_iota::core::Object;
+
+use identity_iota::core::ToJson;
+use identity_iota::core::Url;
+use identity_iota::credential::status_list_2021::StatusList2021;
+use identity_iota::credential::status_list_2021::StatusList2021Credential;
+use identity_iota::credential::status_list_2021::StatusList2021CredentialBuilder;
+use identity_iota::credential::status_list_2021::StatusList2021Entry;
+use identity_iota::credential::status_list_2021::StatusPurpose;
+
+use identity_iota::credential::Credential;
+use identity_iota::credential::CredentialBuilder;
+
+use identity_iota::credential::FailFast;
+use identity_iota::credential::Issuer;
+use identity_iota::credential::Jwt;
+use identity_iota::credential::JwtCredentialValidationOptions;
+use identity_iota::credential::JwtCredentialValidator;
+use identity_iota::credential::JwtCredentialValidatorUtils;
+use identity_iota::credential::JwtValidationError;
+use identity_iota::credential::Status;
+use identity_iota::credential::StatusCheck;
+use identity_iota::credential::Subject;
+use identity_iota::did::DID;
+use identity_iota::iota::IotaDocument;
+use identity_iota::storage::JwkDocumentExt;
+use identity_iota::storage::JwkMemStore;
+use identity_iota::storage::JwsSignatureOptions;
+use identity_iota::storage::KeyIdMemstore;
+use iota_sdk::client::secret::stronghold::StrongholdSecretManager;
+use iota_sdk::client::secret::SecretManager;
+use iota_sdk::client::Client;
+use iota_sdk::client::Password;
+use iota_sdk::types::block::address::Address;
+use serde_json::json;
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+ // ===========================================================================
+ // Create a Verifiable Credential.
+ // ===========================================================================
+
+ // Create a new client to interact with the IOTA ledger.
+ let client: Client = Client::builder()
+ .with_primary_node(API_ENDPOINT, None)?
+ .finish()
+ .await?;
+
+ let mut secret_manager_issuer: SecretManager = SecretManager::Stronghold(
+ StrongholdSecretManager::builder()
+ .password(Password::from("secure_password_1".to_owned()))
+ .build(random_stronghold_path())?,
+ );
+
+ // Create an identity for the issuer with one verification method `key-1`.
+ let storage_issuer: MemStorage = MemStorage::new(JwkMemStore::new(), KeyIdMemstore::new());
+ let (_, issuer_document, fragment_issuer): (Address, IotaDocument, String) =
+ create_did(&client, &mut secret_manager_issuer, &storage_issuer).await?;
+
+ // Create an identity for the holder, in this case also the subject.
+ let mut secret_manager_alice: SecretManager = SecretManager::Stronghold(
+ StrongholdSecretManager::builder()
+ .password(Password::from("secure_password_2".to_owned()))
+ .build(random_stronghold_path())?,
+ );
+ let storage_alice: MemStorage = MemStorage::new(JwkMemStore::new(), KeyIdMemstore::new());
+ let (_, alice_document, _): (Address, IotaDocument, String) =
+ create_did(&client, &mut secret_manager_alice, &storage_alice).await?;
+
+ // Create a new empty status list. No credentials have been revoked yet.
+ let status_list: StatusList2021 = StatusList2021::default();
+
+ // Create a status list credential so that the status list can be stored anywhere.
+ // The issuer makes this credential available on `http://example.com/credential/status`.
+ // For the purposes of this example, the credential will be used directly without fetching.
+ let status_list_credential: StatusList2021Credential = StatusList2021CredentialBuilder::new(status_list)
+ .purpose(StatusPurpose::Revocation)
+ .subject_id(Url::parse("http://example.com/credential/status")?)
+ .issuer(Issuer::Url(issuer_document.id().to_url().into()))
+ .build()?;
+
+ println!("Status list credential > {status_list_credential:#}");
+
+ // Create a credential subject indicating the degree earned by Alice.
+ let subject: Subject = Subject::from_json_value(json!({
+ "id": alice_document.id().as_str(),
+ "name": "Alice",
+ "degree": {
+ "type": "BachelorDegree",
+ "name": "Bachelor of Science and Arts",
+ },
+ "GPA": "4.0",
+ }))?;
+
+ // Create an unsigned `UniversityDegree` credential for Alice.
+ // The issuer also chooses a unique `StatusList2021` index to be able to revoke it later.
+ let credential_index: usize = 420;
+ let status: Status = StatusList2021Entry::new(
+ status_list_credential.id().cloned().unwrap(),
+ status_list_credential.purpose(),
+ credential_index,
+ None,
+ )
+ .into();
+
+ // Build credential using subject above, status, and issuer.
+ let mut credential: Credential = CredentialBuilder::default()
+ .id(Url::parse("https://example.edu/credentials/3732")?)
+ .issuer(Url::parse(issuer_document.id().as_str())?)
+ .type_("UniversityDegreeCredential")
+ .status(status)
+ .subject(subject)
+ .build()?;
+
+ println!("Credential JSON > {credential:#}");
+
+ let credential_jwt: Jwt = issuer_document
+ .create_credential_jwt(
+ &credential,
+ &storage_issuer,
+ &fragment_issuer,
+ &JwsSignatureOptions::default(),
+ None,
+ )
+ .await?;
+
+ let validator: JwtCredentialValidator =
+ JwtCredentialValidator::with_signature_verifier(EdDSAJwsVerifier::default());
+
+ // The validator has no way of retriving the status list to check for the
+ // revocation of the credential. Let's skip that pass and perform the operation manually.
+ let mut validation_options = JwtCredentialValidationOptions::default();
+ validation_options.status = StatusCheck::SkipUnsupported;
+ // Validate the credential's signature using the issuer's DID Document.
+ validator.validate::<_, Object>(
+ &credential_jwt,
+ &issuer_document,
+ &validation_options,
+ FailFast::FirstError,
+ )?;
+ // Check manually for revocation
+ JwtCredentialValidatorUtils::check_status_with_status_list_2021(
+ &credential,
+ &status_list_credential,
+ StatusCheck::Strict,
+ )?;
+ println!("Credential is valid.");
+
+ let status_list_credential_json = status_list_credential.to_json().unwrap();
+
+ // ===========================================================================
+ // Revocation of the Verifiable Credential.
+ // ===========================================================================
+
+ // At a later time, the issuer university found out that Alice cheated in her final exam.
+ // The issuer will revoke Alice's credential.
+
+ // The issuer retrieves the status list credential.
+ let mut status_list_credential =
+ serde_json::from_str::(status_list_credential_json.as_str()).unwrap();
+
+ // Set the value of the chosen index entry to true to revoke the credential
+ status_list_credential.set_credential_status(&mut credential, credential_index, true)?;
+
+ // validate the credential and check for revocation
+ validator.validate::<_, Object>(
+ &credential_jwt,
+ &issuer_document,
+ &validation_options,
+ FailFast::FirstError,
+ )?;
+ let revocation_result = JwtCredentialValidatorUtils::check_status_with_status_list_2021(
+ &credential,
+ &status_list_credential,
+ StatusCheck::Strict,
+ );
+
+ assert!(revocation_result.is_err_and(|e| matches!(e, JwtValidationError::Revoked)));
+ println!("The credential has been successfully revoked.");
+
+ Ok(())
+}
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 7651e67de9..1a9df88899 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
[dependencies]
anyhow = "1.0.62"
identity_eddsa_verifier = { path = "../identity_eddsa_verifier", default-features = false }
-identity_iota = { path = "../identity_iota", default-features = false, features = ["memstore", "domain-linkage"] }
+identity_iota = { path = "../identity_iota", default-features = false, features = ["memstore", "domain-linkage", "revocation-bitmap", "status-list-2021"] }
identity_stronghold = { path = "../identity_stronghold", default-features = false }
iota-sdk = { version = "1.0", default-features = false, features = ["tls", "client", "stronghold"] }
primitive-types = "0.12.1"
@@ -87,3 +87,7 @@ name = "6_domain_linkage"
[[example]]
path = "1_advanced/7_sd_jwt.rs"
name = "7_sd_jwt"
+
+[[example]]
+path = "1_advanced/8_status_list_2021.rs"
+name = "8_status_list_2021"
diff --git a/examples/README.md b/examples/README.md
index 92ba330adf..2076f8b4b2 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -47,4 +47,5 @@ The following advanced examples are available:
| [4_alias_output_history](./1_advanced/4_alias_output_history.rs) | Demonstrates fetching the history of an Alias Output. |
| [5_custom_resolution](./1_advanced/5_custom_resolution.rs) | Demonstrates how to set up a resolver using custom handlers. |
| [6_domain_linkage](./1_advanced/6_domain_linkage) | Demonstrates how to link a domain and a DID and verify the linkage. |
-| [7_sd_jwt](./1_advanced/7_sd_jwt) | Demonstrates how to create and verify selective disclosure verifiable credentials. |
+| [7_sd_jwt](./1_advanced/7_sd_jwt) | Demonstrates how to create and verify selective disclosure verifiable credentials. |
+| [8_status_list_2021](./1_advanced/8_status_list_2021.rs) | Demonstrates how to revoke a credential using `StatusList2021`. |
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 332e695521..653f9a354c 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -26,6 +26,7 @@ reqwest = { version = "0.11", default-features = false, features = ["default-tls
roaring = { version = "0.10", default-features = false, optional = true }
sd-jwt-payload = { version = "0.1.2", default-features = false, features = ["sha"], optional = true }
serde.workspace = true
+serde-aux = { version = "4.3.1", default-features = false, optional = true }
serde_json.workspace = true
serde_repr = { version = "0.1", default-features = false, optional = true }
strum.workspace = true
@@ -33,6 +34,7 @@ thiserror.workspace = true
url = { version = "2.5", default-features = false }
[dev-dependencies]
+anyhow = "1.0.62"
identity_eddsa_verifier = { version = "=1.0.0", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519", "std", "random"] }
proptest = { version = "1.4.0", default-features = false, features = ["std"] }
@@ -49,6 +51,7 @@ default = ["revocation-bitmap", "validator", "credential", "presentation", "doma
credential = []
presentation = ["credential"]
revocation-bitmap = ["dep:dataurl", "dep:flate2", "dep:roaring"]
+status-list-2021 = ["revocation-bitmap", "dep:serde-aux"]
validator = ["dep:itertools", "dep:serde_repr", "credential", "presentation"]
domain-linkage = ["validator"]
domain-linkage-fetch = ["domain-linkage", "dep:reqwest", "dep:futures"]
diff --git a/identity_credential/src/credential/builder.rs b/identity_credential/src/credential/builder.rs
index 6014578221..f95771c500 100644
--- a/identity_credential/src/credential/builder.rs
+++ b/identity_credential/src/credential/builder.rs
@@ -121,8 +121,8 @@ impl CredentialBuilder {
/// Adds a value to the `credentialStatus` set.
#[must_use]
- pub fn status(mut self, value: Status) -> Self {
- self.status = Some(value);
+ pub fn status(mut self, value: impl Into) -> Self {
+ self.status = Some(value.into());
self
}
diff --git a/identity_credential/src/credential/status.rs b/identity_credential/src/credential/status.rs
index 7496aea10b..bc5d0d3f8d 100644
--- a/identity_credential/src/credential/status.rs
+++ b/identity_credential/src/credential/status.rs
@@ -40,7 +40,7 @@ impl Status {
mod tests {
use identity_core::convert::FromJson;
- use crate::credential::Status;
+ use super::*;
const JSON: &str = include_str!("../../tests/fixtures/status-1.json");
@@ -48,6 +48,6 @@ mod tests {
fn test_from_json() {
let status: Status = Status::from_json(JSON).unwrap();
assert_eq!(status.id.as_str(), "https://example.edu/status/24");
- assert_eq!(status.type_, "CredentialStatusList2017".to_owned());
+ assert_eq!(status.type_, "CredentialStatusList2017");
}
}
diff --git a/identity_credential/src/revocation/mod.rs b/identity_credential/src/revocation/mod.rs
index ca8773309f..6732ff4194 100644
--- a/identity_credential/src/revocation/mod.rs
+++ b/identity_credential/src/revocation/mod.rs
@@ -1,13 +1,14 @@
-// Copyright 2020-2023 IOTA Stiftung
+// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
-//! Contains an implementation of RevocationBitmap2022 for managing credential revocation.
+//! Contains the implementations for all the credential revocation methods that can be used with IOTA's Identity
+//! framework.
-mod bitmap;
-mod document_ext;
mod error;
+mod revocation_bitmap_2022;
+#[cfg(feature = "status-list-2021")]
+pub mod status_list_2021;
-pub use self::bitmap::RevocationBitmap;
-pub use self::document_ext::RevocationDocumentExt;
pub use self::error::RevocationError;
pub use self::error::RevocationResult;
+pub use revocation_bitmap_2022::*;
diff --git a/identity_credential/src/revocation/bitmap.rs b/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
similarity index 99%
rename from identity_credential/src/revocation/bitmap.rs
rename to identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
index 947dc94aaa..6f47db97be 100644
--- a/identity_credential/src/revocation/bitmap.rs
+++ b/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
@@ -14,7 +14,7 @@ use identity_core::convert::BaseEncoding;
use identity_did::DIDUrl;
use roaring::RoaringBitmap;
-use super::error::RevocationError;
+use crate::revocation::error::RevocationError;
use identity_document::service::Service;
use identity_document::service::ServiceEndpoint;
diff --git a/identity_credential/src/revocation/document_ext.rs b/identity_credential/src/revocation/revocation_bitmap_2022/document_ext.rs
similarity index 98%
rename from identity_credential/src/revocation/document_ext.rs
rename to identity_credential/src/revocation/revocation_bitmap_2022/document_ext.rs
index a0318d6774..65e2789f5e 100644
--- a/identity_credential/src/revocation/document_ext.rs
+++ b/identity_credential/src/revocation/revocation_bitmap_2022/document_ext.rs
@@ -7,8 +7,8 @@ use identity_document::service::Service;
use identity_document::utils::DIDUrlQuery;
use identity_document::utils::Queryable;
-use super::RevocationError;
-use super::RevocationResult;
+use crate::revocation::RevocationError;
+use crate::revocation::RevocationResult;
/// Extension trait providing convenience methods to update a `RevocationBitmap2022` service
/// in a [`CoreDocument`](::identity_document::document::CoreDocument).
diff --git a/identity_credential/src/revocation/revocation_bitmap_2022/mod.rs b/identity_credential/src/revocation/revocation_bitmap_2022/mod.rs
new file mode 100644
index 0000000000..609cba5277
--- /dev/null
+++ b/identity_credential/src/revocation/revocation_bitmap_2022/mod.rs
@@ -0,0 +1,8 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+mod bitmap;
+mod document_ext;
+
+pub use bitmap::*;
+pub use document_ext::*;
diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs
new file mode 100644
index 0000000000..3588772e82
--- /dev/null
+++ b/identity_credential/src/revocation/status_list_2021/credential.rs
@@ -0,0 +1,406 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use std::fmt::Display;
+use std::ops::Deref;
+use std::str::FromStr;
+
+use identity_core::common::Context;
+use identity_core::common::OneOrMany;
+use identity_core::common::Timestamp;
+use identity_core::common::Url;
+use serde::Deserialize;
+use serde::Serialize;
+use serde_json::Value;
+use thiserror::Error;
+
+/// The type of a `StatusList2021Credential`.
+pub const CREDENTIAL_TYPE: &str = "StatusList2021Credential";
+const CREDENTIAL_SUBJECT_TYPE: &str = "StatusList2021";
+
+/// [Error](std::error::Error) type that represents the possible errors that can be
+/// encountered when dealing with [`StatusList2021Credential`]s.
+#[derive(Clone, Debug, Error, strum::IntoStaticStr)]
+pub enum StatusList2021CredentialError {
+ /// The provided [`Credential`] has more than one `credentialSubject`.
+ #[error("A StatusList2021Credential may only have one credentialSubject")]
+ MultipleCredentialSubject,
+ /// The provided [`Credential`] has an invalid property.
+ #[error("Invalid property \"{0}\"")]
+ InvalidProperty(&'static str),
+ /// The provided [`Credential`] doesn't have a mandatory property.
+ #[error("Missing property \"{0}\"")]
+ MissingProperty(&'static str),
+ /// Inner status list failures.
+ #[error(transparent)]
+ StatusListError(#[from] StatusListError),
+ /// Missing status list id
+ #[error("Cannot set the status of a credential without a \"credentialSubject.id\".")]
+ Unreferenceable,
+}
+
+use crate::credential::Credential;
+use crate::credential::CredentialBuilder;
+use crate::credential::Issuer;
+use crate::credential::Proof;
+use crate::credential::Subject;
+
+use super::status_list::StatusListError;
+use super::StatusList2021;
+use super::StatusList2021Entry;
+
+/// A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021credential).
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+#[serde(try_from = "Credential", into = "Credential")]
+pub struct StatusList2021Credential {
+ inner: Credential,
+ subject: StatusList2021CredentialSubject,
+}
+
+impl Display for StatusList2021Credential {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", &self.inner)
+ }
+}
+
+impl From for Credential {
+ fn from(value: StatusList2021Credential) -> Self {
+ value.into_inner()
+ }
+}
+
+impl Deref for StatusList2021Credential {
+ type Target = Credential;
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl TryFrom for StatusList2021Credential {
+ type Error = StatusList2021CredentialError;
+ fn try_from(mut credential: Credential) -> Result {
+ let has_right_credential_type = credential.types.contains(&CREDENTIAL_TYPE.to_owned());
+ let subject = StatusList2021CredentialSubject::try_from_credential(&mut credential)?;
+
+ if has_right_credential_type {
+ Ok(Self {
+ inner: credential,
+ subject,
+ })
+ } else {
+ Err(StatusList2021CredentialError::InvalidProperty("type"))
+ }
+ }
+}
+
+impl StatusList2021Credential {
+ /// Returns the inner "raw" [`Credential`].
+ pub fn into_inner(self) -> Credential {
+ let Self { mut inner, subject } = self;
+ inner.credential_subject = OneOrMany::One(subject.into());
+ inner
+ }
+
+ /// Returns the id of this credential.
+ pub fn id(&self) -> Option<&Url> {
+ self.subject.id.as_ref()
+ }
+
+ /// Returns the purpose of this status list.
+ pub fn purpose(&self) -> StatusPurpose {
+ self.subject.status_purpose
+ }
+
+ fn status_list(&self) -> Result {
+ StatusList2021::try_from_encoded_str(&self.subject.encoded_list)
+ }
+
+ /// Sets the credential status of a given [`Credential`],
+ /// mapping it to the `index`-th entry of this [`StatusList2021Credential`].
+ pub fn set_credential_status(
+ &mut self,
+ credential: &mut Credential,
+ index: usize,
+ revoked_or_suspended: bool,
+ ) -> Result {
+ let id = self
+ .id()
+ .cloned()
+ .ok_or(StatusList2021CredentialError::Unreferenceable)?;
+ let entry = StatusList2021Entry::new(id, self.purpose(), index, None);
+
+ self.set_entry(index, revoked_or_suspended)?;
+ credential.credential_status = Some(entry.clone().into());
+
+ Ok(entry)
+ }
+
+ /// Sets the `index`-th entry to `value`
+ pub(crate) fn set_entry(&mut self, index: usize, value: bool) -> Result<(), StatusList2021CredentialError> {
+ let mut status_list = self.status_list()?;
+ status_list.set(index, value)?;
+ self.subject.encoded_list = status_list.into_encoded_str();
+
+ Ok(())
+ }
+
+ /// Returns the status of the `index-th` entry.
+ pub fn entry(&self, index: usize) -> Result {
+ let status_list = self.status_list()?;
+ Ok(match (self.purpose(), status_list.get(index)?) {
+ (StatusPurpose::Revocation, true) => CredentialStatus::Revoked,
+ (StatusPurpose::Suspension, true) => CredentialStatus::Suspended,
+ _ => CredentialStatus::Valid,
+ })
+ }
+}
+
+/// The status of a credential referenced inside a [`StatusList2021Credential`]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum CredentialStatus {
+ /// A revoked credential
+ Revoked,
+ /// A suspended credential
+ Suspended,
+ /// A valid credential
+ Valid,
+}
+
+/// [`StatusList2021Credential`]'s purpose.
+#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum StatusPurpose {
+ /// Used for revocation.
+ #[default]
+ Revocation,
+ /// Used for suspension.
+ Suspension,
+}
+
+impl Display for StatusPurpose {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match self {
+ Self::Revocation => "revocation",
+ Self::Suspension => "suspension",
+ };
+ write!(f, "{s}")
+ }
+}
+
+impl FromStr for StatusPurpose {
+ type Err = ();
+ fn from_str(s: &str) -> Result {
+ match s {
+ "revocation" => Ok(Self::Revocation),
+ "suspension" => Ok(Self::Suspension),
+ _ => Err(()),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+struct StatusList2021CredentialSubject {
+ status_purpose: StatusPurpose,
+ encoded_list: String,
+ id: Option,
+}
+
+impl From for Subject {
+ fn from(value: StatusList2021CredentialSubject) -> Self {
+ let properties = [
+ (
+ "statusPurpose".to_owned(),
+ Value::String(value.status_purpose.to_string()),
+ ),
+ ("type".to_owned(), Value::String(CREDENTIAL_SUBJECT_TYPE.to_owned())),
+ ("encodedList".to_owned(), Value::String(value.encoded_list)),
+ ]
+ .into_iter()
+ .collect();
+
+ if let Some(id) = value.id {
+ Subject::with_id_and_properties(id, properties)
+ } else {
+ Subject::with_properties(properties)
+ }
+ }
+}
+
+impl StatusList2021CredentialSubject {
+ /// Parse a StatusListCredentialSubject out of a credential, without copying.
+ fn try_from_credential(credential: &mut Credential) -> Result {
+ let OneOrMany::One(subject) = &mut credential.credential_subject else {
+ return Err(StatusList2021CredentialError::MultipleCredentialSubject);
+ };
+ if let Some(subject_type) = subject.properties.get("type") {
+ if !subject_type.as_str().is_some_and(|t| t == CREDENTIAL_SUBJECT_TYPE) {
+ return Err(StatusList2021CredentialError::InvalidProperty("credentialSubject.type"));
+ }
+ } else {
+ return Err(StatusList2021CredentialError::MissingProperty("credentialSubject.type"));
+ }
+ let status_purpose = subject
+ .properties
+ .get("statusPurpose")
+ .ok_or(StatusList2021CredentialError::MissingProperty(
+ "credentialSubject.statusPurpose",
+ ))
+ .and_then(|value| {
+ value
+ .as_str()
+ .and_then(|purpose| StatusPurpose::from_str(purpose).ok())
+ .ok_or(StatusList2021CredentialError::InvalidProperty(
+ "credentialSubject.statusPurpose",
+ ))
+ })?;
+ let encoded_list = subject
+ .properties
+ .get_mut("encodedList")
+ .ok_or(StatusList2021CredentialError::MissingProperty(
+ "credentialSubject.encodedList",
+ ))
+ .and_then(|value| {
+ if let Value::String(ref mut s) = value {
+ Ok(s)
+ } else {
+ Err(StatusList2021CredentialError::InvalidProperty(
+ "credentialSubject.encodedList",
+ ))
+ }
+ })
+ .map(std::mem::take)?;
+
+ Ok(StatusList2021CredentialSubject {
+ id: std::mem::take(&mut subject.id),
+ encoded_list,
+ status_purpose,
+ })
+ }
+}
+
+/// Builder type for [`StatusList2021Credential`].
+#[derive(Debug, Default)]
+pub struct StatusList2021CredentialBuilder {
+ inner_builder: CredentialBuilder,
+ credential_subject: StatusList2021CredentialSubject,
+}
+
+impl StatusList2021CredentialBuilder {
+ /// Creates a new [`StatusList2021CredentialBuilder`] from a [`StatusList2021`].
+ pub fn new(status_list: StatusList2021) -> Self {
+ let credential_subject = StatusList2021CredentialSubject {
+ encoded_list: status_list.into_encoded_str(),
+ ..Default::default()
+ };
+ Self {
+ credential_subject,
+ ..Default::default()
+ }
+ }
+
+ /// Sets `credentialSubject.statusPurpose`.
+ pub const fn purpose(mut self, purpose: StatusPurpose) -> Self {
+ self.credential_subject.status_purpose = purpose;
+ self
+ }
+
+ /// Sets `credentialSubject.id`.
+ pub fn subject_id(mut self, id: Url) -> Self {
+ self.credential_subject.id = Some(id);
+ self
+ }
+
+ /// Sets `expirationDate`.
+ pub const fn expiration_date(mut self, time: Timestamp) -> Self {
+ self.inner_builder.expiration_date = Some(time);
+ self
+ }
+
+ /// Sets `issuer`.
+ pub fn issuer(mut self, issuer: Issuer) -> Self {
+ self.inner_builder.issuer = Some(issuer);
+ self
+ }
+
+ /// Adds a `@context` entry.
+ pub fn context(mut self, ctx: Context) -> Self {
+ self.inner_builder.context.push(ctx);
+ self
+ }
+
+ /// Adds a `type` entry.
+ pub fn add_type(mut self, type_: String) -> Self {
+ self.inner_builder.types.push(type_);
+ self
+ }
+
+ /// Adds a credential proof.
+ pub fn proof(mut self, proof: Proof) -> Self {
+ self.inner_builder.proof = Some(proof);
+ self
+ }
+
+ /// Consumes this [`StatusList2021CredentialBuilder`] into a [`StatusList2021Credential`].
+ pub fn build(mut self) -> Result {
+ let id = self.credential_subject.id.clone().map(|mut url| {
+ url.set_fragment(None);
+ url
+ });
+ self.inner_builder.id = id;
+ self
+ .inner_builder
+ .type_(CREDENTIAL_TYPE)
+ .issuance_date(Timestamp::now_utc())
+ .subject(self.credential_subject.clone().into())
+ .build()
+ .map(|credential| StatusList2021Credential {
+ subject: self.credential_subject,
+ inner: credential,
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const STATUS_LIST_2021_CREDENTIAL_SAMPLE: &str = r#"
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials/v1",
+ "https://w3id.org/vc/status-list/2021/v1"
+ ],
+ "id": "https://example.com/credentials/status/3",
+ "type": ["VerifiableCredential", "StatusList2021Credential"],
+ "issuer": "did:example:12345",
+ "issuanceDate": "2021-04-05T14:27:40Z",
+ "credentialSubject": {
+ "id": "https://example.com/status/3#list",
+ "type": "StatusList2021",
+ "statusPurpose": "revocation",
+ "encodedList": "H4sIAAAAAAAAA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA"
+ }
+}
+ "#;
+
+ #[test]
+ fn status_purpose_serialization_works() {
+ assert_eq!(
+ serde_json::to_string(&StatusPurpose::Revocation).ok(),
+ Some(format!("\"{}\"", StatusPurpose::Revocation))
+ );
+ }
+ #[test]
+ fn status_purpose_deserialization_works() {
+ assert_eq!(
+ serde_json::from_str::("\"suspension\"").ok(),
+ Some(StatusPurpose::Suspension),
+ )
+ }
+ #[test]
+ fn status_list_2021_credential_deserialization_works() {
+ let credential = serde_json::from_str::(STATUS_LIST_2021_CREDENTIAL_SAMPLE)
+ .expect("Failed to deserialize");
+ assert_eq!(credential.purpose(), StatusPurpose::Revocation);
+ }
+}
diff --git a/identity_credential/src/revocation/status_list_2021/entry.rs b/identity_credential/src/revocation/status_list_2021/entry.rs
new file mode 100644
index 0000000000..7eecf2f28e
--- /dev/null
+++ b/identity_credential/src/revocation/status_list_2021/entry.rs
@@ -0,0 +1,145 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use identity_core::common::Url;
+use serde::de::Error;
+use serde::de::Visitor;
+use serde::Deserialize;
+use serde::Serialize;
+
+use crate::credential::Status;
+
+use super::credential::StatusPurpose;
+
+const CREDENTIAL_STATUS_TYPE: &str = "StatusList2021Entry";
+
+fn deserialize_status_entry_type<'de, D>(deserializer: D) -> Result
+where
+ D: serde::Deserializer<'de>,
+{
+ struct ExactStrVisitor(&'static str);
+ impl<'a> Visitor<'a> for ExactStrVisitor {
+ type Value = &'static str;
+ fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(formatter, "the exact string \"{}\"", self.0)
+ }
+ fn visit_str(self, str: &str) -> Result {
+ if str == self.0 {
+ Ok(self.0)
+ } else {
+ Err(E::custom(format!("not \"{}\"", self.0)))
+ }
+ }
+ }
+
+ deserializer
+ .deserialize_str(ExactStrVisitor(CREDENTIAL_STATUS_TYPE))
+ .map(ToOwned::to_owned)
+}
+
+/// [StatusList2021Entry](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021entry) implementation.
+#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct StatusList2021Entry {
+ id: Url,
+ #[serde(rename = "type", deserialize_with = "deserialize_status_entry_type")]
+ type_: String,
+ status_purpose: StatusPurpose,
+ #[serde(deserialize_with = "serde_aux::prelude::deserialize_number_from_string")]
+ status_list_index: usize,
+ status_list_credential: Url,
+}
+
+impl TryFrom<&Status> for StatusList2021Entry {
+ type Error = serde_json::Error;
+ fn try_from(status: &Status) -> Result {
+ let json_status = serde_json::to_value(status)?;
+ serde_json::from_value(json_status)
+ }
+}
+
+impl From for Status {
+ fn from(entry: StatusList2021Entry) -> Self {
+ let json_status = serde_json::to_value(entry).unwrap(); // Safety: shouldn't go out of memory
+ serde_json::from_value(json_status).unwrap() // Safety: `StatusList2021Entry` is a credential status
+ }
+}
+
+impl StatusList2021Entry {
+ /// Creates a new [`StatusList2021Entry`].
+ pub fn new(status_list: Url, purpose: StatusPurpose, index: usize, id: Option) -> Self {
+ let id = id.unwrap_or_else(|| {
+ let mut id = status_list.clone();
+ id.set_fragment(None);
+ id
+ });
+
+ Self {
+ id,
+ type_: CREDENTIAL_STATUS_TYPE.to_owned(),
+ status_purpose: purpose,
+ status_list_credential: status_list,
+ status_list_index: index,
+ }
+ }
+
+ /// Returns this `credentialStatus`'s `id`.
+ pub const fn id(&self) -> &Url {
+ &self.id
+ }
+
+ /// Returns the purpose of this entry.
+ pub const fn purpose(&self) -> StatusPurpose {
+ self.status_purpose
+ }
+
+ /// Returns the index of this entry.
+ pub const fn index(&self) -> usize {
+ self.status_list_index
+ }
+
+ /// Returns the referenced [`StatusList2021Credential`]'s [`Url`].
+ pub const fn status_list_credential(&self) -> &Url {
+ &self.status_list_credential
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const STATUS_LIST_ENTRY_SAMPLE: &str = r#"
+{
+ "id": "https://example.com/credentials/status/3#94567",
+ "type": "StatusList2021Entry",
+ "statusPurpose": "revocation",
+ "statusListIndex": "94567",
+ "statusListCredential": "https://example.com/credentials/status/3"
+}"#;
+
+ #[test]
+ fn entry_deserialization_works() {
+ let deserialized =
+ serde_json::from_str::(STATUS_LIST_ENTRY_SAMPLE).expect("Failed to deserialize");
+ let status = StatusList2021Entry::new(
+ Url::parse("https://example.com/credentials/status/3").unwrap(),
+ StatusPurpose::Revocation,
+ 94567,
+ Url::parse("https://example.com/credentials/status/3#94567").ok(),
+ );
+ assert_eq!(status, deserialized);
+ }
+
+ #[test]
+ #[should_panic]
+ fn deserializing_wrong_status_type_fails() {
+ let status = serde_json::json!({
+ "id": "https://example.com/credentials/status/3#94567",
+ "type": "Whatever2024",
+ "statusPurpose": "revocation",
+ "statusListIndex": "94567",
+ "statusListCredential": "https://example.com/credentials/status/3"
+ });
+ serde_json::from_value::(status).expect("wrong type");
+ }
+}
diff --git a/identity_credential/src/revocation/status_list_2021/mod.rs b/identity_credential/src/revocation/status_list_2021/mod.rs
new file mode 100644
index 0000000000..39c4dfbcf4
--- /dev/null
+++ b/identity_credential/src/revocation/status_list_2021/mod.rs
@@ -0,0 +1,13 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+//! Implementation of [StatusList2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/).
+
+/// Implementation of [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#statuslist2021credential).
+mod credential;
+mod entry;
+mod status_list;
+
+pub use credential::*;
+pub use entry::*;
+pub use status_list::*;
diff --git a/identity_credential/src/revocation/status_list_2021/status_list.rs b/identity_credential/src/revocation/status_list_2021/status_list.rs
new file mode 100644
index 0000000000..30ad6a8582
--- /dev/null
+++ b/identity_credential/src/revocation/status_list_2021/status_list.rs
@@ -0,0 +1,174 @@
+// Copyright 2020-2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+use flate2::read::GzDecoder;
+use flate2::write::GzEncoder;
+use flate2::Compression;
+use identity_core::convert::Base;
+use identity_core::convert::BaseEncoding;
+use std::io::Write;
+use thiserror::Error;
+
+const MINIMUM_LIST_SIZE: usize = 16 * 1024 * 8;
+
+/// [`std::error::Error`] type for [`StatusList2021`]'s operations.
+#[derive(Debug, Error, PartialEq, Eq, Clone, strum::IntoStaticStr)]
+pub enum StatusListError {
+ /// Requested entry is not in the list.
+ #[error("The requested entry is not in the list.")]
+ IndexOutOfBounds,
+ /// Improperly encoded status list.
+ #[error("\"{0}\" is not a valid encoded status list.")]
+ InvalidEncoding(String),
+ /// Invalid list size
+ #[error("A StatusList2021 must have at least {MINIMUM_LIST_SIZE} entries.")]
+ InvalidListSize,
+}
+
+/// StatusList2021 data structure as described in [W3C's VC status list 2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/).
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct StatusList2021(Box<[u8]>);
+
+impl Default for StatusList2021 {
+ fn default() -> Self {
+ StatusList2021::new(MINIMUM_LIST_SIZE).unwrap()
+ }
+}
+
+impl StatusList2021 {
+ /// Returns a new zero-filled [`StatusList2021`] that can hold `num_entries` credential statuses.
+ ///
+ /// ## Notes:
+ /// - The actual length of the list will be rounded up to the closest multiple of 8 to accomodate for byte sizes.
+ /// - `num_entries` must be at least 131,072 which corresponds to a size of 16KB.
+ pub fn new(num_entries: usize) -> Result {
+ if num_entries < MINIMUM_LIST_SIZE {
+ return Err(StatusListError::InvalidListSize);
+ }
+
+ let size = num_entries / 8 + (num_entries % 8 != 0) as usize;
+ let store = vec![0; size];
+
+ Ok(StatusList2021(store.into_boxed_slice()))
+ }
+
+ /// Returns the number of entries.
+ #[allow(clippy::len_without_is_empty)]
+ pub const fn len(&self) -> usize {
+ self.0.len() * 8
+ }
+
+ /// Returns the status of the entry at `index` without bound checking.
+ /// ## Panic:
+ /// * if `index` is greater than or equal to `self.len()`.
+ const fn get_unchecked(&self, index: usize) -> bool {
+ let (i, offset) = Self::entry_index_to_store_index(index);
+ self.0[i] & (0b1000_0000 >> offset) != 0
+ }
+
+ /// Sets the status of the `index`-th entry to `value`.
+ ///
+ /// ## Panic:
+ /// * if `index` is greater than or equal to `self.len()`.
+ fn set_unchecked(&mut self, index: usize, value: bool) {
+ let (i, offset) = Self::entry_index_to_store_index(index);
+ if value {
+ self.0[i] |= 0b1000_0000 >> offset
+ } else {
+ self.0[i] &= 0b0111_1111 >> offset
+ }
+ }
+
+ /// Returns the status of the `index`-th entry, if it exists.
+ pub fn get(&self, index: usize) -> Result {
+ (index < self.len())
+ .then_some(self.get_unchecked(index))
+ .ok_or(StatusListError::IndexOutOfBounds)
+ }
+
+ /// Sets the status of the `index`-th entry to `value`.
+ pub fn set(&mut self, index: usize, value: bool) -> Result<(), StatusListError> {
+ if index < self.len() {
+ self.set_unchecked(index, value);
+ Ok(())
+ } else {
+ Err(StatusListError::IndexOutOfBounds)
+ }
+ }
+
+ /// Attempts to parse a [`StatusList2021`] from a string, following the
+ /// [StatusList2021 expansion algorithm](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#bitstring-expansion-algorithm).
+ pub fn try_from_encoded_str(s: &str) -> Result {
+ let compressed_status_list =
+ BaseEncoding::decode(s, Base::Base64).or(Err(StatusListError::InvalidEncoding(s.to_owned())))?;
+ let status_list = {
+ use std::io::Read;
+
+ let mut decompressor = GzDecoder::new(&compressed_status_list[..]);
+ let mut status_list = vec![];
+ decompressor
+ .read_to_end(&mut status_list)
+ .or(Err(StatusListError::InvalidEncoding(s.to_owned())))?;
+
+ StatusList2021(status_list.into_boxed_slice())
+ };
+
+ Ok(status_list)
+ }
+
+ /// Encode this [`StatusList2021`] into its string representation following
+ /// [StatusList2021 generation algorithm](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#bitstring-generation-algorithm).
+ pub fn into_encoded_str(self) -> String {
+ let compressed_status_list = {
+ let mut compressor = GzEncoder::new(vec![], Compression::best());
+ compressor.write_all(&self.0).unwrap();
+ compressor.finish().unwrap()
+ };
+
+ BaseEncoding::encode(&compressed_status_list[..], Base::Base64)
+ }
+
+ /// Returns the byte location and the bit location within it.
+ const fn entry_index_to_store_index(index: usize) -> (usize, usize) {
+ (index / 8, index % 8)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn default_status_list() {
+ let mut status_list = StatusList2021::default();
+ status_list.set(131071, true).unwrap();
+ assert!(status_list.get(131071).unwrap());
+ assert_eq!(status_list.set(131072, true), Err(StatusListError::IndexOutOfBounds));
+ }
+
+ #[test]
+ fn status_list_too_short_fails() {
+ assert_eq!(StatusList2021::new(100), Err(StatusListError::InvalidListSize));
+ }
+
+ #[test]
+ fn status_list_entry_access() {
+ let mut status_list = StatusList2021::default();
+ status_list.set(42, true).unwrap();
+ assert!(status_list.get(42).unwrap());
+
+ status_list.set(42, false).unwrap();
+ assert_eq!(status_list, StatusList2021::default());
+ }
+
+ #[test]
+ fn status_list_encode_decode() {
+ let mut status_list = StatusList2021::default();
+ status_list.set(42, true).unwrap();
+ status_list.set(420, true).unwrap();
+ status_list.set(4200, true).unwrap();
+ let encoded = status_list.clone().into_encoded_str();
+ let decoded = StatusList2021::try_from_encoded_str(&encoded).unwrap();
+ assert_eq!(decoded, status_list);
+ }
+}
diff --git a/identity_credential/src/validator/jwt_credential_validation/error.rs b/identity_credential/src/validator/jwt_credential_validation/error.rs
index c418db9676..073ffe303c 100644
--- a/identity_credential/src/validator/jwt_credential_validation/error.rs
+++ b/identity_credential/src/validator/jwt_credential_validation/error.rs
@@ -101,6 +101,9 @@ pub enum JwtValidationError {
/// Indicates that the credential has been revoked.
#[error("credential has been revoked")]
Revoked,
+ /// Indicates that the credential has been suspended.
+ #[error("credential has been suspended")]
+ Suspended,
}
/// Specifies whether an error is related to a credential issuer or the presentation holder.
diff --git a/identity_credential/src/validator/jwt_credential_validation/jwt_credential_validator_utils.rs b/identity_credential/src/validator/jwt_credential_validation/jwt_credential_validator_utils.rs
index 83e21ba3a6..e7a43bcdab 100644
--- a/identity_credential/src/validator/jwt_credential_validation/jwt_credential_validator_utils.rs
+++ b/identity_credential/src/validator/jwt_credential_validation/jwt_credential_validator_utils.rs
@@ -1,4 +1,4 @@
-// Copyright 2020-2023 IOTA Stiftung
+// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
use std::str::FromStr;
@@ -15,6 +15,8 @@ use super::SignerContext;
use crate::credential::Credential;
use crate::credential::CredentialJwtClaims;
use crate::credential::Jwt;
+#[cfg(feature = "status-list-2021")]
+use crate::revocation::status_list_2021::StatusList2021Credential;
use crate::validator::SubjectHolderRelationship;
/// Utility functions for verifying JWT credentials.
@@ -82,6 +84,46 @@ impl JwtCredentialValidatorUtils {
.ok_or(JwtValidationError::SubjectHolderRelationship)
}
+ /// Checks whether the status specified in `credentialStatus` has been set by the issuer.
+ ///
+ /// Only supports `StatusList2021`.
+ #[cfg(feature = "status-list-2021")]
+ pub fn check_status_with_status_list_2021(
+ credential: &Credential,
+ status_list_credential: &StatusList2021Credential,
+ status_check: crate::validator::StatusCheck,
+ ) -> ValidationUnitResult {
+ use crate::revocation::status_list_2021::CredentialStatus;
+ use crate::revocation::status_list_2021::StatusList2021Entry;
+
+ if status_check == crate::validator::StatusCheck::SkipAll {
+ return Ok(());
+ }
+
+ match &credential.credential_status {
+ None => Ok(()),
+ Some(status) => {
+ let status = StatusList2021Entry::try_from(status)
+ .map_err(|e| JwtValidationError::InvalidStatus(crate::Error::InvalidStatus(e.to_string())))?;
+ if Some(status.status_list_credential()) == status_list_credential.id.as_ref()
+ && status.purpose() == status_list_credential.purpose()
+ {
+ let entry_status = status_list_credential
+ .entry(status.index())
+ .map_err(|e| JwtValidationError::InvalidStatus(crate::Error::InvalidStatus(e.to_string())))?;
+ match entry_status {
+ CredentialStatus::Revoked => Err(JwtValidationError::Revoked),
+ CredentialStatus::Suspended => Err(JwtValidationError::Suspended),
+ CredentialStatus::Valid => Ok(()),
+ }
+ } else {
+ Err(JwtValidationError::InvalidStatus(crate::Error::InvalidStatus(
+ "The given statusListCredential doesn't match the credential's status".to_owned(),
+ )))
+ }
+ }
+ }
+ }
/// Checks whether the credential status has been revoked.
///
/// Only supports `RevocationBitmap2022`.
diff --git a/identity_iota/Cargo.toml b/identity_iota/Cargo.toml
index 38d406989e..52a9e2b8d3 100644
--- a/identity_iota/Cargo.toml
+++ b/identity_iota/Cargo.toml
@@ -43,6 +43,9 @@ revocation-bitmap = [
"identity_resolver?/revocation-bitmap",
]
+# Enables revocation with `StatusList2021`.
+status-list-2021 = ["revocation-bitmap", "identity_credential/status-list-2021"]
+
# Enables support for the `Resolver`.
resolver = ["dep:identity_resolver"]
From 7ce7840dffaede9664ab6b53b75a15ec615e21c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Thu, 25 Jan 2024 09:17:10 +0100
Subject: [PATCH 03/23] Split cargo release command (#1279)
---
.github/actions/publish/publish-rust/action.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/actions/publish/publish-rust/action.yml b/.github/actions/publish/publish-rust/action.yml
index 3143267414..4e6f8bcadb 100644
--- a/.github/actions/publish/publish-rust/action.yml
+++ b/.github/actions/publish/publish-rust/action.yml
@@ -29,4 +29,6 @@ runs:
echo "dry-run: '${{ inputs.dry-run }}'"
echo "version: '${{ inputs.version }}'"
cargo login ${{ inputs.crates-token }}
- cargo release --workspace --isolated --no-push --no-tag --verbose $(if [ "${{ inputs.dry-run }}" = "false" ]; then echo --execute --no-confirm; fi) ${{ inputs.version }}
+ cargo release config
+ cargo release version --verbose --execute --no-confirm ${{ inputs.version }}
+ cargo release publish --verbose $(if [ "${{ inputs.dry-run }}" = "false" ]; then echo --execute --no-confirm; fi)
From e67287ac4026a102303eb19d928e8f9341587cec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Thu, 25 Jan 2024 14:38:43 +0100
Subject: [PATCH 04/23] Remove local versions from Wasm crate (#1280)
---
.github/actions/release/bump-versions/action.yml | 7 -------
bindings/wasm/Cargo.toml | 3 +--
2 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/.github/actions/release/bump-versions/action.yml b/.github/actions/release/bump-versions/action.yml
index 7d153ccab6..cf1cf65781 100644
--- a/.github/actions/release/bump-versions/action.yml
+++ b/.github/actions/release/bump-versions/action.yml
@@ -47,13 +47,6 @@ runs:
run: |
cargo workspaces version --force "*" --no-git-commit --exact custom ${{ inputs.version }} -y -a
- - name: Replace identity_iota version in Wasm bindings
- shell: bash
- if: ${{inputs.release-target == 'rust'}}
- working-directory: bindings/wasm
- run: |
- cargo add identity_iota --path=../../identity_iota
-
- name: Set up Node.js
uses: actions/setup-node@v2
if: ${{inputs.release-target == 'wasm'}}
diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml
index 09f0d7aa43..0e67337d41 100644
--- a/bindings/wasm/Cargo.toml
+++ b/bindings/wasm/Cargo.toml
@@ -19,7 +19,7 @@ crate-type = ["cdylib", "rlib"]
async-trait = { version = "0.1", default-features = false }
console_error_panic_hook = { version = "0.1" }
futures = { version = "0.3" }
-identity_eddsa_verifier = { version = "1.0.0", path = "../../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_eddsa_verifier = { path = "../../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
js-sys = { version = "0.3.61" }
proc_typescript = { version = "0.1.0", path = "./proc_typescript" }
serde = { version = "1.0", features = ["derive"] }
@@ -31,7 +31,6 @@ wasm-bindgen = { version = "0.2.85", features = ["serde-serialize"] }
wasm-bindgen-futures = { version = "0.4", default-features = false }
[dependencies.identity_iota]
-version = "1.0.0"
path = "../../identity_iota"
default-features = false
features = ["client", "revocation-bitmap", "resolver", "domain-linkage", "sd-jwt", "status-list-2021"]
From 692fbea625a2b9569883f3db5c19250d9bd31ce8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 25 Jan 2024 15:30:59 +0100
Subject: [PATCH 05/23] changelog and versions (#1281)
---
examples/Cargo.toml | 2 +-
identity_core/Cargo.toml | 2 +-
identity_credential/Cargo.toml | 12 ++++++------
identity_did/Cargo.toml | 4 ++--
identity_document/Cargo.toml | 8 ++++----
identity_eddsa_verifier/Cargo.toml | 4 ++--
identity_iota/Cargo.toml | 18 +++++++++---------
identity_iota_core/Cargo.toml | 12 ++++++------
identity_jose/Cargo.toml | 4 ++--
identity_resolver/Cargo.toml | 12 ++++++------
identity_storage/Cargo.toml | 18 +++++++++---------
identity_stronghold/Cargo.toml | 8 ++++----
identity_verification/Cargo.toml | 8 ++++----
13 files changed, 56 insertions(+), 56 deletions(-)
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 1a9df88899..3a0974122f 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "examples"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors = ["IOTA Stiftung"]
edition = "2021"
publish = false
diff --git a/identity_core/Cargo.toml b/identity_core/Cargo.toml
index 984df9f3dd..284cca081d 100644
--- a/identity_core/Cargo.toml
+++ b/identity_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_core"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 653f9a354c..436ed5fbfb 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_credential"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors = ["IOTA Stiftung"]
edition = "2021"
homepage.workspace = true
@@ -15,10 +15,10 @@ description = "An implementation of the Verifiable Credentials standard."
dataurl = { version = "0.1.2", default-features = false, optional = true }
flate2 = { version = "1.0.28", default-features = false, features = ["rust_backend"], optional = true }
futures = { version = "0.3", default-features = false, optional = true }
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
-identity_did = { version = "=1.0.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.0.0", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
itertools = { version = "0.11", default-features = false, features = ["use_std"], optional = true }
once_cell = { version = "1.18", default-features = false, features = ["std"] }
@@ -35,7 +35,7 @@ url = { version = "2.5", default-features = false }
[dev-dependencies]
anyhow = "1.0.62"
-identity_eddsa_verifier = { version = "=1.0.0", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_eddsa_verifier = { version = "=1.1.0-alpha.1", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519", "std", "random"] }
proptest = { version = "1.4.0", default-features = false, features = ["std"] }
tokio = { version = "1.35.0", default-features = false, features = ["rt-multi-thread", "macros"] }
diff --git a/identity_did/Cargo.toml b/identity_did/Cargo.toml
index 21cc9508f1..9492997598 100644
--- a/identity_did/Cargo.toml
+++ b/identity_did/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_did"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition = "2021"
homepage.workspace = true
@@ -13,7 +13,7 @@ description = "Agnostic implementation of the Decentralized Identifiers (DID) st
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
form_urlencoded = { version = "1.2.0", default-features = false, features = ["alloc"] }
-identity_core = { version = "=1.0.0", path = "../identity_core" }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core" }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
diff --git a/identity_document/Cargo.toml b/identity_document/Cargo.toml
index 6b1bbdf3b0..e44b8ce02a 100644
--- a/identity_document/Cargo.toml
+++ b/identity_document/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_document"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,9 +13,9 @@ description = "Method-agnostic implementation of the Decentralized Identifiers (
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
-identity_core = { version = "=1.0.0", path = "../identity_core" }
-identity_did = { version = "=1.0.0", path = "../identity_did" }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core" }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did" }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
serde.workspace = true
strum.workspace = true
diff --git a/identity_eddsa_verifier/Cargo.toml b/identity_eddsa_verifier/Cargo.toml
index 39f6c724bf..d8271444eb 100644
--- a/identity_eddsa_verifier/Cargo.toml
+++ b/identity_eddsa_verifier/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_eddsa_verifier"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "JWS EdDSA signature verification for IOTA Identity"
[dependencies]
-identity_jose = { version = "=1.0.0", path = "../identity_jose", default-features = false }
+identity_jose = { version = "=1.1.0-alpha.1", path = "../identity_jose", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std"] }
[features]
diff --git a/identity_iota/Cargo.toml b/identity_iota/Cargo.toml
index 52a9e2b8d3..d519fb6917 100644
--- a/identity_iota/Cargo.toml
+++ b/identity_iota/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,14 +12,14 @@ rust-version.workspace = true
description = "Framework for Self-Sovereign Identity with IOTA DID."
[dependencies]
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.0.0", path = "../identity_credential", features = ["validator"], default-features = false }
-identity_did = { version = "=1.0.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.0.0", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.0.0", path = "../identity_iota_core", default-features = false }
-identity_resolver = { version = "=1.0.0", path = "../identity_resolver", default-features = false, optional = true }
-identity_storage = { version = "=1.0.0", path = "../identity_storage", default-features = false, features = ["iota-document"] }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", features = ["validator"], default-features = false }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.0-alpha.1", path = "../identity_iota_core", default-features = false }
+identity_resolver = { version = "=1.1.0-alpha.1", path = "../identity_resolver", default-features = false, optional = true }
+identity_storage = { version = "=1.1.0-alpha.1", path = "../identity_storage", default-features = false, features = ["iota-document"] }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
[dev-dependencies]
anyhow = "1.0.64"
diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml
index 5903c39d6e..3f7e9fbf12 100644
--- a/identity_iota_core/Cargo.toml
+++ b/identity_iota_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota_core"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,11 +14,11 @@ description = "An IOTA Ledger integration for the IOTA DID Method."
[dependencies]
async-trait = { version = "0.1.56", default-features = false, optional = true }
futures = { version = "0.3", default-features = false }
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.0.0", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.0.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.0.0", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
iota-sdk = { version = "1.0.2", default-features = false, features = ["serde", "std"], optional = true }
num-derive = { version = "0.4", default-features = false }
num-traits = { version = "0.2", default-features = false, features = ["std"] }
diff --git a/identity_jose/Cargo.toml b/identity_jose/Cargo.toml
index b00479ba81..748b481910 100644
--- a/identity_jose/Cargo.toml
+++ b/identity_jose/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_jose"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "A library for JOSE (JSON Object Signing and Encryption)"
[dependencies]
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std", "sha"] }
serde.workspace = true
serde_json = { version = "1.0", default-features = false, features = ["std"] }
diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml
index c5edc05a70..76679caa5f 100644
--- a/identity_resolver/Cargo.toml
+++ b/identity_resolver/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_resolver"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -15,16 +15,16 @@ description = "DID Resolution utilities for the identity.rs library."
# This is currently necessary for the ResolutionHandler trait. This can be made an optional dependency if alternative ways of attaching handlers are introduced.
async-trait = { version = "0.1", default-features = false }
futures = { version = "0.3" }
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.0.0", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.0.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.0.0", path = "../identity_document", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
serde = { version = "1.0", default-features = false, features = ["std", "derive"] }
strum.workspace = true
thiserror = { version = "1.0", default-features = false }
[dependencies.identity_iota_core]
-version = "=1.0.0"
+version = "=1.1.0-alpha.1"
path = "../identity_iota_core"
default-features = false
features = ["send-sync-client-ext", "iota-client"]
diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml
index 795721da5a..ca2cc6eb8d 100644
--- a/identity_storage/Cargo.toml
+++ b/identity_storage/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_storage"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,12 +14,12 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
futures = { version = "0.3.27", default-features = false, features = ["async-await"] }
-identity_core = { version = "=1.0.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.0.0", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
-identity_did = { version = "=1.0.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.0.0", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.0.0", path = "../identity_iota_core", default-features = false, optional = true }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default_features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.0-alpha.1", path = "../identity_iota_core", default-features = false, optional = true }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"], optional = true }
rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"], optional = true }
seahash = { version = "4.1.0", default_features = false }
@@ -29,8 +29,8 @@ thiserror.workspace = true
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync"], optional = true }
[dev-dependencies]
-identity_credential = { version = "=1.0.0", path = "../identity_credential", features = ["revocation-bitmap"] }
-identity_eddsa_verifier = { version = "=1.0.0", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", features = ["revocation-bitmap"] }
+identity_eddsa_verifier = { version = "=1.1.0-alpha.1", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
once_cell = { version = "1.18", default-features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
diff --git a/identity_stronghold/Cargo.toml b/identity_stronghold/Cargo.toml
index 596617ec21..02342b6f51 100644
--- a/identity_stronghold/Cargo.toml
+++ b/identity_stronghold/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_stronghold"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,8 +13,8 @@ description = "Secure JWK storage with Stronghold for IOTA Identity"
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
-identity_storage = { version = "=1.0.0", path = "../identity_storage", default_features = false }
-identity_verification = { version = "=1.0.0", path = "../identity_verification", default_features = false }
+identity_storage = { version = "=1.1.0-alpha.1", path = "../identity_storage", default_features = false }
+identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"] }
iota-sdk = { version = "1.0.2", default-features = false, features = ["client", "stronghold"] }
iota_stronghold = { version = "2.0", default-features = false }
@@ -23,7 +23,7 @@ tokio = { version = "1.29.0", default-features = false, features = ["macros", "s
zeroize = { version = "1.6.0", default_features = false }
[dev-dependencies]
-identity_did = { version = "=1.0.0", path = "../identity_did", default_features = false }
+identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default_features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
[features]
diff --git a/identity_verification/Cargo.toml b/identity_verification/Cargo.toml
index 15da686d4e..2367aeed14 100644
--- a/identity_verification/Cargo.toml
+++ b/identity_verification/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_verification"
-version = "1.0.0"
+version = "1.1.0-alpha.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -9,9 +9,9 @@ rust-version.workspace = true
description = "Verification data types and functionality for identity.rs"
[dependencies]
-identity_core = { version = "=1.0.0", path = "./../identity_core", default-features = false }
-identity_did = { version = "=1.0.0", path = "./../identity_did", default-features = false }
-identity_jose = { version = "=1.0.0", path = "./../identity_jose", default-features = false }
+identity_core = { version = "=1.1.0-alpha.1", path = "./../identity_core", default-features = false }
+identity_did = { version = "=1.1.0-alpha.1", path = "./../identity_did", default-features = false }
+identity_jose = { version = "=1.1.0-alpha.1", path = "./../identity_jose", default-features = false }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
From 2252c8bb1ccd2f9f40272bd8f89ab21192f9f15d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Thu, 25 Jan 2024 17:02:42 +0100
Subject: [PATCH 06/23] remove dev dependency version (#1282)
---
identity_credential/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 436ed5fbfb..22fbb4b5da 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -35,7 +35,7 @@ url = { version = "2.5", default-features = false }
[dev-dependencies]
anyhow = "1.0.62"
-identity_eddsa_verifier = { version = "=1.1.0-alpha.1", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_eddsa_verifier = { path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519", "std", "random"] }
proptest = { version = "1.4.0", default-features = false, features = ["std"] }
tokio = { version = "1.35.0", default-features = false, features = ["rt-multi-thread", "macros"] }
From 5e8953efdbf222931584e59ff3944e71e2b0bd29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Fri, 26 Jan 2024 11:59:08 +0100
Subject: [PATCH 07/23] Add Rust readme test (#1241)
---
.github/workflows/build-and-test.yml | 8 ++++++++
README.md | 26 ++++++++++++++++++++++++++
bindings/wasm/package.json | 1 +
bindings/wasm/tests/txm_readme.js | 22 ++++++++++++++++++----
bindings/wasm/tests/txm_readme_rust.js | 21 +++++++++++++++++++++
5 files changed, 74 insertions(+), 4 deletions(-)
create mode 100644 bindings/wasm/tests/txm_readme_rust.js
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 47e0e622d0..27ded3b745 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -140,6 +140,14 @@ jobs:
parallel -k -j 4 --retries 3 --joblog report.log ./target/release/examples/{}
cat report.log
+ - name: Run Rust Readme examples
+ # run examples only on ubuntu for now
+ if: matrix.os == 'ubuntu-latest'
+ run: |
+ cd bindings/wasm
+ npm ci
+ npm run test:readme:rust
+
- name: Tear down private tangle
if: matrix.os == 'ubuntu-latest' && always()
uses: './.github/actions/private-tangle/tear-down'
diff --git a/README.md b/README.md
index 564817faa8..558e53f7e2 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,17 @@ See the [instructions](https://github.com/iotaledger/hornet/tree/develop/private
_Cargo.toml_
+
+
+
```toml
[package]
name = "iota_identity_example"
@@ -77,10 +88,25 @@ edition = "2021"
identity_iota = {version = "1.0.0", features = ["memstore"]}
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
+anyhow = "1.0.62"
+rand = "0.8.5"
```
_main.__rs_
+
+
+
+
```rust,no_run
use identity_iota::core::ToJson;
use identity_iota::iota::IotaClientExt;
diff --git a/bindings/wasm/package.json b/bindings/wasm/package.json
index 7f00d683d8..842945fe79 100644
--- a/bindings/wasm/package.json
+++ b/bindings/wasm/package.json
@@ -25,6 +25,7 @@
"test:browser:parallel": "npm run build:examples:web && cypress-parallel -s test:browser -t 4 -d cypress/e2e -a '\"--quiet\"'",
"test:browser": "cypress run --headless",
"test:readme": "mocha ./tests/txm_readme.js --retries 3 --timeout 180000 --exit",
+ "test:readme:rust": "mocha ./tests/txm_readme_rust.js --retries 3 --timeout 360000 --exit",
"test:unit:node": "ts-mocha -p tsconfig.node.json ./tests/*.ts --parallel --exit",
"cypress": "cypress open",
"fmt": "dprint fmt"
diff --git a/bindings/wasm/tests/txm_readme.js b/bindings/wasm/tests/txm_readme.js
index 0f1ed5d0c0..2a388c2dba 100644
--- a/bindings/wasm/tests/txm_readme.js
+++ b/bindings/wasm/tests/txm_readme.js
@@ -1,7 +1,21 @@
-const { execSync } = require("child_process");
+const assert = require("assert");
+const spawn = require("child_process").spawn;
-describe("Test TXM", function() {
- it("README examples pass", async () => {
- execSync("txm README.md");
+describe("Test TXM", () => {
+ before((done) => {
+ let process = spawn("txm", ["README.md"]);
+ process.stdout.on("data", function(data) {
+ console.log(data.toString());
+ });
+ process.stderr.on("data", function(data) {
+ console.log(data.toString());
+ });
+ process.on("exit", (code) => {
+ exitCode = code;
+ done();
+ });
+ });
+ it("exit code should be zero", () => {
+ assert.equal(exitCode, 0);
});
});
diff --git a/bindings/wasm/tests/txm_readme_rust.js b/bindings/wasm/tests/txm_readme_rust.js
new file mode 100644
index 0000000000..d024653fe2
--- /dev/null
+++ b/bindings/wasm/tests/txm_readme_rust.js
@@ -0,0 +1,21 @@
+const assert = require("assert");
+const spawn = require("child_process").spawn;
+
+describe("Test TXM", () => {
+ before((done) => {
+ let process = spawn("txm", ["../../README.md"]);
+ process.stdout.on("data", function(data) {
+ console.log(data.toString());
+ });
+ process.stderr.on("data", function(data) {
+ console.log(data.toString());
+ });
+ process.on("exit", (code) => {
+ exitCode = code;
+ done();
+ });
+ });
+ it("exit code should be zero", () => {
+ assert.equal(exitCode, 0);
+ });
+});
From a9295109dcbfcb0b61a5cac909022a2cfd0b1993 Mon Sep 17 00:00:00 2001
From: Enrico Marconi <31142849+UMR1352@users.noreply.github.com>
Date: Fri, 26 Jan 2024 15:33:50 +0100
Subject: [PATCH 08/23] Credentials cannot be unrevoked with StatusList2021
(#1284)
* credentials cannot be unrevoked with StatusList2021
* Add test for unsuspension of credentials
* fmt clippy
* unrevoking valid credential does nothing
* change error name, fix test
* Update identity_credential/src/revocation/status_list_2021/credential.rs
Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
* Update identity_credential/src/revocation/status_list_2021/credential.rs
Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
---------
Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
---
.../revocation/status_list_2021/credential.rs | 47 ++++++++++++++++++-
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs
index 3588772e82..e3f0875216 100644
--- a/identity_credential/src/revocation/status_list_2021/credential.rs
+++ b/identity_credential/src/revocation/status_list_2021/credential.rs
@@ -20,7 +20,7 @@ const CREDENTIAL_SUBJECT_TYPE: &str = "StatusList2021";
/// [Error](std::error::Error) type that represents the possible errors that can be
/// encountered when dealing with [`StatusList2021Credential`]s.
-#[derive(Clone, Debug, Error, strum::IntoStaticStr)]
+#[derive(Clone, Debug, Error, strum::IntoStaticStr, PartialEq, Eq)]
pub enum StatusList2021CredentialError {
/// The provided [`Credential`] has more than one `credentialSubject`.
#[error("A StatusList2021Credential may only have one credentialSubject")]
@@ -34,9 +34,12 @@ pub enum StatusList2021CredentialError {
/// Inner status list failures.
#[error(transparent)]
StatusListError(#[from] StatusListError),
- /// Missing status list id
+ /// Missing status list id.
#[error("Cannot set the status of a credential without a \"credentialSubject.id\".")]
Unreferenceable,
+ /// Credentials cannot be unrevoked.
+ #[error("A previously revoked credential cannot be unrevoked.")]
+ UnreversibleRevocation,
}
use crate::credential::Credential;
@@ -117,6 +120,11 @@ impl StatusList2021Credential {
/// Sets the credential status of a given [`Credential`],
/// mapping it to the `index`-th entry of this [`StatusList2021Credential`].
+ ///
+ /// ## Note:
+ /// - A revoked credential cannot ever be unrevoked and will lead to a
+ /// [`StatusList2021CredentialError::UnreversibleRevocation`].
+ /// - Trying to set `revoked_or_suspended` to `false` for an already valid credential will have no impact.
pub fn set_credential_status(
&mut self,
credential: &mut Credential,
@@ -138,6 +146,10 @@ impl StatusList2021Credential {
/// Sets the `index`-th entry to `value`
pub(crate) fn set_entry(&mut self, index: usize, value: bool) -> Result<(), StatusList2021CredentialError> {
let mut status_list = self.status_list()?;
+ let entry_status = status_list.get(index)?;
+ if self.purpose() == StatusPurpose::Revocation && !value && entry_status {
+ return Err(StatusList2021CredentialError::UnreversibleRevocation);
+ }
status_list.set(index, value)?;
self.subject.encoded_list = status_list.into_encoded_str();
@@ -403,4 +415,35 @@ mod tests {
.expect("Failed to deserialize");
assert_eq!(credential.purpose(), StatusPurpose::Revocation);
}
+ #[test]
+ fn revoked_credential_cannot_be_unrevoked() {
+ let url = Url::parse("http://example.com").unwrap();
+ let mut status_list_credential = StatusList2021CredentialBuilder::new(StatusList2021::default())
+ .issuer(Issuer::Url(url.clone()))
+ .purpose(StatusPurpose::Revocation)
+ .subject_id(url)
+ .build()
+ .unwrap();
+
+ assert!(status_list_credential.set_entry(420, false).is_ok());
+ status_list_credential.set_entry(420, true).unwrap();
+ assert_eq!(
+ status_list_credential.set_entry(420, false),
+ Err(StatusList2021CredentialError::UnreversibleRevocation)
+ );
+ }
+ #[test]
+ fn suspended_credential_can_be_unsuspended() {
+ let url = Url::parse("http://example.com").unwrap();
+ let mut status_list_credential = StatusList2021CredentialBuilder::new(StatusList2021::default())
+ .issuer(Issuer::Url(url.clone()))
+ .purpose(StatusPurpose::Suspension)
+ .subject_id(url)
+ .build()
+ .unwrap();
+
+ assert!(status_list_credential.set_entry(420, false).is_ok());
+ status_list_credential.set_entry(420, true).unwrap();
+ assert!(status_list_credential.set_entry(420, false).is_ok());
+ }
}
From c0f15f6f1dd067f98d983264ec297c829128247c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Fri, 2 Feb 2024 14:07:44 +0100
Subject: [PATCH 09/23] Adapt to IOTA sandbox (#1290)
---
.github/actions/iota-sandbox/setup/action.yml | 36 +++++++++++++++
.../actions/iota-sandbox/tear-down/action.yml | 12 +++++
.../actions/private-tangle/setup/action.yml | 44 -------------------
.../private-tangle/tear-down/action.yml | 16 -------
.github/workflows/build-and-test.yml | 16 +++----
README.md | 8 ++--
bindings/wasm/README.md | 4 +-
bindings/wasm/examples/src/util.ts | 4 +-
examples/0_basic/0_create_did.rs | 4 +-
examples/0_basic/8_stronghold.rs | 4 +-
examples/utils/utils.rs | 4 +-
identity_iota/README.md | 12 ++---
12 files changed, 77 insertions(+), 87 deletions(-)
create mode 100644 .github/actions/iota-sandbox/setup/action.yml
create mode 100644 .github/actions/iota-sandbox/tear-down/action.yml
delete mode 100644 .github/actions/private-tangle/setup/action.yml
delete mode 100644 .github/actions/private-tangle/tear-down/action.yml
diff --git a/.github/actions/iota-sandbox/setup/action.yml b/.github/actions/iota-sandbox/setup/action.yml
new file mode 100644
index 0000000000..b62c175e7f
--- /dev/null
+++ b/.github/actions/iota-sandbox/setup/action.yml
@@ -0,0 +1,36 @@
+name: 'iota-sandbox-setup'
+description: 'Setup IOTA Sandbox'
+runs:
+ using: "composite"
+ steps:
+ - name: Setup iota sandbox
+ shell: bash
+ run: |
+ # Use next lines for using the GitHub release
+ mkdir iota-sandbox
+ cd iota-sandbox
+ mkdir sandbox
+ cd sandbox
+ # Use the output of https://api.github.com/repos/iotaledger/iota-sandbox/releases/latest
+ DOWNLOAD_URL=$(curl "https://api.github.com/repos/iotaledger/iota-sandbox/releases" | jq -r '.[0].assets[] | select(.name | contains("iota_sandbox")) | .browser_download_url')
+ echo "Downloading sandbox from $DOWNLOAD_URL"
+ curl -L -o iota_sandbox.tar.gz $DOWNLOAD_URL
+ tar -xf iota_sandbox.tar.gz
+
+ # Use the next lines to use the main branch
+ # git clone https://github.com/iotaledger/iota-sandbox
+ # cd iota-sandbox/sandbox
+
+ # Start Tangle
+ sudo ./bootstrap.sh
+ docker compose up -d
+ - name: Wait for tangle to start
+ shell: bash
+ run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/$WAIT_FOR_VERSION/wait-for | sh -s -- -t 60 http://localhost/health -- echo "Tangle is up"
+ env:
+ WAIT_FOR_VERSION: 4df3f9262d84cab0039c07bf861045fbb3c20ab7 # v2.2.3
+ - name: Wait for faucet to start
+ shell: bash
+ run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/$WAIT_FOR_VERSION/wait-for | sh -s -- -t 60 http://localhost/faucet/api/info -- echo "Faucet is up"
+ env:
+ WAIT_FOR_VERSION: 4df3f9262d84cab0039c07bf861045fbb3c20ab7 # v2.2.3
diff --git a/.github/actions/iota-sandbox/tear-down/action.yml b/.github/actions/iota-sandbox/tear-down/action.yml
new file mode 100644
index 0000000000..8a0da1906e
--- /dev/null
+++ b/.github/actions/iota-sandbox/tear-down/action.yml
@@ -0,0 +1,12 @@
+name: 'iota-sandbox-tear-down'
+description: 'tear-down a iota sandbox'
+runs:
+ using: "composite"
+ steps:
+ - name: Tear down iota sandbox
+ shell: bash
+ run: |
+ cd iota-sandbox/sandbox
+ docker-compose down
+ cd ../..
+ sudo rm -rf iota-sandbox
diff --git a/.github/actions/private-tangle/setup/action.yml b/.github/actions/private-tangle/setup/action.yml
deleted file mode 100644
index 3d6feab379..0000000000
--- a/.github/actions/private-tangle/setup/action.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-name: 'private-tangle-setup'
-description: 'Setup a private tangle'
-runs:
- using: "composite"
- steps:
- - name: Setup private tangle
- shell: bash
- run: |
- # TODO: use next lines when a working hornet release is published
- # # Download the private_tangle setup from the hornet repo.
- # mkdir private_tangle
- # cd private_tangle
- # # Use the output of https://api.github.com/repos/iotaledger/hornet/releases/latest once there's a 2.0 Hornet release.
- # DOWNLOAD_URL=$(curl "https://api.github.com/repos/iotaledger/hornet/releases" | jq -r '.[0].assets[] | select(.name | contains("private_tangle")) | .browser_download_url')
- # echo "Downloading private tangle from $DOWNLOAD_URL"
- # curl -L -o private_tangle.tar.gz $DOWNLOAD_URL
- # tar -xf private_tangle.tar.gz
-
- # TODO: remove next lines when a working hornet release is published
- git clone https://github.com/iotaledger/hornet.git
- cd hornet/private_tangle
-
- # Set minPoWScore = 1 since the default (0) doesn't work with wasm_miner.rs in iota.rs currently.
- jq '.minPoWScore = $val' --argjson val 1 protocol_parameters.json > tmp.json && mv tmp.json protocol_parameters.json
- jq --color-output . protocol_parameters.json
-
- # Manipulate and print config
- jq '.restAPI.pow.enabled = $newVal' --argjson newVal true config_private_tangle.json > tmp.$$.json && mv tmp.$$.json config_private_tangle.json
- jq --color-output . config_private_tangle.json
-
- # Start Tangle
- sudo ./cleanup.sh
- sudo ./bootstrap.sh
- sudo ./run.sh -d
- - name: Wait for tangle to start
- shell: bash
- run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/$WAIT_FOR_VERSION/wait-for | sh -s -- -t 60 http://localhost:14265/health -- echo "Tangle is up"
- env:
- WAIT_FOR_VERSION: 4df3f9262d84cab0039c07bf861045fbb3c20ab7 # v2.2.3
- - name: Wait for faucet to start
- shell: bash
- run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/$WAIT_FOR_VERSION/wait-for | sh -s -- -t 60 http://localhost:8091/api/info -- echo "Faucet is up"
- env:
- WAIT_FOR_VERSION: 4df3f9262d84cab0039c07bf861045fbb3c20ab7 # v2.2.3
diff --git a/.github/actions/private-tangle/tear-down/action.yml b/.github/actions/private-tangle/tear-down/action.yml
deleted file mode 100644
index bfd73f46ff..0000000000
--- a/.github/actions/private-tangle/tear-down/action.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: 'private-tangle-tear-down'
-description: 'tear-down a private tangle'
-runs:
- using: "composite"
- steps:
- - name: Tear down private tangle
- shell: bash
- run: |
- # TODO: use next line when a working hornet release is published
- #cd private_tangle
-
- # TODO: remove next line when a working hornet release is published
- cd hornet/private_tangle
- docker-compose down
- cd ..
- sudo rm -rf private_tangle
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 27ded3b745..d60c351e6c 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -123,9 +123,9 @@ jobs:
- name: Build with all features
run: cargo build --workspace --tests --examples --all-features --release
- - name: Start private tangle
+ - name: Start iota sandbox
if: matrix.os == 'ubuntu-latest'
- uses: './.github/actions/private-tangle/setup'
+ uses: './.github/actions/iota-sandbox/setup'
- name: Run tests
run: cargo test --workspace --all-features --release
@@ -148,9 +148,9 @@ jobs:
npm ci
npm run test:readme:rust
- - name: Tear down private tangle
+ - name: Tear down iota sandbox
if: matrix.os == 'ubuntu-latest' && always()
- uses: './.github/actions/private-tangle/tear-down'
+ uses: './.github/actions/iota-sandbox/tear-down'
- name: Stop sccache
uses: './.github/actions/rust/sccache/stop-sccache'
@@ -194,13 +194,13 @@ jobs:
name: identity-wasm-bindings-build
path: bindings/wasm
- - name: Start private tangle
- uses: './.github/actions/private-tangle/setup'
+ - name: Start iota sandbox
+ uses: './.github/actions/iota-sandbox/setup'
- name: Run Wasm examples
run: npm run test:examples
working-directory: bindings/wasm
- - name: Tear down private tangle
+ - name: Tear down iota sandbox
if: always()
- uses: './.github/actions/private-tangle/tear-down'
+ uses: './.github/actions/iota-sandbox/tear-down'
diff --git a/README.md b/README.md
index 558e53f7e2..8c1d535eed 100644
--- a/README.md
+++ b/README.md
@@ -57,13 +57,13 @@ identity_iota = { version = "1.0.0" }
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
1. Clone the repository, e.g. through `git clone https://github.com/iotaledger/identity.rs`
-2. Start a private Tangle as described in the [next section](#example-creating-an-identity)
+2. Start IOTA Sandbox as described in the [next section](#example-creating-an-identity)
3. Run the example to create a DID using `cargo run --release --example 0_create_did`
## Example: Creating an Identity
The following code creates and publishes a new IOTA DID Document to a locally running private network.
-See the [instructions](https://github.com/iotaledger/hornet/tree/develop/private_tangle) on running your own private network.
+See the [instructions](https://github.com/iotaledger/iota-sandbox) on running your own private network for development.
_Cargo.toml_
@@ -130,7 +130,7 @@ use iota_sdk::types::block::output::dto::AliasOutputDto;
use tokio::io::AsyncReadExt;
// The endpoint of the IOTA node to use.
-static API_ENDPOINT: &str = "http://127.0.0.1:14265";
+static API_ENDPOINT: &str = "http://localhost";
/// Demonstrates how to create a DID Document and publish it in a new Alias Output.
#[tokio::main]
@@ -168,7 +168,7 @@ async fn main() -> anyhow::Result<()> {
.await?[0];
println!("Your wallet address is: {}", address);
- println!("Please request funds from http://127.0.0.1:8091/, wait for a couple of seconds and then press Enter.");
+ println!("Please request funds from http://localhost/faucet/, wait for a couple of seconds and then press Enter.");
tokio::io::stdin().read_u8().await?;
// Create a new DID document with a placeholder DID.
diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md
index f3b854fa37..b7cee7a287 100644
--- a/bindings/wasm/README.md
+++ b/bindings/wasm/README.md
@@ -81,7 +81,7 @@ const EXAMPLE_JWK = new Jwk({
});
// The endpoint of the IOTA node to use.
-const API_ENDPOINT = "http://127.0.0.1:14265";
+const API_ENDPOINT = "http://localhost";
/** Demonstrate how to create a DID Document. */
async function main() {
@@ -230,7 +230,7 @@ import init, { Client } from "@iota/sdk-wasm/web";
import * as identity from "@iota/identity-wasm/web";
// The endpoint of the IOTA node to use.
-const API_ENDPOINT = "http://127.0.0.1:14265";
+const API_ENDPOINT = "http://localhost";
const EXAMPLE_JWK = new identity.Jwk({
kty: identity.JwkType.Okp,
diff --git a/bindings/wasm/examples/src/util.ts b/bindings/wasm/examples/src/util.ts
index 41a0a5a7ee..3fc2be116e 100644
--- a/bindings/wasm/examples/src/util.ts
+++ b/bindings/wasm/examples/src/util.ts
@@ -16,8 +16,8 @@ import {
Utils,
} from "@iota/sdk-wasm/node";
-export const API_ENDPOINT = "http://localhost:14265";
-export const FAUCET_ENDPOINT = "http://localhost:8091/api/enqueue";
+export const API_ENDPOINT = "http://localhost";
+export const FAUCET_ENDPOINT = "http://localhost/faucet/api/enqueue";
/** Creates a DID Document and publishes it in a new Alias Output.
diff --git a/examples/0_basic/0_create_did.rs b/examples/0_basic/0_create_did.rs
index 03f64353fc..61f157cb37 100644
--- a/examples/0_basic/0_create_did.rs
+++ b/examples/0_basic/0_create_did.rs
@@ -30,10 +30,10 @@ use iota_sdk::types::block::output::AliasOutput;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// The API endpoint of an IOTA node, e.g. Hornet.
- let api_endpoint: &str = "http://127.0.0.1:14265";
+ let api_endpoint: &str = "http://localhost";
// The faucet endpoint allows requesting funds for testing purposes.
- let faucet_endpoint: &str = "http://127.0.0.1:8091/api/enqueue";
+ let faucet_endpoint: &str = "http://localhost/faucet/api/enqueue";
// Create a new client to interact with the IOTA ledger.
let client: Client = Client::builder()
diff --git a/examples/0_basic/8_stronghold.rs b/examples/0_basic/8_stronghold.rs
index a706e467e7..0681e5b612 100644
--- a/examples/0_basic/8_stronghold.rs
+++ b/examples/0_basic/8_stronghold.rs
@@ -29,10 +29,10 @@ use iota_sdk::types::block::output::AliasOutput;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// The API endpoint of an IOTA node, e.g. Hornet.
- let api_endpoint: &str = "http://127.0.0.1:14265";
+ let api_endpoint: &str = "http://localhost";
// The faucet endpoint allows requesting funds for testing purposes.
- let faucet_endpoint: &str = "http://127.0.0.1:8091/api/enqueue";
+ let faucet_endpoint: &str = "http://localhost/faucet/api/enqueue";
// Stronghold snapshot path.
let path = random_stronghold_path();
diff --git a/examples/utils/utils.rs b/examples/utils/utils.rs
index a9b8ca5154..a79a74312e 100644
--- a/examples/utils/utils.rs
+++ b/examples/utils/utils.rs
@@ -28,8 +28,8 @@ use iota_sdk::types::block::address::Hrp;
use rand::distributions::DistString;
use serde_json::Value;
-pub static API_ENDPOINT: &str = "http://localhost:14265";
-pub static FAUCET_ENDPOINT: &str = "http://localhost:8091/api/enqueue";
+pub static API_ENDPOINT: &str = "http://localhost";
+pub static FAUCET_ENDPOINT: &str = "http://localhost/faucet/api/enqueue";
pub type MemStorage = Storage;
diff --git a/identity_iota/README.md b/identity_iota/README.md
index 83254d2152..548cf8a9e3 100644
--- a/identity_iota/README.md
+++ b/identity_iota/README.md
@@ -57,13 +57,13 @@ identity_iota = { version = "1.0.0" }
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
1. Clone the repository, e.g. through `git clone https://github.com/iotaledger/identity.rs`
-2. Start a private Tangle as described in the [next section](#example-creating-an-identity)
+2. Start IOTA Sandbox as described in the [next section](#example-creating-an-identity)
3. Run the example to create a DID using `cargo run --release --example 0_create_did`
## Example: Creating an Identity
The following code creates and publishes a new IOTA DID Document to a locally running private network.
-See the [instructions](https://github.com/iotaledger/hornet/tree/develop/private_tangle) on running your own private network.
+See the [instructions](https://github.com/iotaledger/iota-sandbox) on running your own private network for development.
_Cargo.toml_
@@ -74,9 +74,11 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = { version = "1.0.0" }
+identity_iota = {version = "1.0.0", features = ["memstore"]}
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
+anyhow = "1.0.62"
+rand = "0.8.5"
```
_main.__rs_
@@ -104,7 +106,7 @@ use iota_sdk::types::block::output::dto::AliasOutputDto;
use tokio::io::AsyncReadExt;
// The endpoint of the IOTA node to use.
-static API_ENDPOINT: &str = "http://127.0.0.1:14265";
+static API_ENDPOINT: &str = "http://localhost";
/// Demonstrates how to create a DID Document and publish it in a new Alias Output.
#[tokio::main]
@@ -142,7 +144,7 @@ async fn main() -> anyhow::Result<()> {
.await?[0];
println!("Your wallet address is: {}", address);
- println!("Please request funds from http://127.0.0.1:8091/, wait for a couple of seconds and then press Enter.");
+ println!("Please request funds from http://localhost/faucet/, wait for a couple of seconds and then press Enter.");
tokio::io::stdin().read_u8().await?;
// Create a new DID document with a placeholder DID.
From 22f042add257b26ce59336cb4a3aa9b8099cee3c Mon Sep 17 00:00:00 2001
From: Enrico Marconi <31142849+UMR1352@users.noreply.github.com>
Date: Tue, 6 Feb 2024 14:12:37 +0100
Subject: [PATCH 10/23] Fix RevocationBitmap2022 encoding bug (#1292)
* fix RevocationBitmap2022 encoding
* Support for previous encoding
---
identity_credential/Cargo.toml | 3 +-
.../revocation_bitmap_2022/bitmap.rs | 70 ++++++++++++-------
2 files changed, 47 insertions(+), 26 deletions(-)
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 22fbb4b5da..8d447567b7 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -12,7 +12,6 @@ rust-version.workspace = true
description = "An implementation of the Verifiable Credentials standard."
[dependencies]
-dataurl = { version = "0.1.2", default-features = false, optional = true }
flate2 = { version = "1.0.28", default-features = false, features = ["rust_backend"], optional = true }
futures = { version = "0.3", default-features = false, optional = true }
identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
@@ -50,7 +49,7 @@ rustdoc-args = ["--cfg", "docsrs"]
default = ["revocation-bitmap", "validator", "credential", "presentation", "domain-linkage-fetch", "sd-jwt"]
credential = []
presentation = ["credential"]
-revocation-bitmap = ["dep:dataurl", "dep:flate2", "dep:roaring"]
+revocation-bitmap = ["dep:flate2", "dep:roaring"]
status-list-2021 = ["revocation-bitmap", "dep:serde-aux"]
validator = ["dep:itertools", "dep:serde_repr", "credential", "presentation"]
domain-linkage = ["validator"]
diff --git a/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs b/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
index 6f47db97be..2dd61ba324 100644
--- a/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
+++ b/identity_credential/src/revocation/revocation_bitmap_2022/bitmap.rs
@@ -1,9 +1,9 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
+use std::borrow::Cow;
use std::io::Write;
-use dataurl::DataUrl;
use flate2::write::ZlibDecoder;
use flate2::write::ZlibEncoder;
use flate2::Compression;
@@ -18,7 +18,7 @@ use crate::revocation::error::RevocationError;
use identity_document::service::Service;
use identity_document::service::ServiceEndpoint;
-const DATA_URL_MEDIA_TYPE: &str = "application/octet-stream";
+const DATA_URL_PATTERN: &str = "data:application/octet-stream;base64,";
/// A compressed bitmap for managing credential revocation.
#[derive(Clone, Debug, Default, PartialEq)]
@@ -80,11 +80,8 @@ impl RevocationBitmap {
pub(crate) 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());
- Url::parse(data_url.to_string())
+ let data_url = format!("{DATA_URL_PATTERN}{endpoint_data}");
+ Url::parse(data_url)
.map(ServiceEndpoint::One)
.map_err(|e| RevocationError::UrlConstructionError(e.into()))
}
@@ -92,19 +89,13 @@ impl RevocationBitmap {
/// Construct a `RevocationBitmap` from a data url embedded in `service_endpoint`.
pub(crate) fn try_from_endpoint(service_endpoint: &ServiceEndpoint) -> Result {
if let ServiceEndpoint::One(url) = service_endpoint {
- 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 {
+ let Some(encoded_bitmap) = url.as_str().strip_prefix(DATA_URL_PATTERN) else {
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(|_| RevocationError::InvalidService("invalid data url - expected valid utf-8"))?,
- )
+ RevocationBitmap::deserialize_compressed_base64(encoded_bitmap)
} else {
Err(RevocationError::InvalidService(
"invalid endpoint - expected a single data url",
@@ -117,7 +108,22 @@ impl RevocationBitmap {
where
T: AsRef + ?Sized,
{
- let decoded_data: Vec = BaseEncoding::decode(data, Base::Base64Url)
+ // Fixes issue #1291.
+ // Before this fix, revocation bitmaps had been encoded twice, like so:
+ // Base64Url(Base64(compressed_bitmap)).
+ // This fix checks if the encoded string it receives as input has undergone such process
+ // and undo the inner Base64 encoding before processing the input further.
+ let mut data = Cow::Borrowed(data.as_ref());
+ if !data.starts_with("eJy") {
+ // Base64 encoded zlib default compression header
+ let decoded = BaseEncoding::decode(&data, Base::Base64)
+ .map_err(|e| RevocationError::Base64DecodingError(data.into_owned(), e))?;
+ data = Cow::Owned(
+ String::from_utf8(decoded)
+ .map_err(|_| RevocationError::InvalidService("invalid data url - expected valid utf-8"))?,
+ );
+ }
+ let decoded_data: Vec = BaseEncoding::decode(&data, Base::Base64Url)
.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)
@@ -215,7 +221,7 @@ mod tests {
#[test]
fn test_revocation_bitmap_test_vector_1() {
- const URL: &str = "data:application/octet-stream;base64,ZUp5ek1tQUFBd0FES0FCcg==";
+ const URL: &str = "data:application/octet-stream;base64,eJyzMmAAAwADKABr";
let bitmap: RevocationBitmap = RevocationBitmap::try_from_endpoint(
&identity_document::service::ServiceEndpoint::One(Url::parse(URL).unwrap()),
@@ -227,8 +233,8 @@ mod tests {
#[test]
fn test_revocation_bitmap_test_vector_2() {
- const URL: &str = "data:application/octet-stream;base64,ZUp5ek1tQmdZR0lBQVVZZ1pHQ1FBR0laSUdabDZHUGN3UW9BRXVvQjlB";
- const EXPECTED: &[u32] = &[5, 398, 67000];
+ const URL: &str = "data:application/octet-stream;base64,eJyzMmBgYGQAAWYGATDNysDGwMEAAAscAJI";
+ const EXPECTED: &[u32] = &[0, 5, 6, 8];
let bitmap: RevocationBitmap = RevocationBitmap::try_from_endpoint(
&identity_document::service::ServiceEndpoint::One(Url::parse(URL).unwrap()),
@@ -239,22 +245,38 @@ mod tests {
assert!(bitmap.is_revoked(*revoked));
}
- assert_eq!(bitmap.len(), 3);
+ assert_eq!(bitmap.len(), 4);
}
#[test]
fn test_revocation_bitmap_test_vector_3() {
- const URL: &str = "data:application/octet-stream;base64,ZUp6dHhERVJBQ0FNQkxESEFWS1lXZkN2Q3E0MmFESmtyMlNrM0ROckFLQ2RBQUFBQUFBQTMzbGhHZm9q";
+ const URL: &str = "data:application/octet-stream;base64,eJyzMmBgYGQAAWYGASCpxbCEMUNAYAkAEpcCeg";
+ const EXPECTED: &[u32] = &[42, 420, 4200, 42000];
let bitmap: RevocationBitmap = RevocationBitmap::try_from_endpoint(
&identity_document::service::ServiceEndpoint::One(Url::parse(URL).unwrap()),
)
.unwrap();
- for index in 0..2u32.pow(14) {
+ for &index in EXPECTED {
assert!(bitmap.is_revoked(index));
}
+ }
+
+ #[test]
+ fn test_revocation_bitmap_pre_1291_fix() {
+ const URL: &str = "data:application/octet-stream;base64,ZUp5ek1tQmdZR0lBQVVZZ1pHQ1FBR0laSUdabDZHUGN3UW9BRXVvQjlB";
+ const EXPECTED: &[u32] = &[5, 398, 67000];
+
+ let bitmap: RevocationBitmap = RevocationBitmap::try_from_endpoint(
+ &identity_document::service::ServiceEndpoint::One(Url::parse(URL).unwrap()),
+ )
+ .unwrap();
+
+ for revoked in EXPECTED {
+ assert!(bitmap.is_revoked(*revoked));
+ }
- assert_eq!(bitmap.len(), 2u64.pow(14));
+ assert_eq!(bitmap.len(), 3);
}
}
From 1a030d5631fae261e173d93c2905393854a2d70a Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Tue, 6 Feb 2024 14:31:22 +0100
Subject: [PATCH 11/23] Update `sd-jwt-payload` dependency (#1296)
---
bindings/wasm/docs/api-reference.md | 151 ++++++++----------
.../wasm/examples/src/1_advanced/6_sd_jwt.ts | 14 +-
bindings/wasm/src/sd_jwt/encoder.rs | 78 +++------
bindings/wasm/tests/sd_jwt.ts | 10 +-
examples/1_advanced/7_sd_jwt.rs | 6 +-
examples/1_advanced/8_status_list_2021.rs | 4 -
examples/Cargo.toml | 2 +-
identity_credential/Cargo.toml | 2 +-
identity_storage/src/storage/tests/kb_jwt.rs | 8 +-
9 files changed, 115 insertions(+), 160 deletions(-)
diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index e17fcf0c2c..e9e3a65a85 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -189,9 +189,10 @@ working with storage backed DID documents.
- StateMetadataEncoding
-- StatusPurpose
-Purpose of a StatusList2021.
-
+- MethodRelationship
+
+- CredentialStatus
+
- SubjectHolderRelationship
Declares how credential subjects must relate to the presentation holder.
See also the Subject-Holder Relationship section of the specification.
@@ -215,6 +216,9 @@ This variant is the default.
- FirstError
Return after the first error occurs.
+- StatusPurpose
+Purpose of a StatusList2021.
+
- StatusCheck
Controls validation behaviour when checking whether or not a credential has been revoked by its
credentialStatus
.
@@ -232,15 +236,17 @@ This variant is the default.
- SkipAll
Skip all status checks.
-- CredentialStatus
-
-- MethodRelationship
-
## Functions
+- encodeB64(data) ⇒
string
+Encode the given bytes in url-safe base64.
+
+- decodeB64(data) ⇒
Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
+
- verifyEd25519(alg, signingInput, decodedSignature, publicKey)
Verify a JWS signature secured with the EdDSA
algorithm and curve Ed25519
.
This function is useful when one is composing a IJwsVerifier
that delegates
@@ -249,12 +255,6 @@ This variant is the default.
This function does not check whether alg = EdDSA
in the protected header. Callers are expected to assert this
prior to calling the function.
-- encodeB64(data) ⇒
string
-Encode the given bytes in url-safe base64.
-
-- decodeB64(data) ⇒
Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
-
- start()
Initializes the console error panic hook for better error messages
@@ -5233,7 +5233,6 @@ Note: digests are created using the sha-256 algorithm.
* [SdObjectEncoder](#SdObjectEncoder)
* [new SdObjectEncoder(object)](#new_SdObjectEncoder_new)
* [.conceal(path, [salt])](#SdObjectEncoder+conceal) ⇒ [Disclosure
](#Disclosure)
- * [.concealArrayEntry(path, element_index, [salt])](#SdObjectEncoder+concealArrayEntry) ⇒ [Disclosure
](#Disclosure)
* [.addSdAlgProperty()](#SdObjectEncoder+addSdAlgProperty)
* [.encodeToString()](#SdObjectEncoder+encodeToString) ⇒ string
* [.toString()](#SdObjectEncoder+toString) ⇒ string
@@ -5257,43 +5256,35 @@ Creates a new `SdObjectEncoder` with `sha-256` hash function.
Substitutes a value with the digest of its disclosure.
If no salt is provided, the disclosure will be created with a random salt value.
-The value of the key specified in `path` will be concealed. E.g. for path
-`["claim", "subclaim"]` the value of `claim.subclaim` will be concealed.
+`path` indicates the pointer to the value that will be concealed using the syntax of
+[JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901).
-## Error
-`InvalidPath` if path is invalid or the path slice is empty.
-`DataTypeMismatch` if existing SD format is invalid.
+For the following object:
-## Note
-Use `concealArrayEntry` for values in arrays.
+ ```
+{
+ "id": "did:value",
+ "claim1": {
+ "abc": true
+ },
+ "claim2": ["val_1", "val_2"]
+}
+```
-**Kind**: instance method of [SdObjectEncoder
](#SdObjectEncoder)
+Path "/id" conceals `"id": "did:value"`
+Path "/claim1/abc" conceals `"abc": true`
+Path "/claim2/0" conceals `val_1`
+```
-| Param | Type |
-| --- | --- |
-| path | Array.<string>
|
-| [salt] | string
\| undefined
|
-
-
-
-### sdObjectEncoder.concealArrayEntry(path, element_index, [salt]) ⇒ [Disclosure
](#Disclosure)
-Substitutes a value within an array with the digest of its disclosure.
-If no salt is provided, the disclosure will be created with random salt value.
-
-`path` is used to specify the array in the object, while `element_index` specifies
-the index of the element to be concealed (index start at 0).
-
-## Error
-`InvalidPath` if path is invalid or the path slice is empty.
-`DataTypeMismatch` if existing SD format is invalid.
-`IndexOutofBounds` if `element_index` is out of bounds.
+## Errors
+* `InvalidPath` if pointer is invalid.
+* `DataTypeMismatch` if existing SD format is invalid.
**Kind**: instance method of [SdObjectEncoder
](#SdObjectEncoder)
| Param | Type |
| --- | --- |
-| path | Array.<string>
|
-| element_index | number
|
+| path | string
|
| [salt] | string
\| undefined
|
@@ -5337,7 +5328,7 @@ If path is an empty slice, decoys will be added to the top level.
| Param | Type |
| --- | --- |
-| path | Array.<string>
|
+| path | string
|
| number_of_decoys | number
|
@@ -5506,7 +5497,7 @@ A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list
* [new StatusList2021Credential(credential)](#new_StatusList2021Credential_new)
* _instance_
* [.id()](#StatusList2021Credential+id) ⇒ string
- * [.setCredentialStatus(credential, index, value)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+ * [.setCredentialStatus(credential, index, revoked_or_suspended)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
* [.purpose()](#StatusList2021Credential+purpose) ⇒ [StatusPurpose
](#StatusPurpose)
* [.entry(index)](#StatusList2021Credential+entry) ⇒ [CredentialStatus
](#CredentialStatus)
* [.clone()](#StatusList2021Credential+clone) ⇒ [StatusList2021Credential
](#StatusList2021Credential)
@@ -5530,7 +5521,7 @@ Creates a new [StatusList2021Credential](#StatusList2021Credential).
**Kind**: instance method of [StatusList2021Credential
](#StatusList2021Credential)
-### statusList2021Credential.setCredentialStatus(credential, index, value) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
+### statusList2021Credential.setCredentialStatus(credential, index, revoked_or_suspended) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
Sets the given credential's status using the `index`-th entry of this status list.
Returns the created `credentialStatus`.
@@ -5540,7 +5531,7 @@ Returns the created `credentialStatus`.
| --- | --- |
| credential | [Credential
](#Credential) |
| index | number
|
-| value | boolean
|
+| revoked_or_suspended | boolean
|
@@ -5700,7 +5691,7 @@ Attempts to build a valid [StatusList2021Credential](#StatusList2021Credential)
* [.id()](#StatusList2021Entry+id) ⇒ string
* [.purpose()](#StatusList2021Entry+purpose) ⇒ [StatusPurpose
](#StatusPurpose)
* [.index()](#StatusList2021Entry+index) ⇒ number
- * [.status_list_credential()](#StatusList2021Entry+status_list_credential) ⇒ string
+ * [.statusListCredential()](#StatusList2021Entry+statusListCredential) ⇒ string
* [.toStatus()](#StatusList2021Entry+toStatus) ⇒ Status
* [.clone()](#StatusList2021Entry+clone) ⇒ [StatusList2021Entry
](#StatusList2021Entry)
* [.toJSON()](#StatusList2021Entry+toJSON) ⇒ any
@@ -5738,9 +5729,9 @@ Returns the purpose of this entry.
Returns the index of this entry.
**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
-
+
-### statusList2021Entry.status\_list\_credential() ⇒ string
+### statusList2021Entry.statusListCredential() ⇒ string
Returns the referenced [StatusList2021Credential](#StatusList2021Credential)'s url.
**Kind**: instance method of [StatusList2021Entry
](#StatusList2021Entry)
@@ -6117,11 +6108,13 @@ Deserializes an instance from a JSON object.
## StateMetadataEncoding
**Kind**: global variable
-
+
-## StatusPurpose
-Purpose of a [StatusList2021](#StatusList2021).
+## MethodRelationship
+**Kind**: global variable
+
+## CredentialStatus
**Kind**: global variable
@@ -6167,6 +6160,12 @@ Return all errors that occur during validation.
## FirstError
Return after the first error occurs.
+**Kind**: global variable
+
+
+## StatusPurpose
+Purpose of a [StatusList2021](#StatusList2021).
+
**Kind**: global variable
@@ -6199,14 +6198,28 @@ Validate the status if supported, skip any unsupported
Skip all status checks.
**Kind**: global variable
-
+
-## CredentialStatus
-**Kind**: global variable
-
+## encodeB64(data) ⇒ string
+Encode the given bytes in url-safe base64.
+
+**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
+
+
+
+## decodeB64(data) ⇒ Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
+
+**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
-## MethodRelationship
-**Kind**: global variable
## verifyEd25519(alg, signingInput, decodedSignature, publicKey)
@@ -6229,28 +6242,6 @@ prior to calling the function.
| decodedSignature | Uint8Array
|
| publicKey | [Jwk
](#Jwk) |
-
-
-## encodeB64(data) ⇒ string
-Encode the given bytes in url-safe base64.
-
-**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
-
-
-
-## decodeB64(data) ⇒ Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
-
-**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
-
## start()
diff --git a/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts b/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts
index 397f608ee3..e389118f8c 100644
--- a/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts
+++ b/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts
@@ -99,16 +99,16 @@ export async function sdJwt() {
// Make "locality", "postal_code", "street_address" and the first entry of "nationalities"
// selectively disclosable while keeping other properties in plain text.
let disclosures = [
- encoder.conceal(["vc", "credentialSubject", "address", "locality"]),
- encoder.conceal(["vc", "credentialSubject", "address", "postal_code"]),
- encoder.conceal(["vc", "credentialSubject", "address", "street_address"]),
- encoder.concealArrayEntry(["vc", "credentialSubject", "nationalities"], 1),
+ encoder.conceal("/vc/credentialSubject/address/locality"),
+ encoder.conceal("/vc/credentialSubject/address/postal_code"),
+ encoder.conceal("/vc/credentialSubject/address/street_address"),
+ encoder.conceal("/vc/credentialSubject/nationalities/1"),
];
// Add decoys in the credential top level, nationalities array and address object.
- encoder.addDecoys(["vc", "credentialSubject", "nationalities"], 3);
- encoder.addDecoys(["vc"], 4);
- encoder.addDecoys(["vc", "credentialSubject", "address"], 2);
+ encoder.addDecoys("/vc/credentialSubject/nationalities", 3);
+ encoder.addDecoys("/vc", 4);
+ encoder.addDecoys("/vc/credentialSubject/address", 2);
// Add the `_sd_alg` property.
encoder.addSdAlgProperty();
diff --git a/bindings/wasm/src/sd_jwt/encoder.rs b/bindings/wasm/src/sd_jwt/encoder.rs
index 79ad041dc1..550742b42b 100644
--- a/bindings/wasm/src/sd_jwt/encoder.rs
+++ b/bindings/wasm/src/sd_jwt/encoder.rs
@@ -2,14 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
use super::disclosure::WasmDisclosure;
-use crate::common::ArrayString;
use crate::common::RecordStringAny;
use crate::error::Result;
use crate::error::WasmResult;
use identity_iota::sd_jwt_payload::SdObjectEncoder;
use identity_iota::sd_jwt_payload::Sha256Hasher;
-use js_sys::Array;
-use js_sys::JsString;
use serde_json::Value;
use wasm_bindgen::prelude::*;
@@ -32,54 +29,35 @@ impl WasmSdObjectEncoder {
/// Substitutes a value with the digest of its disclosure.
/// If no salt is provided, the disclosure will be created with a random salt value.
///
- /// The value of the key specified in `path` will be concealed. E.g. for path
- /// `["claim", "subclaim"]` the value of `claim.subclaim` will be concealed.
+ /// `path` indicates the pointer to the value that will be concealed using the syntax of
+ /// [JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901).
///
- /// ## Error
- /// `InvalidPath` if path is invalid or the path slice is empty.
- /// `DataTypeMismatch` if existing SD format is invalid.
+ /// For the following object:
///
- /// ## Note
- /// Use `concealArrayEntry` for values in arrays.
+ /// ```
+ /// {
+ /// "id": "did:value",
+ /// "claim1": {
+ /// "abc": true
+ /// },
+ /// "claim2": ["val_1", "val_2"]
+ /// }
+ /// ```
+ ///
+ /// Path "/id" conceals `"id": "did:value"`
+ /// Path "/claim1/abc" conceals `"abc": true`
+ /// Path "/claim2/0" conceals `val_1`
+ /// ```
+ ///
+ /// ## Errors
+ /// * `InvalidPath` if pointer is invalid.
+ /// * `DataTypeMismatch` if existing SD format is invalid.
#[wasm_bindgen(js_name = conceal)]
- pub fn conceal(&mut self, path: ArrayString, salt: Option) -> Result {
- let path: Vec = path
- .dyn_into::()?
- .iter()
- .map(|item| item.dyn_into::().map(String::from))
- .collect::>>()?;
- let path: Vec<&str> = path.iter().map(|s| &**s).collect();
+ pub fn conceal(&mut self, path: String, salt: Option) -> Result {
let disclosure = self.0.conceal(&path, salt).wasm_result()?;
Ok(WasmDisclosure(disclosure))
}
- /// Substitutes a value within an array with the digest of its disclosure.
- /// If no salt is provided, the disclosure will be created with random salt value.
- ///
- /// `path` is used to specify the array in the object, while `element_index` specifies
- /// the index of the element to be concealed (index start at 0).
- ///
- /// ## Error
- /// `InvalidPath` if path is invalid or the path slice is empty.
- /// `DataTypeMismatch` if existing SD format is invalid.
- /// `IndexOutofBounds` if `element_index` is out of bounds.
- #[wasm_bindgen(js_name = concealArrayEntry)]
- pub fn conceal_array_entry(
- &mut self,
- path: ArrayString,
- element_index: usize,
- salt: Option,
- ) -> Result {
- let path: Vec = path
- .dyn_into::()?
- .iter()
- .map(|item| item.dyn_into::().map(String::from))
- .collect::>>()?;
- let path: Vec<&str> = path.iter().map(|s| &**s).collect();
- let disclosure = self.0.conceal_array_entry(&path, element_index, salt).wasm_result()?;
- Ok(WasmDisclosure(disclosure))
- }
-
/// Adds the `_sd_alg` property to the top level of the object, with
/// its value set to "sha-256".
#[wasm_bindgen(js_name = addSdAlgProperty)]
@@ -103,7 +81,7 @@ impl WasmSdObjectEncoder {
#[wasm_bindgen(js_name = encodeToObject)]
pub fn encode_to_object(&self) -> Result {
Ok(
- JsValue::from_serde(&self.0.object())
+ JsValue::from_serde(&self.0.object().wasm_result()?)
.wasm_result()?
.unchecked_into::(),
)
@@ -112,19 +90,13 @@ impl WasmSdObjectEncoder {
/// Returns the modified object.
#[wasm_bindgen(js_name = toJSON)]
pub fn to_json(&self) -> Result {
- JsValue::from_serde(&self.0.object()).wasm_result()
+ JsValue::from_serde(&self.0.object().wasm_result()?).wasm_result()
}
/// Adds a decoy digest to the specified path.
/// If path is an empty slice, decoys will be added to the top level.
#[wasm_bindgen(js_name = addDecoys)]
- pub fn add_decoys(&mut self, path: ArrayString, number_of_decoys: usize) -> Result<()> {
- let path: Vec = path
- .dyn_into::()?
- .iter()
- .map(|item| item.dyn_into::().map(String::from))
- .collect::>>()?;
- let path: Vec<&str> = path.iter().map(|s| &**s).collect();
+ pub fn add_decoys(&mut self, path: String, number_of_decoys: usize) -> Result<()> {
self.0.add_decoys(&path, number_of_decoys).wasm_result()?;
Ok(())
}
diff --git a/bindings/wasm/tests/sd_jwt.ts b/bindings/wasm/tests/sd_jwt.ts
index 3c471fab6d..31d02633e7 100644
--- a/bindings/wasm/tests/sd_jwt.ts
+++ b/bindings/wasm/tests/sd_jwt.ts
@@ -1,5 +1,5 @@
import * as assert from "assert";
-import { SdJwt, SdObjectDecoder, SdObjectEncoder } from "../node";
+import { SdObjectDecoder, SdObjectEncoder } from "../node";
describe("sd-jwt-payload", function() {
describe("#encoder", function() {
@@ -26,7 +26,7 @@ describe("sd-jwt-payload", function() {
};
let encoder = new SdObjectEncoder(obj);
- let emailDisclosure = encoder.conceal(["email"], "tstsalt");
+ let emailDisclosure = encoder.conceal("/email", "tstsalt");
console.log(emailDisclosure);
assert.deepStrictEqual(emailDisclosure.claimName(), "email");
assert.deepStrictEqual(emailDisclosure.claimValue(), "johndoe@example.com");
@@ -38,11 +38,11 @@ describe("sd-jwt-payload", function() {
let disclosures = [
emailDisclosure.toEncodedString(),
- encoder.conceal(["address", "street_address"]).toEncodedString(),
- encoder.concealArrayEntry(["nationalities"], 0).toEncodedString(),
+ encoder.conceal("/address/street_address").toEncodedString(),
+ encoder.conceal("/nationalities/0").toEncodedString(),
];
encoder.addSdAlgProperty();
- encoder.addDecoys([], 3);
+ encoder.addDecoys("", 3);
let encoded = encoder.encodeToObject();
assert.equal(encoded._sd.length, 4);
diff --git a/examples/1_advanced/7_sd_jwt.rs b/examples/1_advanced/7_sd_jwt.rs
index 90fac13307..2d2a4665ee 100644
--- a/examples/1_advanced/7_sd_jwt.rs
+++ b/examples/1_advanced/7_sd_jwt.rs
@@ -112,9 +112,9 @@ async fn main() -> anyhow::Result<()> {
// Make "locality", "postal_code" and "street_address" selectively disclosable while keeping
// other properties in plain text.
let disclosures = vec![
- encoder.conceal(&["vc", "credentialSubject", "address", "locality"], None)?,
- encoder.conceal(&["vc", "credentialSubject", "address", "postal_code"], None)?,
- encoder.conceal(&["vc", "credentialSubject", "address", "street_address"], None)?,
+ encoder.conceal("/vc/credentialSubject/address/locality", None)?,
+ encoder.conceal("/vc/credentialSubject/address/postal_code", None)?,
+ encoder.conceal("/vc/credentialSubject/address/street_address", None)?,
];
// Add the `_sd_alg` property.
diff --git a/examples/1_advanced/8_status_list_2021.rs b/examples/1_advanced/8_status_list_2021.rs
index 3f41823bfe..0a70690e91 100644
--- a/examples/1_advanced/8_status_list_2021.rs
+++ b/examples/1_advanced/8_status_list_2021.rs
@@ -6,10 +6,8 @@ use examples::random_stronghold_path;
use examples::MemStorage;
use examples::API_ENDPOINT;
use identity_eddsa_verifier::EdDSAJwsVerifier;
-
use identity_iota::core::FromJson;
use identity_iota::core::Object;
-
use identity_iota::core::ToJson;
use identity_iota::core::Url;
use identity_iota::credential::status_list_2021::StatusList2021;
@@ -17,10 +15,8 @@ use identity_iota::credential::status_list_2021::StatusList2021Credential;
use identity_iota::credential::status_list_2021::StatusList2021CredentialBuilder;
use identity_iota::credential::status_list_2021::StatusList2021Entry;
use identity_iota::credential::status_list_2021::StatusPurpose;
-
use identity_iota::credential::Credential;
use identity_iota::credential::CredentialBuilder;
-
use identity_iota::credential::FailFast;
use identity_iota::credential::Issuer;
use identity_iota::credential::Jwt;
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 3a0974122f..653bd436c9 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -13,7 +13,7 @@ identity_stronghold = { path = "../identity_stronghold", default-features = fals
iota-sdk = { version = "1.0", default-features = false, features = ["tls", "client", "stronghold"] }
primitive-types = "0.12.1"
rand = "0.8.5"
-sd-jwt-payload = { version = "0.1.2", default-features = false, features = ["sha"] }
+sd-jwt-payload = { version = "0.2.0", default-features = false, features = ["sha"] }
serde_json = { version = "1.0", default-features = false }
tokio = { version = "1.29", default-features = false, features = ["rt"] }
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 8d447567b7..de9559b842 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -23,7 +23,7 @@ itertools = { version = "0.11", default-features = false, features = ["use_std"]
once_cell = { version = "1.18", default-features = false, features = ["std"] }
reqwest = { version = "0.11", default-features = false, features = ["default-tls", "json", "stream"], optional = true }
roaring = { version = "0.10", default-features = false, optional = true }
-sd-jwt-payload = { version = "0.1.2", default-features = false, features = ["sha"], optional = true }
+sd-jwt-payload = { version = "0.2.0", default-features = false, features = ["sha"], optional = true }
serde.workspace = true
serde-aux = { version = "4.3.1", default-features = false, optional = true }
serde_json.workspace = true
diff --git a/identity_storage/src/storage/tests/kb_jwt.rs b/identity_storage/src/storage/tests/kb_jwt.rs
index 5ea27ed5b9..e7451050fd 100644
--- a/identity_storage/src/storage/tests/kb_jwt.rs
+++ b/identity_storage/src/storage/tests/kb_jwt.rs
@@ -57,12 +57,8 @@ async fn setup_test() -> (Setup, Credential, SdJwt)
let mut encoder = SdObjectEncoder::new(&payload).unwrap();
let disclosures = vec![
- encoder
- .conceal(&["vc", "credentialSubject", "degree", "type"], None)
- .unwrap(),
- encoder
- .conceal(&["vc", "credentialSubject", "degree", "name"], None)
- .unwrap(),
+ encoder.conceal("/vc/credentialSubject/degree/type", None).unwrap(),
+ encoder.conceal("/vc/credentialSubject/degree/name", None).unwrap(),
];
encoder.add_sd_alg_property();
let encoded_payload = encoder.try_to_string().unwrap();
From a7576ee99c9f2ff0ecc413f6349b52fba1d39e47 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Feb 2024 16:48:46 +0100
Subject: [PATCH 12/23] Release v1.1.0 (#1297)
---
CHANGELOG.md | 418 +++++------------------------
README.md | 4 +-
examples/Cargo.toml | 2 +-
identity_core/Cargo.toml | 2 +-
identity_credential/Cargo.toml | 10 +-
identity_did/Cargo.toml | 4 +-
identity_document/Cargo.toml | 8 +-
identity_eddsa_verifier/Cargo.toml | 4 +-
identity_iota/Cargo.toml | 18 +-
identity_iota/README.md | 4 +-
identity_iota_core/Cargo.toml | 12 +-
identity_jose/Cargo.toml | 4 +-
identity_resolver/Cargo.toml | 12 +-
identity_storage/Cargo.toml | 18 +-
identity_stronghold/Cargo.toml | 8 +-
identity_verification/Cargo.toml | 8 +-
16 files changed, 128 insertions(+), 408 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90b76a914f..b7c3937447 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,164 +1,65 @@
# Changelog
-## [1.0.0](https://github.com/iotaledger/identity.rs/tree/v1.0.0) (2023-11-02)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.6.3...v1.0.0)
-
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 assets like Native Tokens, NFTs and various Output types.
-
-This version changes the credential and presentation format to JWT, as specified by the [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
-
-Note: Identities and credentials created with the earlier versions cannot be resolved with this version of the library.
-
-### Changed
-
-- Add dedicated stronghold crate [#1243](https://github.com/iotaledger/identity.rs/pull/1243)
-- Add dedicated EdDSA verifier crate [#1238](https://github.com/iotaledger/identity.rs/pull/1238)
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Remove `vp` and `vc` from JWT claims in JOSE [#1233](https://github.com/iotaledger/identity.rs/pull/1233)
-- Mark error enums as non-exhaustive [#1227](https://github.com/iotaledger/identity.rs/pull/1227)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-- Bring JwkDocumentExt names in line with Wasm [#1233](https://github.com/iotaledger/identity.rs/pull/1223)
-- Add lints for all crates [#1222](https://github.com/iotaledger/identity.rs/pull/1222)
-- Bump `iota-sdk` and other dependencies [#1208](https://github.com/iotaledger/identity.rs/pull/1208)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_resolver` and`identity_storage` [#1204](https://github.com/iotaledger/identity.rs/pull/1204)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Polish `identity_document` [#1198](https://github.com/iotaledger/identity.rs/pull/1198)
-- Polish `identity_did` & `identity_verification` [#1197](https://github.com/iotaledger/identity.rs/pull/1197)
-- Polish `identity_core` [#1196](https://github.com/iotaledger/identity.rs/pull/1196)
-- Remove identity-diff remains [#1195](https://github.com/iotaledger/identity.rs/pull/1195)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove `identity_agent` & `identity_comm` [#1168](https://github.com/iotaledger/identity.rs/pull/1168)
-- Remove `identity-diff` crate [#1167](https://github.com/iotaledger/identity.rs/pull/1167)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Adapt StorageError to be more generic [#1144](https://github.com/iotaledger/identity.rs/pull/1144)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Split JWS `Decoder` functionality [#1133](https://github.com/iotaledger/identity.rs/pull/1133)
-- `CoreDocument` & `Service` and `VerificationMethod` are now in the `document` and `verification` modules respectively [#1104](https://github.com/iotaledger/identity.rs/pull/1104)
-- Remove generics in CoreDocument, VerificationMethod, Service, DIDUrl and LinkedDomainService [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-- Updated `iota-types` dependency to `1.0.0-rc.6` [#1121](https://github.com/iotaledger/identity.rs/pull/1121)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
-- Update iota client 2.0.1 rc.3 [\#1062](https://github.com/iotaledger/identity.rs/pull/1062)
-- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
-- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
-- Remove `identity_agent` reexport [\#1031](https://github.com/iotaledger/identity.rs/pull/1031)
-- Rename `MixedResolver` to `Resolver` in Wasm [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
-- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
-- Feature-gate `Resolver` [\#1007](https://github.com/iotaledger/identity.rs/pull/1007)
-- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
-- Change Stardust DID method to IOTA [\#982](https://github.com/iotaledger/identity.rs/pull/982)
-- Add Wasm Stardust Client [\#975](https://github.com/iotaledger/identity.rs/pull/975)
-- Generalized Resolver [\#970](https://github.com/iotaledger/identity.rs/pull/970)
-- Change `Storage` to handle `CoreDID` [\#968](https://github.com/iotaledger/identity.rs/pull/968)
-- Feature-gate `iota-client` dependency, integrate `StardustDID` [\#958](https://github.com/iotaledger/identity.rs/pull/958)
-- Change `Storage` to store arbitrary blobs [\#953](https://github.com/iotaledger/identity.rs/pull/953)
-- Add `StardustDocumentMetadata`, implement `StardustDocument` methods [\#951](https://github.com/iotaledger/identity.rs/pull/951)
-- Fix stack overflow in `CoreDID` `PartialEq` impl [\#946](https://github.com/iotaledger/identity.rs/pull/946)
-- Change `Service` `type` field to allow sets [\#944](https://github.com/iotaledger/identity.rs/pull/944)
-- Generalise `CredentialValidator`, `PresentationValidator` to support arbitrary DID Documents [\#935](https://github.com/iotaledger/identity.rs/pull/935)
+## [v1.1.0](https://github.com/iotaledger/identity.rs/tree/v1.1.0) (2024-02-06)
+[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v1.0.0...v1.1.0)
### Added
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Polish `identity_jose` [#1201](https://github.com/iotaledger/identity.rs/pull/1201)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Make JWT presentations generic [#1186](https://github.com/iotaledger/identity.rs/pull/1186)
-- Support JWT presentations [#1175](https://github.com/iotaledger/identity.rs/pull/1175)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Stronghold Storage Implementation [#1157](https://github.com/iotaledger/identity.rs/pull/1157)
-- Implement `KeyIdStorage` in Rust [#1134](https://github.com/iotaledger/identity.rs/pull/1134)
-- Implement `JwkStorage` [#1116](https://github.com/iotaledger/identity.rs/pull/1133)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-- Add Support for Domain Linkage in Rust [#1094](https://github.com/iotaledger/identity.rs/pull/1094)
-- Add JSON Object Signing capabilities [#1105](https://github.com/iotaledger/identity.rs/pull/1105)
-- Make `StateMetadataDocument` public [#1085](https://github.com/iotaledger/identity.rs/pull/1085)
-- Add v. credentials and presentations examples [#1070](https://github.com/iotaledger/identity.rs/pull/1070)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
-- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
-- Add Stardust Client Extension Trait [\#963](https://github.com/iotaledger/identity.rs/pull/963)
-- Add StardustDID [\#949](https://github.com/iotaledger/identity.rs/pull/949)
-- State metadata serialization for the stardust DID method [\#947](https://github.com/iotaledger/identity.rs/pull/947)
-- Stardust DID Method Proof-of-Concept [\#940](https://github.com/iotaledger/identity.rs/pull/940)
-- Implement the Identity Agent [\#322](https://github.com/iotaledger/identity.rs/pull/322)
-
+- Support Selective Disclosure SD-JWT [\#1268](https://github.com/iotaledger/identity.rs/pull/1268)
+- Add support for StatusList2021 [\#1273](https://github.com/iotaledger/identity.rs/pull/1273)
+- Update sd-jwt-payload dependency [\#1296](https://github.com/iotaledger/identity.rs/pull/1296)
### Patch
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-- Feature-gate Domain Linkage [#1184](https://github.com/iotaledger/identity.rs/pull/1184)
-- Update method spec and JWK method type [#1176](https://github.com/iotaledger/identity.rs/pull/1176)
-- Replace `iota-client` with `iota-sdk` [#1161](https://github.com/iotaledger/identity.rs/pull/1161)
-- Pin `form_urlencoded` to `1.1.0` [#1136](https://github.com/iotaledger/identity.rs/pull/1136)
-- Remove legacy crates [#1080](https://github.com/iotaledger/identity.rs/pull/1080)
-- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
-- Pin agent dev-dependencies to crates versions [\#1029](https://github.com/iotaledger/identity.rs/pull/1029)
-- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
-- Update stronghold to 0.6.4 [\#928](https://github.com/iotaledger/identity.rs/pull/928)
-
-## [1.0.0-rc.1](https://github.com/iotaledger/identity.rs/tree/v1.0.0-rc.1) (2023-09-29)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.6.3...v1.0.0-rc.1)
+- Validate domain-linkage URL making sure they only include an origin [\#1267](https://github.com/iotaledger/identity.rs/pull/1267)
+- Credentials cannot be unrevoked with StatusList2021 [\#1284](https://github.com/iotaledger/identity.rs/pull/1284)
+- Fix RevocationBitmap2022 encoding bug [\#1292](https://github.com/iotaledger/identity.rs/pull/1292)
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 assets like Native Tokens, NFTs and various Output types.
+## [v1.0.0](https://github.com/iotaledger/identity.rs/tree/v1.0.0) (2023-11-02)
-This version changes the credential and presentation format to JWT, as specified by the [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
-
-Note: Identities and credentials created with the earlier versions cannot be resolved with this version of the library.
+[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.6.0...v1.0.0)
### Changed
-- Add dedicated stronghold crate [#1243](https://github.com/iotaledger/identity.rs/pull/1243)
-- Add dedicated EdDSA verifier crate [#1238](https://github.com/iotaledger/identity.rs/pull/1238)
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Remove `vp` and `vc` from JWT claims in JOSE [#1233](https://github.com/iotaledger/identity.rs/pull/1233)
-- Mark error enums as non-exhaustive [#1227](https://github.com/iotaledger/identity.rs/pull/1227)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-- Bring JwkDocumentExt names in line with Wasm [#1233](https://github.com/iotaledger/identity.rs/pull/1223)
-- Add lints for all crates [#1222](https://github.com/iotaledger/identity.rs/pull/1222)
-- Bump `iota-sdk` and other dependencies [#1208](https://github.com/iotaledger/identity.rs/pull/1208)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_resolver` and`identity_storage` [#1204](https://github.com/iotaledger/identity.rs/pull/1204)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Polish `identity_document` [#1198](https://github.com/iotaledger/identity.rs/pull/1198)
-- Polish `identity_did` & `identity_verification` [#1197](https://github.com/iotaledger/identity.rs/pull/1197)
-- Polish `identity_core` [#1196](https://github.com/iotaledger/identity.rs/pull/1196)
-- Remove identity-diff remains [#1195](https://github.com/iotaledger/identity.rs/pull/1195)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove `identity_agent` & `identity_comm` [#1168](https://github.com/iotaledger/identity.rs/pull/1168)
-- Remove `identity-diff` crate [#1167](https://github.com/iotaledger/identity.rs/pull/1167)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Adapt StorageError to be more generic [#1144](https://github.com/iotaledger/identity.rs/pull/1144)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Split JWS `Decoder` functionality [#1133](https://github.com/iotaledger/identity.rs/pull/1133)
-- `CoreDocument` & `Service` and `VerificationMethod` are now in the `document` and `verification` modules respectively [#1104](https://github.com/iotaledger/identity.rs/pull/1104)
-- Remove generics in CoreDocument, VerificationMethod, Service, DIDUrl and LinkedDomainService [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-- Updated `iota-types` dependency to `1.0.0-rc.6` [#1121](https://github.com/iotaledger/identity.rs/pull/1121)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
+- Add dedicated stronghold crate [\#1243](https://github.com/iotaledger/identity.rs/pull/1243)
+- Allow custom `kid` to be set in JWS [\#1239](https://github.com/iotaledger/identity.rs/pull/1239)
+- Add dedicated EdDSA verifier crate [\#1238](https://github.com/iotaledger/identity.rs/pull/1238)
+- Remove `vp` and `vc` from JWT claims in JOSE [\#1233](https://github.com/iotaledger/identity.rs/pull/1233)
+- Change `verifiable_credential` to type `Vec` in `Presentation` [\#1231](https://github.com/iotaledger/identity.rs/pull/1231)
+- Mark error enums as non-exhaustive [\#1227](https://github.com/iotaledger/identity.rs/pull/1227)
+- Bring `JwkDocumentExt` names in line with Wasm [\#1223](https://github.com/iotaledger/identity.rs/pull/1223)
+- Add lints for all crates [\#1222](https://github.com/iotaledger/identity.rs/pull/1222)
+- Bump `iota-sdk` and other dependencies [\#1208](https://github.com/iotaledger/identity.rs/pull/1208)
+- Polish `identity_credential` [\#1205](https://github.com/iotaledger/identity.rs/pull/1205)
+- Polish `identity_resolver` and `identity_storage` [\#1204](https://github.com/iotaledger/identity.rs/pull/1204)
+- Polish `identity_iota_core` [\#1203](https://github.com/iotaledger/identity.rs/pull/1203)
+- Rename `JwtPresentation` to `Presentation` [\#1200](https://github.com/iotaledger/identity.rs/pull/1200)
+- Polish `identity_document` [\#1198](https://github.com/iotaledger/identity.rs/pull/1198)
+- Polish `identity_did` & `identity_verification` [\#1197](https://github.com/iotaledger/identity.rs/pull/1197)
+- Polish `identity_core` [\#1196](https://github.com/iotaledger/identity.rs/pull/1196)
+- Remove identity-diff remains [\#1195](https://github.com/iotaledger/identity.rs/pull/1195)
+- Remove legacy signing and verification APIs [\#1194](https://github.com/iotaledger/identity.rs/pull/1194)
+- Remove old `Presentation` type [\#1190](https://github.com/iotaledger/identity.rs/pull/1190)
+- Remove reexported `Resolver` validation APIs [\#1183](https://github.com/iotaledger/identity.rs/pull/1183)
+- Use JWT credentials for Domain Linkage [\#1180](https://github.com/iotaledger/identity.rs/pull/1180)
+- Remove `identity_agent` & `identity_comm` [\#1168](https://github.com/iotaledger/identity.rs/pull/1168)
+- Remove `identity-diff` crate [\#1167](https://github.com/iotaledger/identity.rs/pull/1167)
+- JwkStorageDocument & JwtCredential validation [\#1152](https://github.com/iotaledger/identity.rs/pull/1152)
+- Adapt StorageError to be more generic [\#1144](https://github.com/iotaledger/identity.rs/pull/1144)
+- Add initial PublicKeyJwk support [\#1143](https://github.com/iotaledger/identity.rs/pull/1143)
+- Split JWS `Decoder` functionality [\#1133](https://github.com/iotaledger/identity.rs/pull/1133)
+- Refactor `MethodType` to make it extensible [\#1112](https://github.com/iotaledger/identity.rs/pull/1112)
+- Remove generics in `CoreDocument`, `VerificationMethod`, `Service`, `DIDUrl` and `LinkedDomainService` [\#1110](https://github.com/iotaledger/identity.rs/pull/1110)
+- `CoreDocument` & `Service` and `VerificationMethod` are now in the `document` and `verification` modules respectively [\#1104](https://github.com/iotaledger/identity.rs/pull/1104)
+- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [\#1088](https://github.com/iotaledger/identity.rs/pull/1088)
+- Fix clippy lints [\#1069](https://github.com/iotaledger/identity.rs/pull/1069)
+- More identifier checks in `CoreDocument` [\#1067](https://github.com/iotaledger/identity.rs/pull/1067)
- Update iota client 2.0.1 rc.3 [\#1062](https://github.com/iotaledger/identity.rs/pull/1062)
- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
-- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
- Remove `identity_agent` reexport [\#1031](https://github.com/iotaledger/identity.rs/pull/1031)
- Rename `MixedResolver` to `Resolver` in Wasm [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
+- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
- Feature-gate `Resolver` [\#1007](https://github.com/iotaledger/identity.rs/pull/1007)
- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
@@ -175,26 +76,25 @@ Note: Identities and credentials created with the earlier versions cannot be res
### Added
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Polish `identity_jose` [#1201](https://github.com/iotaledger/identity.rs/pull/1201)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Make JWT presentations generic [#1186](https://github.com/iotaledger/identity.rs/pull/1186)
-- Support JWT presentations [#1175](https://github.com/iotaledger/identity.rs/pull/1175)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Stronghold Storage Implementation [#1157](https://github.com/iotaledger/identity.rs/pull/1157)
-- Implement `KeyIdStorage` in Rust [#1134](https://github.com/iotaledger/identity.rs/pull/1134)
-- Implement `JwkStorage` [#1116](https://github.com/iotaledger/identity.rs/pull/1133)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-- Add Support for Domain Linkage in Rust [#1094](https://github.com/iotaledger/identity.rs/pull/1094)
-- Add JSON Object Signing capabilities [#1105](https://github.com/iotaledger/identity.rs/pull/1105)
-- Make `StateMetadataDocument` public [#1085](https://github.com/iotaledger/identity.rs/pull/1085)
-- Add v. credentials and presentations examples [#1070](https://github.com/iotaledger/identity.rs/pull/1070)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
+- Allow arbitrary JWS header parameters [\#1245](https://github.com/iotaledger/identity.rs/pull/1245)
+- Allow custom JWT claims for presentations [\#1244](https://github.com/iotaledger/identity.rs/pull/1244)
+- Allow custom JWT claims for credentials [\#1237](https://github.com/iotaledger/identity.rs/pull/1237)
+- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [\#1234](https://github.com/iotaledger/identity.rs/pull/1234)
+- Improve `Proof` [\#1209](https://github.com/iotaledger/identity.rs/pull/1209)
+- Polish `identity_jose` [\#1201](https://github.com/iotaledger/identity.rs/pull/1201)
+- Add `resolve_multiple` to Resolver [\#1189](https://github.com/iotaledger/identity.rs/pull/1189)
+- Make JWT presentations generic [\#1186](https://github.com/iotaledger/identity.rs/pull/1186)
+- Support JWT Presentations [\#1175](https://github.com/iotaledger/identity.rs/pull/1175)
+- Polish JWK thumbprint and document extension API [\#1173](https://github.com/iotaledger/identity.rs/pull/1173)
+- Stronghold Storage Implementation [\#1157](https://github.com/iotaledger/identity.rs/pull/1157)
+- Implement `KeyIdStorage` in Rust [\#1134](https://github.com/iotaledger/identity.rs/pull/1134)
+- Introduce `IToCoreDocument` and document locks in the bindings [\#1120](https://github.com/iotaledger/identity.rs/pull/1120)
+- Implement `JwkStorage` [\#1116](https://github.com/iotaledger/identity.rs/pull/1116)
+- Add JSON Object Signing capabilities [\#1105](https://github.com/iotaledger/identity.rs/pull/1105)
+- Add Support for Domain Linkage in Rust [\#1094](https://github.com/iotaledger/identity.rs/pull/1094)
+- Make `StateMetadataDocument` public [\#1085](https://github.com/iotaledger/identity.rs/pull/1085)
+- Add revocation examples [\#1076](https://github.com/iotaledger/identity.rs/pull/1076)
+- Add v. credentials and presentations examples [\#1070](https://github.com/iotaledger/identity.rs/pull/1070)
- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
- Add Stardust Client Extension Trait [\#963](https://github.com/iotaledger/identity.rs/pull/963)
- Add StardustDID [\#949](https://github.com/iotaledger/identity.rs/pull/949)
@@ -204,197 +104,17 @@ Note: Identities and credentials created with the earlier versions cannot be res
### Patch
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-- Feature-gate Domain Linkage [#1184](https://github.com/iotaledger/identity.rs/pull/1184)
-- Update method spec and JWK method type [#1176](https://github.com/iotaledger/identity.rs/pull/1176)
-- Replace `iota-client` with `iota-sdk` [#1161](https://github.com/iotaledger/identity.rs/pull/1161)
-- Pin `form_urlencoded` to `1.1.0` [#1136](https://github.com/iotaledger/identity.rs/pull/1136)
-- Remove legacy crates [#1080](https://github.com/iotaledger/identity.rs/pull/1080)
+- Fix holder claim check in VP [\#1236](https://github.com/iotaledger/identity.rs/pull/1236)
+- Fix issuer claim check in VC [\#1235](https://github.com/iotaledger/identity.rs/pull/1235)
+- Feature-gate Domain Linkage [\#1184](https://github.com/iotaledger/identity.rs/pull/1184)
+- Replace `iota-client` with `iota-sdk` [\#1161](https://github.com/iotaledger/identity.rs/pull/1161)
+- Pin `form_urlencoded` to `1.1.0` [\#1136](https://github.com/iotaledger/identity.rs/pull/1136)
+- Remove legacy crates [\#1080](https://github.com/iotaledger/identity.rs/pull/1080)
- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
- Pin agent dev-dependencies to crates versions [\#1029](https://github.com/iotaledger/identity.rs/pull/1029)
- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
- Update stronghold to 0.6.4 [\#928](https://github.com/iotaledger/identity.rs/pull/928)
-## [0.7.0-alpha.8](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.8) (2023-09-28)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.7...v0.7.0-alpha.8)
-
-
-### Changed
-- Add dedicated stronghold crate [#1243](https://github.com/iotaledger/identity.rs/pull/1243)
-- Add dedicated EdDSA verifier crate [#1238](https://github.com/iotaledger/identity.rs/pull/1238)
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Remove `vp` and `vc` from JWT claims in JOSE [#1233](https://github.com/iotaledger/identity.rs/pull/1233)
-- Mark error enums as non-exhaustive [#1227](https://github.com/iotaledger/identity.rs/pull/1227)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-- Bring JwkDocumentExt names in line with Wasm [#1233](https://github.com/iotaledger/identity.rs/pull/1223)
-- Add lints for all crates [#1222](https://github.com/iotaledger/identity.rs/pull/1222)
-
-### Added
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-
-### Patch
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-
-## [v0.7.0-alpha.7](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.7) (2023-08-15)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.6...v0.7.0-alpha.7)
-
-### Added
-
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Polish `identity_jose` [#1201](https://github.com/iotaledger/identity.rs/pull/1201)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Make JWT presentations generic [#1186](https://github.com/iotaledger/identity.rs/pull/1186)
-- Support JWT presentations [#1175](https://github.com/iotaledger/identity.rs/pull/1175)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Stronghold Storage Implementation [#1157](https://github.com/iotaledger/identity.rs/pull/1157)
-- Implement `KeyIdStorage` in Rust [#1134](https://github.com/iotaledger/identity.rs/pull/1134)
-
-### Changed
-
-- Bump `iota-sdk` and other dependencies [#1208](https://github.com/iotaledger/identity.rs/pull/1208)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_resolver` and`identity_storage` [#1204](https://github.com/iotaledger/identity.rs/pull/1204)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Polish `identity_document` [#1198](https://github.com/iotaledger/identity.rs/pull/1198)
-- Polish `identity_did` & `identity_verification` [#1197](https://github.com/iotaledger/identity.rs/pull/1197)
-- Polish `identity_core` [#1196](https://github.com/iotaledger/identity.rs/pull/1196)
-- Remove identity-diff remains [#1195](https://github.com/iotaledger/identity.rs/pull/1195)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove `identity_agent` & `identity_comm` [#1168](https://github.com/iotaledger/identity.rs/pull/1168)
-- Remove `identity-diff` crate [#1167](https://github.com/iotaledger/identity.rs/pull/1167)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Adapt StorageError to be more generic [#1144](https://github.com/iotaledger/identity.rs/pull/1144)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Split JWS `Decoder` functionality [#1133](https://github.com/iotaledger/identity.rs/pull/1133)
-
-### Patch
-
-- Feature-gate Domain Linkage [#1184](https://github.com/iotaledger/identity.rs/pull/1184)
-- Update method spec and JWK method type [#1176](https://github.com/iotaledger/identity.rs/pull/1176)
-- Replace `iota-client` with `iota-sdk` [#1161](https://github.com/iotaledger/identity.rs/pull/1161)
-- Pin `form_urlencoded` to `1.1.0` [#1136](https://github.com/iotaledger/identity.rs/pull/1136)
-
-## [v0.7.0-alpha.6](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.6) (2023-03-03)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.5...v0.7.0-alpha.6)
-
-### Added
-- Implement `JwkStorage` [#1116](https://github.com/iotaledger/identity.rs/pull/1133)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-
-### Patch
-
-- Pin `form_urlencoded` to `1.1.0` [#1136](https://github.com/iotaledger/identity.rs/pull/1136)
-
-## [v0.7.0-alpha.5](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.5) (2023-02-15)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.4...v0.7.0-alpha.5)
-
-### Added
-- Add Support for Domain Linkage in Rust [#1094](https://github.com/iotaledger/identity.rs/pull/1094)
-- Add JSON Object Signing capabilities [#1105](https://github.com/iotaledger/identity.rs/pull/1105)
-
-### Changed
-- `CoreDocument` & `Service` and `VerificationMethod` are now in the `document` and `verification` modules respectively [#1104](https://github.com/iotaledger/identity.rs/pull/1104)
-- Remove generics in CoreDocument, VerificationMethod, Service, DIDUrl and LinkedDomainService [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-- Updated `iota-types` dependency to `1.0.0-rc.6` [#1121](https://github.com/iotaledger/identity.rs/pull/1121)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-
-## [v0.7.0-alpha.4](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.4) (2022-11-24)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.3...v0.7.0-alpha.4)
-
-### Added
-
-- Make `StateMetadataDocument` public [#1085](https://github.com/iotaledger/identity.rs/pull/1085)
-- Add v. credentials and presentations examples [#1070](https://github.com/iotaledger/identity.rs/pull/1070)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
-
-### Changed
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
-### Patch
-
-- Remove legacy crates [#1080](https://github.com/iotaledger/identity.rs/pull/1080)
-
-## [v0.7.0-alpha.3](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.3) (2022-09-30)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.2...v0.7.0-alpha.3)
-
-### Changed
-
-- Update iota client 2.0.1 rc.3 [\#1062](https://github.com/iotaledger/identity.rs/pull/1062)
-## [v0.7.0-alpha.2](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.2) (2022-09-30)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.7.0-alpha.1...v0.7.0-alpha.2)
-
-### Changed
-
-- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
-- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
-
-### Added
-
-- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
-
-### Patch
-
-- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
-
-## [v0.7.0-alpha.1](https://github.com/iotaledger/identity.rs/tree/v0.7.0-alpha.1) (2022-09-19)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.6.0...v0.7.0-alpha.1)
-
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 entities like native tokens, NFTs and smart contracts.
-
- This is an early alpha release, so there may be breaking changes in upcoming versions that invalidate DIDs created with this version. The method at this point is only intended for experimentation.
-
- Note: Identities created with the earlier versions cannot be resolved with this version of the library.
-
-### Changed
-
-- Remove `identity_agent` reexport [\#1031](https://github.com/iotaledger/identity.rs/pull/1031)
-- Rename `MixedResolver` to `Resolver` in Wasm [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
-- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
-- Feature-gate `Resolver` [\#1007](https://github.com/iotaledger/identity.rs/pull/1007)
-- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
-- Change Stardust DID method to IOTA [\#982](https://github.com/iotaledger/identity.rs/pull/982)
-- Add Wasm Stardust Client [\#975](https://github.com/iotaledger/identity.rs/pull/975)
-- Generalized Resolver [\#970](https://github.com/iotaledger/identity.rs/pull/970)
-- Change `Storage` to handle `CoreDID` [\#968](https://github.com/iotaledger/identity.rs/pull/968)
-- Feature-gate `iota-client` dependency, integrate `StardustDID` [\#958](https://github.com/iotaledger/identity.rs/pull/958)
-- Change `Storage` to store arbitrary blobs [\#953](https://github.com/iotaledger/identity.rs/pull/953)
-- Add `StardustDocumentMetadata`, implement `StardustDocument` methods [\#951](https://github.com/iotaledger/identity.rs/pull/951)
-- Fix stack overflow in `CoreDID` `PartialEq` impl [\#946](https://github.com/iotaledger/identity.rs/pull/946)
-- Change `Service` `type` field to allow sets [\#944](https://github.com/iotaledger/identity.rs/pull/944)
-- Generalise `CredentialValidator`, `PresentationValidator` to support arbitrary DID Documents [\#935](https://github.com/iotaledger/identity.rs/pull/935)
-
-### Added
-
-- Add Stardust Client Extension Trait [\#963](https://github.com/iotaledger/identity.rs/pull/963)
-- Add StardustDID [\#949](https://github.com/iotaledger/identity.rs/pull/949)
-- State metadata serialization for the stardust DID method [\#947](https://github.com/iotaledger/identity.rs/pull/947)
-- Stardust DID Method Proof-of-Concept [\#940](https://github.com/iotaledger/identity.rs/pull/940)
-- Implement the Identity Agent [\#322](https://github.com/iotaledger/identity.rs/pull/322)
-
-### Patch
-
-- Pin agent dev-dependencies to crates versions [\#1029](https://github.com/iotaledger/identity.rs/pull/1029)
-- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
-- Update stronghold to 0.6.4 [\#928](https://github.com/iotaledger/identity.rs/pull/928)
-
## [v0.6.0](https://github.com/iotaledger/identity.rs/tree/v0.6.0) (2022-06-15)
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v0.5.0...v0.6.0)
diff --git a/README.md b/README.md
index 8c1d535eed..18a90879eb 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ If you want to include IOTA Identity in your project, simply add it as a depende
```toml
[dependencies]
-identity_iota = { version = "1.0.0" }
+identity_iota = { version = "1.1.0" }
```
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
@@ -85,7 +85,7 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = {version = "1.0.0", features = ["memstore"]}
+identity_iota = {version = "1.1.0", features = ["memstore"]}
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0.62"
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 653bd436c9..242dacea88 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "examples"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors = ["IOTA Stiftung"]
edition = "2021"
publish = false
diff --git a/identity_core/Cargo.toml b/identity_core/Cargo.toml
index 284cca081d..17199e528f 100644
--- a/identity_core/Cargo.toml
+++ b/identity_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_core"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index de9559b842..491158c1f1 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_credential"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors = ["IOTA Stiftung"]
edition = "2021"
homepage.workspace = true
@@ -14,10 +14,10 @@ description = "An implementation of the Verifiable Credentials standard."
[dependencies]
flate2 = { version = "1.0.28", default-features = false, features = ["rust_backend"], optional = true }
futures = { version = "0.3", default-features = false, optional = true }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
itertools = { version = "0.11", default-features = false, features = ["use_std"], optional = true }
once_cell = { version = "1.18", default-features = false, features = ["std"] }
diff --git a/identity_did/Cargo.toml b/identity_did/Cargo.toml
index 9492997598..2668c55b08 100644
--- a/identity_did/Cargo.toml
+++ b/identity_did/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_did"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition = "2021"
homepage.workspace = true
@@ -13,7 +13,7 @@ description = "Agnostic implementation of the Decentralized Identifiers (DID) st
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
form_urlencoded = { version = "1.2.0", default-features = false, features = ["alloc"] }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core" }
+identity_core = { version = "=1.1.0", path = "../identity_core" }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
diff --git a/identity_document/Cargo.toml b/identity_document/Cargo.toml
index e44b8ce02a..2ab23ef7d9 100644
--- a/identity_document/Cargo.toml
+++ b/identity_document/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_document"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,9 +13,9 @@ description = "Method-agnostic implementation of the Decentralized Identifiers (
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core" }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did" }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core" }
+identity_did = { version = "=1.1.0", path = "../identity_did" }
+identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
serde.workspace = true
strum.workspace = true
diff --git a/identity_eddsa_verifier/Cargo.toml b/identity_eddsa_verifier/Cargo.toml
index d8271444eb..516b544af6 100644
--- a/identity_eddsa_verifier/Cargo.toml
+++ b/identity_eddsa_verifier/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_eddsa_verifier"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "JWS EdDSA signature verification for IOTA Identity"
[dependencies]
-identity_jose = { version = "=1.1.0-alpha.1", path = "../identity_jose", default-features = false }
+identity_jose = { version = "=1.1.0", path = "../identity_jose", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std"] }
[features]
diff --git a/identity_iota/Cargo.toml b/identity_iota/Cargo.toml
index d519fb6917..fdf4edc9a3 100644
--- a/identity_iota/Cargo.toml
+++ b/identity_iota/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,14 +12,14 @@ rust-version.workspace = true
description = "Framework for Self-Sovereign Identity with IOTA DID."
[dependencies]
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", features = ["validator"], default-features = false }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.1.0-alpha.1", path = "../identity_iota_core", default-features = false }
-identity_resolver = { version = "=1.1.0-alpha.1", path = "../identity_resolver", default-features = false, optional = true }
-identity_storage = { version = "=1.1.0-alpha.1", path = "../identity_storage", default-features = false, features = ["iota-document"] }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0", path = "../identity_credential", features = ["validator"], default-features = false }
+identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.0", path = "../identity_iota_core", default-features = false }
+identity_resolver = { version = "=1.1.0", path = "../identity_resolver", default-features = false, optional = true }
+identity_storage = { version = "=1.1.0", path = "../identity_storage", default-features = false, features = ["iota-document"] }
+identity_verification = { version = "=1.1.0", 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 548cf8a9e3..0881e9809b 100644
--- a/identity_iota/README.md
+++ b/identity_iota/README.md
@@ -51,7 +51,7 @@ If you want to include IOTA Identity in your project, simply add it as a depende
```toml
[dependencies]
-identity_iota = { version = "1.0.0" }
+identity_iota = { version = "1.1.0" }
```
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
@@ -74,7 +74,7 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = {version = "1.0.0", features = ["memstore"]}
+identity_iota = {version = "1.1.0", features = ["memstore"]}
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0.62"
diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml
index 3f7e9fbf12..6d09722b5e 100644
--- a/identity_iota_core/Cargo.toml
+++ b/identity_iota_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota_core"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,11 +14,11 @@ description = "An IOTA Ledger integration for the IOTA DID Method."
[dependencies]
async-trait = { version = "0.1.56", default-features = false, optional = true }
futures = { version = "0.3", default-features = false }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
iota-sdk = { version = "1.0.2", default-features = false, features = ["serde", "std"], optional = true }
num-derive = { version = "0.4", default-features = false }
num-traits = { version = "0.2", default-features = false, features = ["std"] }
diff --git a/identity_jose/Cargo.toml b/identity_jose/Cargo.toml
index 748b481910..dd961fbe08 100644
--- a/identity_jose/Cargo.toml
+++ b/identity_jose/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_jose"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "A library for JOSE (JSON Object Signing and Encryption)"
[dependencies]
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std", "sha"] }
serde.workspace = true
serde_json = { version = "1.0", default-features = false, features = ["std"] }
diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml
index 76679caa5f..20ec82cd1b 100644
--- a/identity_resolver/Cargo.toml
+++ b/identity_resolver/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_resolver"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -15,16 +15,16 @@ description = "DID Resolution utilities for the identity.rs library."
# This is currently necessary for the ResolutionHandler trait. This can be made an optional dependency if alternative ways of attaching handlers are introduced.
async-trait = { version = "0.1", default-features = false }
futures = { version = "0.3" }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
serde = { version = "1.0", default-features = false, features = ["std", "derive"] }
strum.workspace = true
thiserror = { version = "1.0", default-features = false }
[dependencies.identity_iota_core]
-version = "=1.1.0-alpha.1"
+version = "=1.1.0"
path = "../identity_iota_core"
default-features = false
features = ["send-sync-client-ext", "iota-client"]
diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml
index ca2cc6eb8d..b7b0ce0b26 100644
--- a/identity_storage/Cargo.toml
+++ b/identity_storage/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_storage"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,12 +14,12 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
futures = { version = "0.3.27", default-features = false, features = ["async-await"] }
-identity_core = { version = "=1.1.0-alpha.1", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0-alpha.1", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.1.0-alpha.1", path = "../identity_iota_core", default-features = false, optional = true }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default_features = false }
+identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
+identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.0", path = "../identity_iota_core", default-features = false, optional = true }
+identity_verification = { version = "=1.1.0", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"], optional = true }
rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"], optional = true }
seahash = { version = "4.1.0", default_features = false }
@@ -29,8 +29,8 @@ thiserror.workspace = true
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync"], optional = true }
[dev-dependencies]
-identity_credential = { version = "=1.1.0-alpha.1", path = "../identity_credential", features = ["revocation-bitmap"] }
-identity_eddsa_verifier = { version = "=1.1.0-alpha.1", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_credential = { version = "=1.1.0", path = "../identity_credential", features = ["revocation-bitmap"] }
+identity_eddsa_verifier = { version = "=1.1.0", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
once_cell = { version = "1.18", default-features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
diff --git a/identity_stronghold/Cargo.toml b/identity_stronghold/Cargo.toml
index 02342b6f51..de0197a3ef 100644
--- a/identity_stronghold/Cargo.toml
+++ b/identity_stronghold/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_stronghold"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,8 +13,8 @@ description = "Secure JWK storage with Stronghold for IOTA Identity"
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
-identity_storage = { version = "=1.1.0-alpha.1", path = "../identity_storage", default_features = false }
-identity_verification = { version = "=1.1.0-alpha.1", path = "../identity_verification", default_features = false }
+identity_storage = { version = "=1.1.0", path = "../identity_storage", default_features = false }
+identity_verification = { version = "=1.1.0", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"] }
iota-sdk = { version = "1.0.2", default-features = false, features = ["client", "stronghold"] }
iota_stronghold = { version = "2.0", default-features = false }
@@ -23,7 +23,7 @@ tokio = { version = "1.29.0", default-features = false, features = ["macros", "s
zeroize = { version = "1.6.0", default_features = false }
[dev-dependencies]
-identity_did = { version = "=1.1.0-alpha.1", path = "../identity_did", default_features = false }
+identity_did = { version = "=1.1.0", path = "../identity_did", default_features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
[features]
diff --git a/identity_verification/Cargo.toml b/identity_verification/Cargo.toml
index 2367aeed14..7d965f60fc 100644
--- a/identity_verification/Cargo.toml
+++ b/identity_verification/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_verification"
-version = "1.1.0-alpha.1"
+version = "1.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -9,9 +9,9 @@ rust-version.workspace = true
description = "Verification data types and functionality for identity.rs"
[dependencies]
-identity_core = { version = "=1.1.0-alpha.1", path = "./../identity_core", default-features = false }
-identity_did = { version = "=1.1.0-alpha.1", path = "./../identity_did", default-features = false }
-identity_jose = { version = "=1.1.0-alpha.1", path = "./../identity_jose", default-features = false }
+identity_core = { version = "=1.1.0", path = "./../identity_core", default-features = false }
+identity_did = { version = "=1.1.0", path = "./../identity_did", default-features = false }
+identity_jose = { version = "=1.1.0", path = "./../identity_jose", default-features = false }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
From 9904aa5cc662b9abd98dbdfffc9aed163b702703 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Feb 2024 16:49:14 +0100
Subject: [PATCH 13/23] Release wasm-v1.1.0 (#1298)
---
bindings/wasm/CHANGELOG.md | 318 ++++++--------------------------
bindings/wasm/Cargo.toml | 2 +-
bindings/wasm/package-lock.json | 4 +-
bindings/wasm/package.json | 2 +-
4 files changed, 56 insertions(+), 270 deletions(-)
diff --git a/bindings/wasm/CHANGELOG.md b/bindings/wasm/CHANGELOG.md
index 14c8168040..7f25322057 100644
--- a/bindings/wasm/CHANGELOG.md
+++ b/bindings/wasm/CHANGELOG.md
@@ -1,285 +1,49 @@
# Changelog
-## [wasm-v1.0.0](https://github.com/iotaledger/identity.rs/tree/wasm-v1.0.0) (2023-11-02)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.6.0...wasm-v1.0.0)
+## [wasm-v1.1.0](https://github.com/iotaledger/identity.rs/tree/wasm-v1.1.0) (2024-02-06)
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 assets like Native Tokens, NFTs and various Output types.
-
-This version changes the credential and presentation format to JWT, as specified by the [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
-
-Note: Identities and credentials created with the earlier versions cannot be resolved with this version of the library.
-
-### Changed
-
-- Add dedicated EdDSA verifier crate [#1238](https://github.com/iotaledger/identity.rs/pull/1238)
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-- Polish Wasm bindings [#1206](https://github.com/iotaledger/identity.rs/pull/1206)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Upgrade `client-wasm` to `sdk-wasm` [#1202](https://github.com/iotaledger/identity.rs/pull/1202)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove stronghold nodejs bindings [#1178](https://github.com/iotaledger/identity.rs/pull/1178)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-- Remove generics in `CoreDocument`, `VerificationMethod`, `Service`, `DIDUrl` and `LinkedDomainService` [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-- Use official client-wasm dependency in examples [#1097](https://github.com/iotaledger/identity.rs/pull/1097)
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
-- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
-- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
-- Chore/rename mixed resolver [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
-- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
-- Update Wasm credential, presentation validators for Stardust [\#1004](https://github.com/iotaledger/identity.rs/pull/1004)
-- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
-- Change Stardust DID method to IOTA [\#982](https://github.com/iotaledger/identity.rs/pull/982)
-- Add Wasm Stardust Client [\#975](https://github.com/iotaledger/identity.rs/pull/975)
-- Generalized Resolver [\#970](https://github.com/iotaledger/identity.rs/pull/970)
-- Change `Storage` to handle `CoreDID` [\#968](https://github.com/iotaledger/identity.rs/pull/968)
-- Change `Storage` to store arbitrary blobs [\#953](https://github.com/iotaledger/identity.rs/pull/953)
-- Change `Service` `type` field to allow sets [\#944](https://github.com/iotaledger/identity.rs/pull/944)
-- Generalise `CredentialValidator`, `PresentationValidator` to support arbitrary DID Documents [\#935](https://github.com/iotaledger/identity.rs/pull/935)
+[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v1.0.0...wasm-v1.1.0)
### Added
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Move jwk_storage and key_id_storage to Wasm lib [#1181](https://github.com/iotaledger/identity.rs/pull/1181)
-- Wasm Bindings for JWT Presentations [#1179](https://github.com/iotaledger/identity.rs/pull/1179)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Wasm bindings for `KeyIdStorage` [#1147](https://github.com/iotaledger/identity.rs/pull/1147)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-- Add wasm credentials and presentations examples [#1075](https://github.com/iotaledger/identity.rs/pull/1075)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
-- Add `IotaDID.fromAliasId` to the Wasm bindings [\#1048](https://github.com/iotaledger/identity.rs/pull/1048)
-- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
-- Add Wasm bindings for `CoreDocument` [\#994](https://github.com/iotaledger/identity.rs/pull/994)
-- Add initial Wasm Stardust bindings [\#967](https://github.com/iotaledger/identity.rs/pull/967)
+- Support Selective Disclosure SD-JWT [\#1268](https://github.com/iotaledger/identity.rs/pull/1268)
+- Add support for StatusList2021 [\#1273](https://github.com/iotaledger/identity.rs/pull/1273)
+- Update sd-jwt-payload dependency [\#1296](https://github.com/iotaledger/identity.rs/pull/1296)
### Patch
-- Fix wasm panic caused by a race condition in `IotaDocument` and `CoreDocument` [#1258](https://github.com/iotaledger/identity.rs/pull/1258)
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-- Fix clippy's issue `uninlined-format-args` [#1109](https://github.com/iotaledger/identity.rs/pull/1109)
-- Update iota.js peer dependency [#1107](https://github.com/iotaledger/identity.rs/pull/1107)
-- Fix unresolved import in TS artifacts [\#1066](https://github.com/iotaledger/identity.rs/pull/1066)
-- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
-- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
-- Fix broken wasm bindings compilation [\#995](https://github.com/iotaledger/identity.rs/pull/995)
-- Fix DID TypeScript references [\#977](https://github.com/iotaledger/identity.rs/pull/977)
-
-## [wasm-v1.0.0-rc.1](https://github.com/iotaledger/identity.rs/tree/wasm-v1.0.0-rc.1) (2023-09-29)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.6.0...wasm-v1.0.0-rc.1)
-
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 assets like Native Tokens, NFTs and various Output types.
-
-This version changes the credential and presentation format to JWT, as specified by the [VC Data Model v1.1](https://www.w3.org/TR/vc-data-model/#json-web-token).
-
-Note: Identities and credentials created with the earlier versions cannot be resolved with this version of the library.
-
-### Changed
-
-- Add dedicated EdDSA verifier crate [#1238](https://github.com/iotaledger/identity.rs/pull/1238)
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-- Polish Wasm bindings [#1206](https://github.com/iotaledger/identity.rs/pull/1206)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Upgrade `client-wasm` to `sdk-wasm` [#1202](https://github.com/iotaledger/identity.rs/pull/1202)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove stronghold nodejs bindings [#1178](https://github.com/iotaledger/identity.rs/pull/1178)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-- Remove generics in `CoreDocument`, `VerificationMethod`, `Service`, `DIDUrl` and `LinkedDomainService` [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-- Use official client-wasm dependency in examples [#1097](https://github.com/iotaledger/identity.rs/pull/1097)
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
-- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
-- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
-- Chore/rename mixed resolver [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
-- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
-- Update Wasm credential, presentation validators for Stardust [\#1004](https://github.com/iotaledger/identity.rs/pull/1004)
-- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
-- Change Stardust DID method to IOTA [\#982](https://github.com/iotaledger/identity.rs/pull/982)
-- Add Wasm Stardust Client [\#975](https://github.com/iotaledger/identity.rs/pull/975)
-- Generalized Resolver [\#970](https://github.com/iotaledger/identity.rs/pull/970)
-- Change `Storage` to handle `CoreDID` [\#968](https://github.com/iotaledger/identity.rs/pull/968)
-- Change `Storage` to store arbitrary blobs [\#953](https://github.com/iotaledger/identity.rs/pull/953)
-- Change `Service` `type` field to allow sets [\#944](https://github.com/iotaledger/identity.rs/pull/944)
-- Generalise `CredentialValidator`, `PresentationValidator` to support arbitrary DID Documents [\#935](https://github.com/iotaledger/identity.rs/pull/935)
-
-### Added
-
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Move jwk_storage and key_id_storage to Wasm lib [#1181](https://github.com/iotaledger/identity.rs/pull/1181)
-- Wasm Bindings for JWT Presentations [#1179](https://github.com/iotaledger/identity.rs/pull/1179)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Wasm bindings for `KeyIdStorage` [#1147](https://github.com/iotaledger/identity.rs/pull/1147)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-- Add wasm credentials and presentations examples [#1075](https://github.com/iotaledger/identity.rs/pull/1075)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
-- Add `IotaDID.fromAliasId` to the Wasm bindings [\#1048](https://github.com/iotaledger/identity.rs/pull/1048)
-- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
-- Add Wasm bindings for `CoreDocument` [\#994](https://github.com/iotaledger/identity.rs/pull/994)
-- Add initial Wasm Stardust bindings [\#967](https://github.com/iotaledger/identity.rs/pull/967)
-
-### Patch
-
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-- Fix clippy's issue `uninlined-format-args` [#1109](https://github.com/iotaledger/identity.rs/pull/1109)
-- Update iota.js peer dependency [#1107](https://github.com/iotaledger/identity.rs/pull/1107)
-- Fix unresolved import in TS artifacts [\#1066](https://github.com/iotaledger/identity.rs/pull/1066)
-- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
-- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
-- Fix broken wasm bindings compilation [\#995](https://github.com/iotaledger/identity.rs/pull/995)
-- Fix DID TypeScript references [\#977](https://github.com/iotaledger/identity.rs/pull/977)
-
-## [wasm-v0.7.0-alpha.7](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.7) (2023-09-28)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.6...wasm-v0.7.0-alpha.7)
-
-### Changed
-- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [#1234](https://github.com/iotaledger/identity.rs/pull/1234)
-- Change `verifiable_credential` to type `Vec` in `Presentation` [#1231](https://github.com/iotaledger/identity.rs/pull/1231)
-
-
-### Added
-- Allow arbitrary JWS header parameters [#1245](https://github.com/iotaledger/identity.rs/pull/1245)
-- Allow custom JWT claims for presentations [#1244](https://github.com/iotaledger/identity.rs/pull/1244)
-- Allow custom `kid` to be set in JWS [#1239](https://github.com/iotaledger/identity.rs/pull/1239)
-- Allow custom JWT claims for credentials [#1237](https://github.com/iotaledger/identity.rs/pull/1237)
-
-
-### Patch
-- Fix holder claim check in VP [#1236](https://github.com/iotaledger/identity.rs/pull/1236)
-- Fix issuer claim check in VC [#1235](https://github.com/iotaledger/identity.rs/pull/1235)
-
-## [wasm-v0.7.0-alpha.6](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.6) (2023-08-15)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.5...wasm-v0.7.0-alpha.6)
-
-### Added
-
-- Improve `Proof` [#1209](https://github.com/iotaledger/identity.rs/pull/1209)
-- Add `resolve_multiple` to Resolver [#1189](https://github.com/iotaledger/identity.rs/pull/1189)
-- Move jwk_storage and key_id_storage to Wasm lib [#1181](https://github.com/iotaledger/identity.rs/pull/1181)
-- Wasm Bindings for JWT Presentations [#1179](https://github.com/iotaledger/identity.rs/pull/1179)
-- Polish JWK thumbprint and document extension API [#1173](https://github.com/iotaledger/identity.rs/pull/1173)
-- Wasm bindings for `KeyIdStorage` [#1147](https://github.com/iotaledger/identity.rs/pull/1147)
-- Introduce `IToCoreDocument` and document locks in the bindings [#1120](https://github.com/iotaledger/identity.rs/pull/1120)
-- Add Wasm Bindings for Domain Linkage [#1115](https://github.com/iotaledger/identity.rs/pull/1115)
-
-### Changed
-
-- Polish Wasm bindings [#1206](https://github.com/iotaledger/identity.rs/pull/1206)
-- Polish `identity_credential` [#1205](https://github.com/iotaledger/identity.rs/pull/1205)
-- Polish `identity_iota_core` [#1203](https://github.com/iotaledger/identity.rs/pull/1203)
-- Upgrade `client-wasm` to `sdk-wasm` [#1202](https://github.com/iotaledger/identity.rs/pull/1202)
-- Rename `JwtPresentation` to `Presentation` [#1200](https://github.com/iotaledger/identity.rs/pull/1200)
-- Remove legacy signing and verification APIs [#1194](https://github.com/iotaledger/identity.rs/pull/1194)
-- Remove old `Presentation` type [#1190](https://github.com/iotaledger/identity.rs/pull/1190)
-- Remove reexported `Resolver` validation APIs [#1183](https://github.com/iotaledger/identity.rs/pull/1183)
-- Use JWT credentials for Domain Linkage [#1180](https://github.com/iotaledger/identity.rs/pull/1180)
-- Remove stronghold nodejs bindings [#1178](https://github.com/iotaledger/identity.rs/pull/1178)
-- JwkStorageDocument & JwtCredential validation [#1152](https://github.com/iotaledger/identity.rs/pull/1152)
-- Add initial PublicKeyJwk support [#1143](https://github.com/iotaledger/identity.rs/pull/1143)
-- Refactor `MethodType` to make it extensible [#1112](https://github.com/iotaledger/identity.rs/pull/1112)
-- Remove generics in `CoreDocument`, `VerificationMethod`, `Service`, `DIDUrl` and `LinkedDomainService` [#1110](https://github.com/iotaledger/identity.rs/pull/1110)
-
-### Patch
-
-- Fix clippy's issue `uninlined-format-args` [#1109](https://github.com/iotaledger/identity.rs/pull/1109)
-- Update iota.js peer dependency [#1107](https://github.com/iotaledger/identity.rs/pull/1107)
-
-## [wasm-v0.7.0-alpha.5](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.5) (2023-01-24)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.4...wasm-v0.7.0-alpha.5)
-
-### Changed
-- Use official client-wasm dependency in examples [#1097](https://github.com/iotaledger/identity.rs/pull/1097)
-
-## [wasm-v0.7.0-alpha.4](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.4) (2022-11-24)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.3...wasm-v0.7.0-alpha.4)
-
-### Added
-- Add wasm credentials and presentations examples [#1075](https://github.com/iotaledger/identity.rs/pull/1075)
-- Add revocation examples [#1076](https://github.com/iotaledger/identity.rs/pull/1076)
-
-### Changed
-- More identifier checks in `CoreDocument` [#1067](https://github.com/iotaledger/identity.rs/pull/1067)
-- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [#1088](https://github.com/iotaledger/identity.rs/pull/1088)
-
-## [wasm-v0.7.0-alpha.3](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.3) (2022-11-01)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.2...wasm-v0.7.0-alpha.3)
-
-### Added
-
-- Add `IotaDID.fromAliasId` to the Wasm bindings [\#1048](https://github.com/iotaledger/identity.rs/pull/1048)
-
-### Patch
-
-- Fix unresolved import in TS artifacts [\#1066](https://github.com/iotaledger/identity.rs/pull/1066)
+- Validate domain-linkage URL making sure they only include an origin [\#1267](https://github.com/iotaledger/identity.rs/pull/1267)
+- Credentials cannot be unrevoked with StatusList2021 [\#1284](https://github.com/iotaledger/identity.rs/pull/1284)
+- Fix RevocationBitmap2022 encoding bug [\#1292](https://github.com/iotaledger/identity.rs/pull/1292)
+## [wasm-v1.0.0](https://github.com/iotaledger/identity.rs/tree/wasm-v1.0.0) (2023-11-02)
-## [wasm-v0.7.0-alpha.2](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.2) (2022-09-30)
+[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.6.0...wasm-v1.0.0)
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.7.0-alpha.1...wasm-v0.7.0-alpha.2)
-
### Changed
+- Allow custom `kid` to be set in JWS [\#1239](https://github.com/iotaledger/identity.rs/pull/1239)
+- Add dedicated EdDSA verifier crate [\#1238](https://github.com/iotaledger/identity.rs/pull/1238)
+- Change `verifiable_credential` to type `Vec` in `Presentation` [\#1231](https://github.com/iotaledger/identity.rs/pull/1231)
+- Polish Wasm bindings [\#1206](https://github.com/iotaledger/identity.rs/pull/1206)
+- Polish `identity_credential` [\#1205](https://github.com/iotaledger/identity.rs/pull/1205)
+- Polish `identity_iota_core` [\#1203](https://github.com/iotaledger/identity.rs/pull/1203)
+- Upgrade `client-wasm` to `sdk-wasm` [\#1202](https://github.com/iotaledger/identity.rs/pull/1202)
+- Rename `JwtPresentation` to `Presentation` [\#1200](https://github.com/iotaledger/identity.rs/pull/1200)
+- Remove legacy signing and verification APIs [\#1194](https://github.com/iotaledger/identity.rs/pull/1194)
+- Remove old `Presentation` type [\#1190](https://github.com/iotaledger/identity.rs/pull/1190)
+- Remove reexported `Resolver` validation APIs [\#1183](https://github.com/iotaledger/identity.rs/pull/1183)
+- Use JWT credentials for Domain Linkage [\#1180](https://github.com/iotaledger/identity.rs/pull/1180)
+- Remove stronghold nodejs bindings [\#1178](https://github.com/iotaledger/identity.rs/pull/1178)
+- JwkStorageDocument & JwtCredential validation [\#1152](https://github.com/iotaledger/identity.rs/pull/1152)
+- Add initial PublicKeyJwk support [\#1143](https://github.com/iotaledger/identity.rs/pull/1143)
+- Refactor `MethodType` to make it extensible [\#1112](https://github.com/iotaledger/identity.rs/pull/1112)
+- Remove generics in `CoreDocument`, `VerificationMethod`, `Service`, `DIDUrl` and `LinkedDomainService` [\#1110](https://github.com/iotaledger/identity.rs/pull/1110)
+- Update to `iota-client` 2.0.1-rc.4 and `iota-client-wasm` 0.5.0-alpha.6 [\#1088](https://github.com/iotaledger/identity.rs/pull/1088)
+- More identifier checks in `CoreDocument` [\#1067](https://github.com/iotaledger/identity.rs/pull/1067)
- Use Bech32-encoded state controller and governor addresses [\#1044](https://github.com/iotaledger/identity.rs/pull/1044)
+- Rename `MixedResolver` to `Resolver` in Wasm [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
- Expose iteration over verification relationship fields [\#1024](https://github.com/iotaledger/identity.rs/pull/1024)
-
-### Added
-
-- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
-
-### Patch
-
-- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
-
-## [wasm-v0.7.0-alpha.1](https://github.com/iotaledger/identity.rs/tree/wasm-v0.7.0-alpha.1) (2022-09-16)
-
-[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v0.6.0...wasm-v0.7.0-alpha.1)
-
-This version introduces a new DID method targeting the IOTA UTXO ledger. This method works fundamentally differently from the previous method and introduces new capabilities to interact with Layer 1 entities like native tokens, NFTs and smart contracts.
-
- This is an early alpha release, so there may be breaking changes in upcoming versions that invalidate DIDs created with this version. The method at this point is only intended for experimentation.
-
- Note: Identities created with the earlier versions cannot be resolved with this version of the library.
-
-
-
-### Changed
-
-- Chore/rename mixed resolver [\#1026](https://github.com/iotaledger/identity.rs/pull/1026)
- Add length prefix to DID Document payloads [\#1010](https://github.com/iotaledger/identity.rs/pull/1010)
- Update Wasm credential, presentation validators for Stardust [\#1004](https://github.com/iotaledger/identity.rs/pull/1004)
- Rename `Stardust` types to `Iota` [\#1000](https://github.com/iotaledger/identity.rs/pull/1000)
@@ -293,11 +57,33 @@ This version introduces a new DID method targeting the IOTA UTXO ledger. This me
### Added
+- Allow arbitrary JWS header parameters [\#1245](https://github.com/iotaledger/identity.rs/pull/1245)
+- Allow custom JWT claims for presentations [\#1244](https://github.com/iotaledger/identity.rs/pull/1244)
+- Allow custom JWT claims for credentials [\#1237](https://github.com/iotaledger/identity.rs/pull/1237)
+- Use `VC Data Model v1.1` JWT encoding instead of `VC-JWT` [\#1234](https://github.com/iotaledger/identity.rs/pull/1234)
+- Improve `Proof` [\#1209](https://github.com/iotaledger/identity.rs/pull/1209)
+- Add `resolve_multiple` to Resolver [\#1189](https://github.com/iotaledger/identity.rs/pull/1189)
+- Move jwk\_storage and key\_id\_storage to Wasm lib [\#1181](https://github.com/iotaledger/identity.rs/pull/1181)
+- Wasm Bindings for JWT Presentations [\#1179](https://github.com/iotaledger/identity.rs/pull/1179)
+- Polish JWK thumbprint and document extension API [\#1173](https://github.com/iotaledger/identity.rs/pull/1173)
+- Wasm bindings for `KeyIdStorage` [\#1147](https://github.com/iotaledger/identity.rs/pull/1147)
+- Introduce `IToCoreDocument` and document locks in the bindings [\#1120](https://github.com/iotaledger/identity.rs/pull/1120)
+- Add Wasm Bindings for Domain Linkage [\#1115](https://github.com/iotaledger/identity.rs/pull/1115)
+- Add revocation examples [\#1076](https://github.com/iotaledger/identity.rs/pull/1076)
+- Add wasm credentials and presentations examples [\#1075](https://github.com/iotaledger/identity.rs/pull/1075)
+- Add `IotaDID.fromAliasId` to the Wasm bindings [\#1048](https://github.com/iotaledger/identity.rs/pull/1048)
+- Expose Controller and Governor Addresses in metadata [\#1023](https://github.com/iotaledger/identity.rs/pull/1023)
- Add Wasm bindings for `CoreDocument` [\#994](https://github.com/iotaledger/identity.rs/pull/994)
- Add initial Wasm Stardust bindings [\#967](https://github.com/iotaledger/identity.rs/pull/967)
### Patch
+- Fix wasm panic caused by a race condition in `IotaDocument` and `CoreDocument` [\#1258](https://github.com/iotaledger/identity.rs/pull/1258)
+- Fix issuer claim check in VC [\#1235](https://github.com/iotaledger/identity.rs/pull/1235)
+- Update iota.js peer dependency [\#1107](https://github.com/iotaledger/identity.rs/pull/1107)
+- Fix unresolved import in TS artifacts [\#1066](https://github.com/iotaledger/identity.rs/pull/1066)
+- Fix `IotaDocument.unpackFromOutput` parameter type [\#1041](https://github.com/iotaledger/identity.rs/pull/1041)
+- Recommend unique `credentialStatus.id` in `RevocationBitmap2022` [\#1039](https://github.com/iotaledger/identity.rs/pull/1039)
- Support case insensitive serialization of `RentStructure` [\#1012](https://github.com/iotaledger/identity.rs/pull/1012)
- Fix broken wasm bindings compilation [\#995](https://github.com/iotaledger/identity.rs/pull/995)
- Fix DID TypeScript references [\#977](https://github.com/iotaledger/identity.rs/pull/977)
diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml
index 0e67337d41..27423f1eef 100644
--- a/bindings/wasm/Cargo.toml
+++ b/bindings/wasm/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_wasm"
-version = "1.0.0"
+version = "1.1.0"
authors = ["IOTA Stiftung"]
edition = "2021"
homepage = "https://www.iota.org"
diff --git a/bindings/wasm/package-lock.json b/bindings/wasm/package-lock.json
index d8d0f1b22c..ef07af4968 100644
--- a/bindings/wasm/package-lock.json
+++ b/bindings/wasm/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@iota/identity-wasm",
- "version": "1.0.0",
+ "version": "1.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@iota/identity-wasm",
- "version": "1.0.0",
+ "version": "1.1.0",
"license": "Apache-2.0",
"dependencies": {
"@noble/ed25519": "^1.7.3",
diff --git a/bindings/wasm/package.json b/bindings/wasm/package.json
index 842945fe79..060b03b33d 100644
--- a/bindings/wasm/package.json
+++ b/bindings/wasm/package.json
@@ -1,6 +1,6 @@
{
"name": "@iota/identity-wasm",
- "version": "1.0.0",
+ "version": "1.1.0",
"description": "WASM bindings for IOTA Identity - A Self Sovereign Identity Framework implementing the DID and VC standards from W3C. To be used in Javascript/Typescript",
"repository": {
"type": "git",
From 6127d5da1e9c2164adc645c926172108f7d3ec49 Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Mon, 19 Feb 2024 11:50:13 +0100
Subject: [PATCH 14/23] Fix compilation error caused by the `roaring` crate
(#1306)
---
README.md | 2 +-
identity_credential/Cargo.toml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 18a90879eb..924fb2c18a 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = {version = "1.1.0", features = ["memstore"]}
+identity_iota = { version = "1.1.0", features = ["memstore"] }
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0.62"
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 491158c1f1..4789aeeb60 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -22,7 +22,7 @@ indexmap = { version = "2.0", default-features = false, features = ["std", "serd
itertools = { version = "0.11", default-features = false, features = ["use_std"], optional = true }
once_cell = { version = "1.18", default-features = false, features = ["std"] }
reqwest = { version = "0.11", default-features = false, features = ["default-tls", "json", "stream"], optional = true }
-roaring = { version = "0.10", default-features = false, optional = true }
+roaring = { version = "0.10", default-features = false, features = ["std"], optional = true }
sd-jwt-payload = { version = "0.2.0", default-features = false, features = ["sha"], optional = true }
serde.workspace = true
serde-aux = { version = "4.3.1", default-features = false, optional = true }
From 5b975bb2660cf7e1e99a35fb248f82effe9650a8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 19 Feb 2024 15:56:11 +0100
Subject: [PATCH 15/23] Release v1.1.1 (#1308)
---
CHANGELOG.md | 10 +++++++++-
README.md | 4 ++--
examples/Cargo.toml | 2 +-
identity_core/Cargo.toml | 2 +-
identity_credential/Cargo.toml | 10 +++++-----
identity_did/Cargo.toml | 4 ++--
identity_document/Cargo.toml | 8 ++++----
identity_eddsa_verifier/Cargo.toml | 4 ++--
identity_iota/Cargo.toml | 18 +++++++++---------
identity_iota/README.md | 4 ++--
identity_iota_core/Cargo.toml | 12 ++++++------
identity_jose/Cargo.toml | 4 ++--
identity_resolver/Cargo.toml | 12 ++++++------
identity_storage/Cargo.toml | 18 +++++++++---------
identity_stronghold/Cargo.toml | 8 ++++----
identity_verification/Cargo.toml | 8 ++++----
16 files changed, 68 insertions(+), 60 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7c3937447..94cc55d62b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,14 @@
# Changelog
-## [v1.1.0](https://github.com/iotaledger/identity.rs/tree/v1.1.0) (2024-02-06)
+## [v1.1.1](https://github.com/iotaledger/identity.rs/tree/v1.1.1) (2024-02-19)
+
+[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v1.1.0...v1.1.1)
+
+### Patch
+
+- Fix compilation error caused by the roaring crate [\#1306](https://github.com/iotaledger/identity.rs/pull/1306)
+
+## [v1.1.0](https://github.com/iotaledger/identity.rs/tree/v1.1.0) (2024-02-07)
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v1.0.0...v1.1.0)
diff --git a/README.md b/README.md
index 924fb2c18a..658479444f 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ If you want to include IOTA Identity in your project, simply add it as a depende
```toml
[dependencies]
-identity_iota = { version = "1.1.0" }
+identity_iota = { version = "1.1.1" }
```
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
@@ -85,7 +85,7 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = { version = "1.1.0", features = ["memstore"] }
+identity_iota = { version = "1.1.1", features = ["memstore"] }
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0.62"
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 242dacea88..a9337d6a33 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "examples"
-version = "1.1.0"
+version = "1.1.1"
authors = ["IOTA Stiftung"]
edition = "2021"
publish = false
diff --git a/identity_core/Cargo.toml b/identity_core/Cargo.toml
index 17199e528f..120d6dc9be 100644
--- a/identity_core/Cargo.toml
+++ b/identity_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_core"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml
index 4789aeeb60..876d5577d5 100644
--- a/identity_credential/Cargo.toml
+++ b/identity_credential/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_credential"
-version = "1.1.0"
+version = "1.1.1"
authors = ["IOTA Stiftung"]
edition = "2021"
homepage.workspace = true
@@ -14,10 +14,10 @@ description = "An implementation of the Verifiable Credentials standard."
[dependencies]
flate2 = { version = "1.0.28", default-features = false, features = ["rust_backend"], optional = true }
futures = { version = "0.3", default-features = false, optional = true }
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
-identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
+identity_did = { version = "=1.1.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.1", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.1", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
itertools = { version = "0.11", default-features = false, features = ["use_std"], optional = true }
once_cell = { version = "1.18", default-features = false, features = ["std"] }
diff --git a/identity_did/Cargo.toml b/identity_did/Cargo.toml
index 2668c55b08..bed6f9012a 100644
--- a/identity_did/Cargo.toml
+++ b/identity_did/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_did"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition = "2021"
homepage.workspace = true
@@ -13,7 +13,7 @@ description = "Agnostic implementation of the Decentralized Identifiers (DID) st
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
form_urlencoded = { version = "1.2.0", default-features = false, features = ["alloc"] }
-identity_core = { version = "=1.1.0", path = "../identity_core" }
+identity_core = { version = "=1.1.1", path = "../identity_core" }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
diff --git a/identity_document/Cargo.toml b/identity_document/Cargo.toml
index 2ab23ef7d9..bebbd8f070 100644
--- a/identity_document/Cargo.toml
+++ b/identity_document/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_document"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,9 +13,9 @@ description = "Method-agnostic implementation of the Decentralized Identifiers (
[dependencies]
did_url = { version = "0.1", default-features = false, features = ["std", "serde"] }
-identity_core = { version = "=1.1.0", path = "../identity_core" }
-identity_did = { version = "=1.1.0", path = "../identity_did" }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core" }
+identity_did = { version = "=1.1.1", path = "../identity_did" }
+identity_verification = { version = "=1.1.1", path = "../identity_verification", default-features = false }
indexmap = { version = "2.0", default-features = false, features = ["std", "serde"] }
serde.workspace = true
strum.workspace = true
diff --git a/identity_eddsa_verifier/Cargo.toml b/identity_eddsa_verifier/Cargo.toml
index 516b544af6..257fa5d5a4 100644
--- a/identity_eddsa_verifier/Cargo.toml
+++ b/identity_eddsa_verifier/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_eddsa_verifier"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "JWS EdDSA signature verification for IOTA Identity"
[dependencies]
-identity_jose = { version = "=1.1.0", path = "../identity_jose", default-features = false }
+identity_jose = { version = "=1.1.1", path = "../identity_jose", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std"] }
[features]
diff --git a/identity_iota/Cargo.toml b/identity_iota/Cargo.toml
index fdf4edc9a3..bd5aa25125 100644
--- a/identity_iota/Cargo.toml
+++ b/identity_iota/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,14 +12,14 @@ rust-version.workspace = true
description = "Framework for Self-Sovereign Identity with IOTA DID."
[dependencies]
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0", path = "../identity_credential", features = ["validator"], default-features = false }
-identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.1.0", path = "../identity_iota_core", default-features = false }
-identity_resolver = { version = "=1.1.0", path = "../identity_resolver", default-features = false, optional = true }
-identity_storage = { version = "=1.1.0", path = "../identity_storage", default-features = false, features = ["iota-document"] }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.1", path = "../identity_credential", features = ["validator"], default-features = false }
+identity_did = { version = "=1.1.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.1", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.1", path = "../identity_iota_core", default-features = false }
+identity_resolver = { version = "=1.1.1", path = "../identity_resolver", default-features = false, optional = true }
+identity_storage = { version = "=1.1.1", path = "../identity_storage", default-features = false, features = ["iota-document"] }
+identity_verification = { version = "=1.1.1", 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 0881e9809b..e210d6e10d 100644
--- a/identity_iota/README.md
+++ b/identity_iota/README.md
@@ -51,7 +51,7 @@ If you want to include IOTA Identity in your project, simply add it as a depende
```toml
[dependencies]
-identity_iota = { version = "1.1.0" }
+identity_iota = { version = "1.1.1" }
```
To try out the [examples](https://github.com/iotaledger/identity.rs/blob/HEAD/examples), you can also do this:
@@ -74,7 +74,7 @@ version = "1.0.0"
edition = "2021"
[dependencies]
-identity_iota = {version = "1.1.0", features = ["memstore"]}
+identity_iota = {version = "1.1.1", features = ["memstore"]}
iota-sdk = { version = "1.0.2", default-features = true, features = ["tls", "client", "stronghold"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0.62"
diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml
index 6d09722b5e..ea8d43a845 100644
--- a/identity_iota_core/Cargo.toml
+++ b/identity_iota_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_iota_core"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,11 +14,11 @@ description = "An IOTA Ledger integration for the IOTA DID Method."
[dependencies]
async-trait = { version = "0.1.56", default-features = false, optional = true }
futures = { version = "0.3", default-features = false }
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.1", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.1", path = "../identity_document", default-features = false }
+identity_verification = { version = "=1.1.1", path = "../identity_verification", default-features = false }
iota-sdk = { version = "1.0.2", default-features = false, features = ["serde", "std"], optional = true }
num-derive = { version = "0.4", default-features = false }
num-traits = { version = "0.2", default-features = false, features = ["std"] }
diff --git a/identity_jose/Cargo.toml b/identity_jose/Cargo.toml
index dd961fbe08..aa2a53f13a 100644
--- a/identity_jose/Cargo.toml
+++ b/identity_jose/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_jose"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -12,7 +12,7 @@ rust-version.workspace = true
description = "A library for JOSE (JSON Object Signing and Encryption)"
[dependencies]
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["std", "sha"] }
serde.workspace = true
serde_json = { version = "1.0", default-features = false, features = ["std"] }
diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml
index 20ec82cd1b..60bda28350 100644
--- a/identity_resolver/Cargo.toml
+++ b/identity_resolver/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_resolver"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -15,16 +15,16 @@ description = "DID Resolution utilities for the identity.rs library."
# This is currently necessary for the ResolutionHandler trait. This can be made an optional dependency if alternative ways of attaching handlers are introduced.
async-trait = { version = "0.1", default-features = false }
futures = { version = "0.3" }
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["validator"] }
-identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.1", path = "../identity_credential", default-features = false, features = ["validator"] }
+identity_did = { version = "=1.1.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.1", path = "../identity_document", default-features = false }
serde = { version = "1.0", default-features = false, features = ["std", "derive"] }
strum.workspace = true
thiserror = { version = "1.0", default-features = false }
[dependencies.identity_iota_core]
-version = "=1.1.0"
+version = "=1.1.1"
path = "../identity_iota_core"
default-features = false
features = ["send-sync-client-ext", "iota-client"]
diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml
index b7b0ce0b26..75086ccab9 100644
--- a/identity_storage/Cargo.toml
+++ b/identity_storage/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_storage"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -14,12 +14,12 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
futures = { version = "0.3.27", default-features = false, features = ["async-await"] }
-identity_core = { version = "=1.1.0", path = "../identity_core", default-features = false }
-identity_credential = { version = "=1.1.0", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
-identity_did = { version = "=1.1.0", path = "../identity_did", default-features = false }
-identity_document = { version = "=1.1.0", path = "../identity_document", default-features = false }
-identity_iota_core = { version = "=1.1.0", path = "../identity_iota_core", default-features = false, optional = true }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default_features = false }
+identity_core = { version = "=1.1.1", path = "../identity_core", default-features = false }
+identity_credential = { version = "=1.1.1", path = "../identity_credential", default-features = false, features = ["credential", "presentation"] }
+identity_did = { version = "=1.1.1", path = "../identity_did", default-features = false }
+identity_document = { version = "=1.1.1", path = "../identity_document", default-features = false }
+identity_iota_core = { version = "=1.1.1", path = "../identity_iota_core", default-features = false, optional = true }
+identity_verification = { version = "=1.1.1", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"], optional = true }
rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"], optional = true }
seahash = { version = "4.1.0", default_features = false }
@@ -29,8 +29,8 @@ thiserror.workspace = true
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync"], optional = true }
[dev-dependencies]
-identity_credential = { version = "=1.1.0", path = "../identity_credential", features = ["revocation-bitmap"] }
-identity_eddsa_verifier = { version = "=1.1.0", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
+identity_credential = { version = "=1.1.1", path = "../identity_credential", features = ["revocation-bitmap"] }
+identity_eddsa_verifier = { version = "=1.1.1", path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
once_cell = { version = "1.18", default-features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
diff --git a/identity_stronghold/Cargo.toml b/identity_stronghold/Cargo.toml
index de0197a3ef..e45a6d4eb7 100644
--- a/identity_stronghold/Cargo.toml
+++ b/identity_stronghold/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_stronghold"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -13,8 +13,8 @@ description = "Secure JWK storage with Stronghold for IOTA Identity"
[dependencies]
async-trait = { version = "0.1.64", default-features = false }
-identity_storage = { version = "=1.1.0", path = "../identity_storage", default_features = false }
-identity_verification = { version = "=1.1.0", path = "../identity_verification", default_features = false }
+identity_storage = { version = "=1.1.1", path = "../identity_storage", default_features = false }
+identity_verification = { version = "=1.1.1", path = "../identity_verification", default_features = false }
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"] }
iota-sdk = { version = "1.0.2", default-features = false, features = ["client", "stronghold"] }
iota_stronghold = { version = "2.0", default-features = false }
@@ -23,7 +23,7 @@ tokio = { version = "1.29.0", default-features = false, features = ["macros", "s
zeroize = { version = "1.6.0", default_features = false }
[dev-dependencies]
-identity_did = { version = "=1.1.0", path = "../identity_did", default_features = false }
+identity_did = { version = "=1.1.1", path = "../identity_did", default_features = false }
tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync", "rt"] }
[features]
diff --git a/identity_verification/Cargo.toml b/identity_verification/Cargo.toml
index 7d965f60fc..1b6bb11d77 100644
--- a/identity_verification/Cargo.toml
+++ b/identity_verification/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "identity_verification"
-version = "1.1.0"
+version = "1.1.1"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
@@ -9,9 +9,9 @@ rust-version.workspace = true
description = "Verification data types and functionality for identity.rs"
[dependencies]
-identity_core = { version = "=1.1.0", path = "./../identity_core", default-features = false }
-identity_did = { version = "=1.1.0", path = "./../identity_did", default-features = false }
-identity_jose = { version = "=1.1.0", path = "./../identity_jose", default-features = false }
+identity_core = { version = "=1.1.1", path = "./../identity_core", default-features = false }
+identity_did = { version = "=1.1.1", path = "./../identity_did", default-features = false }
+identity_jose = { version = "=1.1.1", path = "./../identity_jose", default-features = false }
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
From 48696c682d3e99ecf14c0cbe4929f7aded332922 Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Wed, 21 Feb 2024 10:12:30 +0100
Subject: [PATCH 16/23] Add `get_public_key` for `StrongholdStorage` (#1311)
---
.../src/stronghold_jwk_storage.rs | 33 ++++++++++++++++++-
.../src/tests/test_jwk_storage.rs | 16 +++++++++
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/identity_stronghold/src/stronghold_jwk_storage.rs b/identity_stronghold/src/stronghold_jwk_storage.rs
index eb1b186f86..16f25584b6 100644
--- a/identity_stronghold/src/stronghold_jwk_storage.rs
+++ b/identity_stronghold/src/stronghold_jwk_storage.rs
@@ -62,9 +62,40 @@ impl StrongholdStorage {
pub(crate) async fn get_stronghold(&self) -> MutexGuard<'_, Stronghold> {
match *self.0 {
SecretManager::Stronghold(ref stronghold) => stronghold.inner().await,
- _ => unreachable!("secret manager can be only constrcuted from stronghold"),
+ _ => unreachable!("secret manager can be only constructed from stronghold"),
}
}
+
+ /// Retrieve the public key corresponding to `key_id`.
+ pub async fn get_public_key(&self, key_id: &KeyId) -> KeyStorageResult {
+ let stronghold = self.get_stronghold().await;
+ let client = get_client(&stronghold)?;
+
+ let location = Location::generic(
+ IDENTITY_VAULT_PATH.as_bytes().to_vec(),
+ key_id.to_string().as_bytes().to_vec(),
+ );
+
+ let public_key_procedure = iota_stronghold::procedures::PublicKey {
+ ty: ProceduresKeyType::Ed25519,
+ private_key: location,
+ };
+
+ let procedure_result = client
+ .execute_procedure(StrongholdProcedure::PublicKey(public_key_procedure))
+ .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound).with_source(err))?;
+
+ let public_key: Vec = procedure_result.into();
+
+ let mut params = JwkParamsOkp::new();
+ params.x = jwu::encode_b64(public_key);
+ params.crv = EdCurve::Ed25519.name().to_owned();
+ let mut jwk: Jwk = Jwk::from_params(params);
+ jwk.set_alg(JwsAlgorithm::EdDSA.name());
+ jwk.set_kid(jwk.thumbprint_sha256_b64());
+
+ Ok(jwk)
+ }
}
#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
diff --git a/identity_stronghold/src/tests/test_jwk_storage.rs b/identity_stronghold/src/tests/test_jwk_storage.rs
index 73f6a41a1e..61e25af808 100644
--- a/identity_stronghold/src/tests/test_jwk_storage.rs
+++ b/identity_stronghold/src/tests/test_jwk_storage.rs
@@ -22,6 +22,21 @@ async fn insert() {
jwk_storage_tests::test_insertion(stronghold_storage).await;
}
+#[tokio::test]
+async fn retrieve() {
+ let stronghold_secret_manager = create_stronghold_secret_manager();
+ let stronghold_storage = StrongholdStorage::new(stronghold_secret_manager);
+
+ let generate = stronghold_storage
+ .generate(KeyType::new("Ed25519"), JwsAlgorithm::EdDSA)
+ .await
+ .unwrap();
+ let key_id = &generate.key_id;
+
+ let pub_key: Jwk = stronghold_storage.get_public_key(key_id).await.unwrap();
+ assert_eq!(generate.jwk, pub_key);
+}
+
#[tokio::test]
async fn incompatible_key_alg() {
let stronghold_secret_manager = create_stronghold_secret_manager();
@@ -53,6 +68,7 @@ async fn key_exists() {
// Tests the cases that require persisting to disk, generate, insert and delete.
#[tokio::test]
async fn write_to_disk() {
+ iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap();
const PASS: &str = "secure_password";
let file: PathBuf = create_temp_file();
let secret_manager = StrongholdSecretManager::builder()
From 41105e5a89806afce5b09e6ca714a730b8f478d5 Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Wed, 21 Feb 2024 15:49:12 +0100
Subject: [PATCH 17/23] Support multiple IOTA networks in the `Resolver`
(#1304)
---
identity_iota_core/Cargo.toml | 4 +-
.../src/client/identity_client.rs | 7 +-
identity_resolver/Cargo.toml | 2 +
identity_resolver/src/error.rs | 3 +
identity_resolver/src/resolution/resolver.rs | 118 +++++++++++++++++-
5 files changed, 130 insertions(+), 4 deletions(-)
diff --git a/identity_iota_core/Cargo.toml b/identity_iota_core/Cargo.toml
index ea8d43a845..c5fbfa1f89 100644
--- a/identity_iota_core/Cargo.toml
+++ b/identity_iota_core/Cargo.toml
@@ -45,9 +45,11 @@ rustdoc-args = ["--cfg", "docsrs"]
default = ["client", "iota-client", "revocation-bitmap", "send-sync-client-ext"]
# Exposes the IotaIdentityClient and IotaIdentityClientExt traits.
client = ["dep:async-trait", "iota-sdk"]
-# Enbales the implementation of the extension traits on the iota-sdk's Client.
+# Enables the implementation of the extension traits on the iota-sdk's Client.
iota-client = ["client", "iota-sdk/client", "iota-sdk/tls"]
# Enables revocation with `RevocationBitmap2022`.
revocation-bitmap = ["identity_credential/revocation-bitmap"]
# Adds Send bounds on the futures produces by the client extension traits.
send-sync-client-ext = []
+# Disables the blanket implementation of `IotaIdentityClientExt`.
+test = ["client"]
diff --git a/identity_iota_core/src/client/identity_client.rs b/identity_iota_core/src/client/identity_client.rs
index 94b0cf88b2..34df1fd5f0 100644
--- a/identity_iota_core/src/client/identity_client.rs
+++ b/identity_iota_core/src/client/identity_client.rs
@@ -1,7 +1,8 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
-use crate::block::protocol::ProtocolParameters;
+#[cfg(feature = "test")]
+use iota_sdk::client::Client;
use crate::block::address::Address;
use crate::block::output::feature::SenderFeature;
@@ -14,6 +15,7 @@ use crate::block::output::Feature;
use crate::block::output::OutputId;
use crate::block::output::RentStructure;
use crate::block::output::UnlockCondition;
+use crate::block::protocol::ProtocolParameters;
use crate::Error;
use crate::IotaDID;
use crate::IotaDocument;
@@ -192,7 +194,10 @@ pub trait IotaIdentityClientExt: IotaIdentityClient {
}
}
+#[cfg(not(feature = "test"))]
impl IotaIdentityClientExt for T where T: IotaIdentityClient {}
+#[cfg(feature = "test")]
+impl IotaIdentityClientExt for Client {}
pub(super) async fn validate_network(client: &T, did: &IotaDID) -> Result<()>
where
diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml
index 60bda28350..bd28b248ad 100644
--- a/identity_resolver/Cargo.toml
+++ b/identity_resolver/Cargo.toml
@@ -31,6 +31,8 @@ features = ["send-sync-client-ext", "iota-client"]
optional = true
[dev-dependencies]
+identity_iota_core = { version = "=1.1.1", path = "../identity_iota_core", features = ["test"] }
+iota-sdk = { version = "1.0.2" }
tokio = { version = "1.29.0", default-features = false, features = ["rt-multi-thread", "macros"] }
[features]
diff --git a/identity_resolver/src/error.rs b/identity_resolver/src/error.rs
index 5a8c3c63f4..d72a78fd4a 100644
--- a/identity_resolver/src/error.rs
+++ b/identity_resolver/src/error.rs
@@ -68,4 +68,7 @@ pub enum ErrorCause {
/// The method that is unsupported.
method: String,
},
+ /// No client attached to the specific network.
+ #[error("none of the attached clients support the network {0}")]
+ UnsupportedNetwork(String),
}
diff --git a/identity_resolver/src/resolution/resolver.rs b/identity_resolver/src/resolution/resolver.rs
index 10d5359db8..b8ceffbc7f 100644
--- a/identity_resolver/src/resolution/resolver.rs
+++ b/identity_resolver/src/resolution/resolver.rs
@@ -249,12 +249,14 @@ impl Resolver> {
#[cfg(feature = "iota")]
mod iota_handler {
+ use crate::ErrorCause;
+
use super::Resolver;
use identity_document::document::CoreDocument;
- use identity_iota_core::IotaClientExt;
use identity_iota_core::IotaDID;
use identity_iota_core::IotaDocument;
use identity_iota_core::IotaIdentityClientExt;
+ use std::collections::HashMap;
use std::sync::Arc;
impl Resolver
@@ -266,7 +268,7 @@ mod iota_handler {
/// See also [`attach_handler`](Self::attach_handler).
pub fn attach_iota_handler(&mut self, client: CLI)
where
- CLI: IotaClientExt + Send + Sync + 'static,
+ CLI: IotaIdentityClientExt + Send + Sync + 'static,
{
let arc_client: Arc = Arc::new(client);
@@ -277,6 +279,58 @@ mod iota_handler {
self.attach_handler(IotaDID::METHOD.to_owned(), handler);
}
+
+ /// Convenience method for attaching multiple handlers responsible for resolving IOTA DIDs
+ /// on multiple networks.
+ ///
+ ///
+ /// # Arguments
+ ///
+ /// * `clients` - A collection of tuples where each tuple contains the name of the network name and its
+ /// corresponding client.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// // Assume `smr_client` and `iota_client` are instances IOTA clients `iota_sdk::client::Client`.
+ /// attach_multiple_iota_handlers(vec![("smr", smr_client), ("iota", iota_client)]);
+ /// ```
+ ///
+ /// # See Also
+ /// - [`attach_handler`](Self::attach_handler).
+ ///
+ /// # Note
+ ///
+ /// - Using `attach_iota_handler` or `attach_handler` for the IOTA method would override all
+ /// previously added clients.
+ /// - This function does not validate the provided configuration. Ensure that the provided
+ /// network name corresponds with the client, possibly by using `client.network_name()`.
+ pub fn attach_multiple_iota_handlers(&mut self, clients: I)
+ where
+ CLI: IotaIdentityClientExt + Send + Sync + 'static,
+ I: IntoIterator- ,
+ {
+ let arc_clients = Arc::new(clients.into_iter().collect::>());
+
+ let handler = move |did: IotaDID| {
+ let future_client = arc_clients.clone();
+ async move {
+ let did_network = did.network_str();
+ let client: &CLI =
+ future_client
+ .get(did_network)
+ .ok_or(crate::Error::new(ErrorCause::UnsupportedNetwork(
+ did_network.to_string(),
+ )))?;
+ client
+ .resolve_did(&did)
+ .await
+ .map_err(|err| crate::Error::new(ErrorCause::HandlerError { source: Box::new(err) }))
+ }
+ };
+
+ self.attach_handler(IotaDID::METHOD.to_owned(), handler);
+ }
}
}
@@ -301,3 +355,63 @@ where
.finish()
}
}
+
+#[cfg(test)]
+mod tests {
+ use identity_iota_core::block::output::AliasId;
+ use identity_iota_core::block::output::AliasOutput;
+ use identity_iota_core::block::output::OutputId;
+ use identity_iota_core::block::protocol::ProtocolParameters;
+ use identity_iota_core::IotaDID;
+ use identity_iota_core::IotaDocument;
+ use identity_iota_core::IotaIdentityClient;
+ use identity_iota_core::IotaIdentityClientExt;
+
+ use super::*;
+
+ struct DummyClient(IotaDocument);
+
+ #[async_trait::async_trait]
+ impl IotaIdentityClient for DummyClient {
+ async fn get_alias_output(&self, _id: AliasId) -> identity_iota_core::Result<(OutputId, AliasOutput)> {
+ unreachable!()
+ }
+ async fn get_protocol_parameters(&self) -> identity_iota_core::Result {
+ unreachable!()
+ }
+ }
+
+ #[async_trait::async_trait]
+ impl IotaIdentityClientExt for DummyClient {
+ async fn resolve_did(&self, did: &IotaDID) -> identity_iota_core::Result {
+ if self.0.id().as_str() == did.as_str() {
+ Ok(self.0.clone())
+ } else {
+ Err(identity_iota_core::Error::DIDResolutionError(
+ iota_sdk::client::error::Error::NoOutput(did.to_string()),
+ ))
+ }
+ }
+ }
+
+ #[tokio::test]
+ async fn test_multiple_handlers() {
+ let did1 =
+ IotaDID::parse("did:iota:smr:0x0101010101010101010101010101010101010101010101010101010101010101").unwrap();
+ let document = IotaDocument::new_with_id(did1.clone());
+ let dummy_smr_client = DummyClient(document);
+
+ let did2 = IotaDID::parse("did:iota:0x0101010101010101010101010101010101010101010101010101010101010101").unwrap();
+ let document = IotaDocument::new_with_id(did2.clone());
+ let dummy_iota_client = DummyClient(document);
+
+ let mut resolver = Resolver::::new();
+ resolver.attach_multiple_iota_handlers(vec![("iota", dummy_iota_client), ("smr", dummy_smr_client)]);
+
+ let doc = resolver.resolve(&did1).await.unwrap();
+ assert_eq!(doc.id(), &did1);
+
+ let doc = resolver.resolve(&did2).await.unwrap();
+ assert_eq!(doc.id(), &did2);
+ }
+}
From f3ecfbb3cfea101baeb8011ea8b6052ffa2c9fc3 Mon Sep 17 00:00:00 2001
From: Luca Giorgino <19236900+lucagiorgino@users.noreply.github.com>
Date: Thu, 29 Feb 2024 08:57:16 +0000
Subject: [PATCH 18/23] Add new Verification method type (#1305)
---
identity_verification/src/verification_method/material.rs | 6 +++++-
.../src/verification_method/method_type.rs | 5 +++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/identity_verification/src/verification_method/material.rs b/identity_verification/src/verification_method/material.rs
index d8553a4368..4d5f5775aa 100644
--- a/identity_verification/src/verification_method/material.rs
+++ b/identity_verification/src/verification_method/material.rs
@@ -21,6 +21,9 @@ pub enum MethodData {
PublicKeyBase58(String),
/// Verification Material in the JSON Web Key format.
PublicKeyJwk(Jwk),
+ /// Verification Material in CAIP-10 format.
+ /// [CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md)
+ BlockchainAccountId(String),
}
impl MethodData {
@@ -45,7 +48,7 @@ impl MethodData {
/// represented as a vector of bytes.
pub fn try_decode(&self) -> Result> {
match self {
- Self::PublicKeyJwk(_) => Err(Error::InvalidMethodDataTransformation(
+ Self::PublicKeyJwk(_) | Self::BlockchainAccountId(_) => Err(Error::InvalidMethodDataTransformation(
"method data is not base encoded",
)),
Self::PublicKeyMultibase(input) => {
@@ -76,6 +79,7 @@ impl Debug for MethodData {
Self::PublicKeyJwk(inner) => f.write_fmt(format_args!("PublicKeyJwk({inner:#?})")),
Self::PublicKeyMultibase(inner) => f.write_fmt(format_args!("PublicKeyMultibase({inner})")),
Self::PublicKeyBase58(inner) => f.write_fmt(format_args!("PublicKeyBase58({inner})")),
+ Self::BlockchainAccountId(inner) => f.write_fmt(format_args!("BlockchainAccountId({inner})")),
}
}
}
diff --git a/identity_verification/src/verification_method/method_type.rs b/identity_verification/src/verification_method/method_type.rs
index e387db14de..aa80ef4580 100644
--- a/identity_verification/src/verification_method/method_type.rs
+++ b/identity_verification/src/verification_method/method_type.rs
@@ -12,6 +12,7 @@ use crate::error::Result;
const ED25519_VERIFICATION_KEY_2018_STR: &str = "Ed25519VerificationKey2018";
const X25519_KEY_AGREEMENT_KEY_2019_STR: &str = "X25519KeyAgreementKey2019";
const JSON_WEB_KEY_METHOD_TYPE: &str = "JsonWebKey";
+const ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020_STR: &str = "EcdsaSecp256k1RecoverySignature2020";
/// verification method types.
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
@@ -25,6 +26,9 @@ impl MethodType {
/// A verification method for use with JWT verification as prescribed by the [`Jwk`](::identity_jose::jwk::Jwk)
/// in the [`publicKeyJwk`](crate::MethodData::PublicKeyJwk) entry.
pub const JSON_WEB_KEY: Self = Self(Cow::Borrowed(JSON_WEB_KEY_METHOD_TYPE));
+ /// The `EcdsaSecp256k1RecoverySignature2020` method type.
+ pub const ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020: Self =
+ Self(Cow::Borrowed(ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020_STR));
}
impl MethodType {
@@ -54,6 +58,7 @@ impl FromStr for MethodType {
ED25519_VERIFICATION_KEY_2018_STR => Ok(Self::ED25519_VERIFICATION_KEY_2018),
X25519_KEY_AGREEMENT_KEY_2019_STR => Ok(Self::X25519_KEY_AGREEMENT_KEY_2019),
JSON_WEB_KEY_METHOD_TYPE => Ok(Self::JSON_WEB_KEY),
+ ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020_STR => Ok(Self::ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020),
_ => Ok(Self(Cow::Owned(string.to_owned()))),
}
}
From d51910fe3bd63146e2e22a4b0f783cf838e760ce Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Thu, 29 Feb 2024 09:57:56 +0100
Subject: [PATCH 19/23] Allow setting additional controllers for
`IotaDocument`. (#1314)
---
bindings/wasm/docs/api-reference.md | 111 +++++++-------
bindings/wasm/src/iota/iota_document.rs | 20 +++
.../src/document/iota_document.rs | 135 ++++++++++++++++--
.../src/state_metadata/document.rs | 29 +++-
4 files changed, 235 insertions(+), 60 deletions(-)
diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index e9e3a65a85..e83bbc81b6 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -187,10 +187,6 @@ working with storage backed DID documents.
## Members
-- StateMetadataEncoding
-
-- MethodRelationship
-
- CredentialStatus
- SubjectHolderRelationship
@@ -207,6 +203,9 @@ This variant is the default.
- Any
The holder is not required to have any kind of relationship to any credential subject.
+- StatusPurpose
+Purpose of a StatusList2021.
+
- FailFast
Declares when validation should return if an error occurs.
@@ -216,9 +215,6 @@ This variant is the default.
- FirstError
Return after the first error occurs.
-- StatusPurpose
-Purpose of a StatusList2021.
-
- StatusCheck
Controls validation behaviour when checking whether or not a credential has been revoked by its
credentialStatus
.
@@ -236,16 +232,17 @@ This variant is the default.
- SkipAll
Skip all status checks.
+- StateMetadataEncoding
+
+- MethodRelationship
+
## Functions
-- encodeB64(data) ⇒
string
-Encode the given bytes in url-safe base64.
-
-- decodeB64(data) ⇒
Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
+- start()
+Initializes the console error panic hook for better error messages
- verifyEd25519(alg, signingInput, decodedSignature, publicKey)
Verify a JWS signature secured with the EdDSA
algorithm and curve Ed25519
.
@@ -255,8 +252,11 @@ This variant is the default.
This function does not check whether alg = EdDSA
in the protected header. Callers are expected to assert this
prior to calling the function.
-- start()
-Initializes the console error panic hook for better error messages
+- encodeB64(data) ⇒
string
+Encode the given bytes in url-safe base64.
+
+- decodeB64(data) ⇒
Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
@@ -1967,6 +1967,7 @@ if the object is being concurrently modified.
* _instance_
* [.id()](#IotaDocument+id) ⇒ [IotaDID
](#IotaDID)
* [.controller()](#IotaDocument+controller) ⇒ [Array.<IotaDID>
](#IotaDID)
+ * [.setController(controllers)](#IotaDocument+setController)
* [.alsoKnownAs()](#IotaDocument+alsoKnownAs) ⇒ Array.<string>
* [.setAlsoKnownAs(urls)](#IotaDocument+setAlsoKnownAs)
* [.properties()](#IotaDocument+properties) ⇒ Map.<string, any>
@@ -2039,6 +2040,20 @@ NOTE: controllers are determined by the `state_controller` unlock condition of t
during resolution and are omitted when publishing.
**Kind**: instance method of [IotaDocument
](#IotaDocument)
+
+
+### iotaDocument.setController(controllers)
+Sets the controllers of the document.
+
+Note: Duplicates will be ignored.
+Use `null` to remove all controllers.
+
+**Kind**: instance method of [IotaDocument
](#IotaDocument)
+
+| Param | Type |
+| --- | --- |
+| controllers | [CoreDID
](#CoreDID) \| [Array.<CoreDID>
](#CoreDID) \| null
|
+
### iotaDocument.alsoKnownAs() ⇒ Array.<string>
@@ -6104,14 +6119,6 @@ Deserializes an instance from a JSON object.
| --- | --- |
| json | any
|
-
-
-## StateMetadataEncoding
-**Kind**: global variable
-
-
-## MethodRelationship
-**Kind**: global variable
## CredentialStatus
@@ -6142,6 +6149,12 @@ The holder must match the subject only for credentials where the [`nonTransferab
## Any
The holder is not required to have any kind of relationship to any credential subject.
+**Kind**: global variable
+
+
+## StatusPurpose
+Purpose of a [StatusList2021](#StatusList2021).
+
**Kind**: global variable
@@ -6160,12 +6173,6 @@ Return all errors that occur during validation.
## FirstError
Return after the first error occurs.
-**Kind**: global variable
-
-
-## StatusPurpose
-Purpose of a [StatusList2021](#StatusList2021).
-
**Kind**: global variable
@@ -6198,28 +6205,20 @@ Validate the status if supported, skip any unsupported
Skip all status checks.
**Kind**: global variable
-
-
-## encodeB64(data) ⇒ string
-Encode the given bytes in url-safe base64.
-
-**Kind**: global function
+
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
+## StateMetadataEncoding
+**Kind**: global variable
+
-
+## MethodRelationship
+**Kind**: global variable
+
-## decodeB64(data) ⇒ Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
+## start()
+Initializes the console error panic hook for better error messages
**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
-
## verifyEd25519(alg, signingInput, decodedSignature, publicKey)
@@ -6242,9 +6241,25 @@ prior to calling the function.
| decodedSignature | Uint8Array
|
| publicKey | [Jwk
](#Jwk) |
-
+
-## start()
-Initializes the console error panic hook for better error messages
+## encodeB64(data) ⇒ string
+Encode the given bytes in url-safe base64.
+
+**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
+
+
+
+## decodeB64(data) ⇒ Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
**Kind**: global function
+
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
+
diff --git a/bindings/wasm/src/iota/iota_document.rs b/bindings/wasm/src/iota/iota_document.rs
index 8f8cbe6823..8d004422ad 100644
--- a/bindings/wasm/src/iota/iota_document.rs
+++ b/bindings/wasm/src/iota/iota_document.rs
@@ -5,12 +5,14 @@ use std::rc::Rc;
use identity_iota::core::Object;
use identity_iota::core::OneOrMany;
+
use identity_iota::core::OrderedSet;
use identity_iota::core::Timestamp;
use identity_iota::core::Url;
use identity_iota::credential::Credential;
use identity_iota::credential::JwtPresentationOptions;
use identity_iota::credential::Presentation;
+
use identity_iota::did::DIDUrl;
use identity_iota::iota::block::output::dto::AliasOutputDto;
use identity_iota::iota::block::output::AliasOutput;
@@ -48,6 +50,7 @@ use crate::credential::WasmJws;
use crate::credential::WasmJwt;
use crate::credential::WasmPresentation;
use crate::did::CoreDocumentLock;
+
use crate::did::PromiseJws;
use crate::did::PromiseJwt;
use crate::did::WasmCoreDocument;
@@ -156,6 +159,20 @@ impl WasmIotaDocument {
)
}
+ /// Sets the controllers of the document.
+ ///
+ /// Note: Duplicates will be ignored.
+ /// Use `null` to remove all controllers.
+ #[wasm_bindgen(js_name = setController)]
+ pub fn set_controller(&mut self, controller: &OptionArrayIotaDID) -> Result<()> {
+ let controller: Option> = controller.into_serde().wasm_result()?;
+ match controller {
+ Some(controller) => self.0.try_write()?.set_controller(controller),
+ None => self.0.try_write()?.set_controller([]),
+ };
+ Ok(())
+ }
+
/// Returns a copy of the document's `alsoKnownAs` set.
#[wasm_bindgen(js_name = alsoKnownAs)]
pub fn also_known_as(&self) -> Result {
@@ -845,6 +862,9 @@ impl From for WasmIotaDocument {
#[wasm_bindgen]
extern "C" {
+ #[wasm_bindgen(typescript_type = "IotaDID[] | null")]
+ pub type OptionArrayIotaDID;
+
#[wasm_bindgen(typescript_type = "IotaDID[]")]
pub type ArrayIotaDID;
diff --git a/identity_iota_core/src/document/iota_document.rs b/identity_iota_core/src/document/iota_document.rs
index 89abf06cf5..7ae60381d7 100644
--- a/identity_iota_core/src/document/iota_document.rs
+++ b/identity_iota_core/src/document/iota_document.rs
@@ -5,7 +5,6 @@ use core::fmt;
use core::fmt::Debug;
use core::fmt::Display;
use identity_credential::credential::Jws;
-#[cfg(feature = "client")]
use identity_did::CoreDID;
use identity_did::DIDUrl;
use identity_document::verifiable::JwsVerificationOptions;
@@ -15,7 +14,6 @@ use serde::Deserialize;
use serde::Serialize;
use identity_core::common::Object;
-#[cfg(feature = "client")]
use identity_core::common::OneOrSet;
use identity_core::common::OrderedSet;
use identity_core::common::Url;
@@ -123,9 +121,6 @@ impl IotaDocument {
}
/// Returns an iterator yielding the DID controllers.
- ///
- /// NOTE: controllers are determined by the `state_controller` unlock condition of the output
- /// during resolution and are omitted when publishing.
pub fn controller(&self) -> impl Iterator- + '_ {
let core_did_controller_iter = self
.document
@@ -134,11 +129,31 @@ impl IotaDocument {
.into_iter()
.flatten();
- // CORRECTNESS: These casts are OK because the public API does not expose methods
- // enabling unchecked mutation of the controllers.
+ // CORRECTNESS: These casts are OK because the public API only allows setting IotaDIDs.
core_did_controller_iter.map(IotaDID::from_inner_ref_unchecked)
}
+ /// Sets the value of the document controller.
+ ///
+ /// Note:
+ /// * Duplicates in `controller` will be ignored.
+ /// * Use an empty collection to clear all controllers.
+ pub fn set_controller(&mut self, controller: T)
+ where
+ T: IntoIterator
- ,
+ {
+ let controller_core_dids: Option> = {
+ let controller_set: OrderedSet = controller.into_iter().map(CoreDID::from).collect();
+ if controller_set.is_empty() {
+ None
+ } else {
+ Some(OneOrSet::new_set(controller_set).expect("controller is checked to be not empty"))
+ }
+ };
+
+ *self.document.controller_mut() = controller_core_dids;
+ }
+
/// Returns a reference to the `alsoKnownAs` set.
pub fn also_known_as(&self) -> &OrderedSet {
self.document.also_known_as()
@@ -442,7 +457,14 @@ mod client_document {
_ => None,
};
- *self.core_document_mut().controller_mut() = controller_did.map(CoreDID::from).map(OneOrSet::new_one);
+ if let Some(controller_did) = controller_did {
+ match self.core_document_mut().controller_mut() {
+ Some(controllers) => {
+ controllers.append(CoreDID::from(controller_did));
+ }
+ None => *self.core_document_mut().controller_mut() = Some(OneOrSet::new_one(CoreDID::from(controller_did))),
+ }
+ }
Ok(())
}
@@ -731,6 +753,98 @@ mod tests {
assert_eq!(doc1, doc2);
}
+ #[test]
+ fn test_unpack_no_external_controller() {
+ let document_did: IotaDID = "did:iota:0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ .parse()
+ .unwrap();
+ let alias_controller: IotaDID = "did:iota:0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+ .parse()
+ .unwrap();
+
+ let mut original_doc: IotaDocument = IotaDocument::new_with_id(document_did.clone());
+ original_doc.set_controller([]);
+
+ let alias_output: AliasOutput = AliasOutputBuilder::new_with_amount(1, AliasId::from(&document_did))
+ .with_state_metadata(original_doc.pack().unwrap())
+ .add_unlock_condition(UnlockCondition::StateControllerAddress(
+ StateControllerAddressUnlockCondition::new(Address::Alias(AliasAddress::new(AliasId::from(&alias_controller)))),
+ ))
+ .add_unlock_condition(UnlockCondition::GovernorAddress(GovernorAddressUnlockCondition::new(
+ Address::Alias(AliasAddress::new(AliasId::from(&alias_controller))),
+ )))
+ .finish()
+ .unwrap();
+
+ let document: IotaDocument = IotaDocument::unpack_from_output(&document_did, &alias_output, true).unwrap();
+ let controllers: Vec = document.controller().cloned().collect::>();
+ assert_eq!(controllers.first().unwrap(), &alias_controller);
+ assert_eq!(controllers.len(), 1);
+ }
+
+ #[test]
+ fn test_unpack_with_duplicate_controller() {
+ let document_did: IotaDID = "did:iota:0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ .parse()
+ .unwrap();
+ let alias_controller: IotaDID = "did:iota:0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+ .parse()
+ .unwrap();
+
+ let mut original_doc: IotaDocument = IotaDocument::new_with_id(document_did.clone());
+ original_doc.set_controller([alias_controller.clone()]);
+
+ let alias_output: AliasOutput = AliasOutputBuilder::new_with_amount(1, AliasId::from(&document_did))
+ .with_state_metadata(original_doc.pack().unwrap())
+ .add_unlock_condition(UnlockCondition::StateControllerAddress(
+ StateControllerAddressUnlockCondition::new(Address::Alias(AliasAddress::new(AliasId::from(&alias_controller)))),
+ ))
+ .add_unlock_condition(UnlockCondition::GovernorAddress(GovernorAddressUnlockCondition::new(
+ Address::Alias(AliasAddress::new(AliasId::from(&alias_controller))),
+ )))
+ .finish()
+ .unwrap();
+
+ let document: IotaDocument = IotaDocument::unpack_from_output(&document_did, &alias_output, true).unwrap();
+ let controllers: Vec = document.controller().cloned().collect::>();
+ assert_eq!(controllers.first().unwrap(), &alias_controller);
+ assert_eq!(controllers.len(), 1);
+ }
+
+ #[test]
+ fn test_unpack_with_external_controller() {
+ let document_did: IotaDID = "did:iota:0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ .parse()
+ .unwrap();
+ let alias_controller: IotaDID = "did:iota:0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+ .parse()
+ .unwrap();
+ let external_controller_did: IotaDID =
+ "did:iota:0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
+ .parse()
+ .unwrap();
+
+ let mut original_doc: IotaDocument = IotaDocument::new_with_id(document_did.clone());
+ original_doc.set_controller([external_controller_did.clone()]);
+
+ let alias_output: AliasOutput = AliasOutputBuilder::new_with_amount(1, AliasId::from(&document_did))
+ .with_state_metadata(original_doc.pack().unwrap())
+ .add_unlock_condition(UnlockCondition::StateControllerAddress(
+ StateControllerAddressUnlockCondition::new(Address::Alias(AliasAddress::new(AliasId::from(&alias_controller)))),
+ ))
+ .add_unlock_condition(UnlockCondition::GovernorAddress(GovernorAddressUnlockCondition::new(
+ Address::Alias(AliasAddress::new(AliasId::from(&alias_controller))),
+ )))
+ .finish()
+ .unwrap();
+
+ let document: IotaDocument = IotaDocument::unpack_from_output(&document_did, &alias_output, true).unwrap();
+ let controllers: Vec = document.controller().cloned().collect::>();
+ assert_eq!(controllers.first().unwrap(), &external_controller_did);
+ assert_eq!(controllers.get(1).unwrap(), &alias_controller);
+ assert_eq!(controllers.len(), 2);
+ }
+
#[test]
fn test_unpack_empty() {
let controller_did: IotaDID = valid_did();
@@ -765,7 +879,10 @@ mod tests {
let packed: Vec = document.pack_with_encoding(StateMetadataEncoding::Json).unwrap();
let state_metadata_document: StateMetadataDocument = StateMetadataDocument::unpack(&packed).unwrap();
let unpacked_document: IotaDocument = state_metadata_document.into_iota_document(&did).unwrap();
- assert!(unpacked_document.document.controller().is_none());
+ assert_eq!(
+ unpacked_document.document.controller().unwrap().get(0).unwrap().clone(),
+ CoreDID::from(controller_did)
+ );
assert!(unpacked_document.metadata.state_controller_address.is_none());
assert!(unpacked_document.metadata.governor_address.is_none());
}
diff --git a/identity_iota_core/src/state_metadata/document.rs b/identity_iota_core/src/state_metadata/document.rs
index d15f0d8d26..e14e381f5b 100644
--- a/identity_iota_core/src/state_metadata/document.rs
+++ b/identity_iota_core/src/state_metadata/document.rs
@@ -79,7 +79,6 @@ impl StateMetadataDocument {
// Unset Governor and State Controller Addresses to avoid bloating the payload
self.metadata.governor_address = None;
self.metadata.state_controller_address = None;
- *self.document.controller_mut() = None;
let encoded_message_data: Vec = match encoding {
StateMetadataEncoding::Json => self
@@ -410,8 +409,7 @@ mod tests {
let TestSetup { document, .. } = test_document();
let mut state_metadata_doc: StateMetadataDocument = StateMetadataDocument::from(document);
let packed: Vec = state_metadata_doc.clone().pack(StateMetadataEncoding::Json).unwrap();
- // Controller and State Controller are set to None when packing
- *state_metadata_doc.document.controller_mut() = None;
+ // Governor and State Controller are set to None when packing
state_metadata_doc.metadata.governor_address = None;
state_metadata_doc.metadata.state_controller_address = None;
let expected_payload: String = format!(
@@ -434,6 +432,31 @@ mod tests {
assert_eq!(&packed[7..], expected_payload.as_bytes());
}
+ #[test]
+ fn test_no_controller() {
+ let TestSetup {
+ mut document, did_self, ..
+ } = test_document();
+ *document.core_document_mut().controller_mut() = None;
+ let state_metadata_doc: StateMetadataDocument = StateMetadataDocument::from(document);
+ let packed: Vec = state_metadata_doc.clone().pack(StateMetadataEncoding::Json).unwrap();
+ let expected_payload: String = format!(
+ "{{\"doc\":{},\"meta\":{}}}",
+ state_metadata_doc.document, state_metadata_doc.metadata
+ );
+ assert_eq!(&packed[7..], expected_payload.as_bytes());
+ let unpacked = StateMetadataDocument::unpack(&packed).unwrap();
+ assert_eq!(
+ unpacked
+ .into_iota_document(&did_self)
+ .unwrap()
+ .controller()
+ .collect::>()
+ .len(),
+ 0
+ );
+ }
+
#[test]
fn test_unpack_length_prefix() {
// Changing the serialization is a breaking change!
From 4f0db112506d7063bb60af3754b2b867c552ed82 Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Thu, 29 Feb 2024 11:50:47 +0100
Subject: [PATCH 20/23] Fix example crate compilation with
`--no-default-features` (#1317)
---
examples/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index a9337d6a33..81dcc688bd 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
[dependencies]
anyhow = "1.0.62"
identity_eddsa_verifier = { path = "../identity_eddsa_verifier", default-features = false }
-identity_iota = { path = "../identity_iota", default-features = false, features = ["memstore", "domain-linkage", "revocation-bitmap", "status-list-2021"] }
+identity_iota = { path = "../identity_iota", default-features = false, features = ["iota-client", "client", "memstore", "domain-linkage", "revocation-bitmap", "status-list-2021"] }
identity_stronghold = { path = "../identity_stronghold", default-features = false }
iota-sdk = { version = "1.0", default-features = false, features = ["tls", "client", "stronghold"] }
primitive-types = "0.12.1"
From 28cc8c64194917040a35ec15b5c3c87a28baa16c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eike=20Ha=C3=9F?=
Date: Thu, 29 Feb 2024 13:31:12 +0100
Subject: [PATCH 21/23] Include examples in cargo check (#1319)
---
.github/workflows/build-and-test.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index d60c351e6c..a58316790f 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -101,7 +101,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
cargo metadata --format-version 1 | \
- jq -r '.workspace_members[] | select(contains("examples") | not)' | \
+ jq -r '.workspace_members[]' | \
awk '{print $1}' | \
xargs -I {} cargo check -p {} --no-default-features
@@ -109,7 +109,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
cargo metadata --format-version 1 | \
- jq -r '.workspace_members[] | select(contains("examples") | not)' | \
+ jq -r '.workspace_members[]' | \
awk '{print $1}' | \
xargs -I {} cargo check -p {}
From 59d38f77e8460c1b5da55d751eec0cb88f315d9d Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Wed, 6 Mar 2024 10:56:23 +0100
Subject: [PATCH 22/23] Add constructor for VerificationMethod in TS (#1321)
---
bindings/wasm/docs/api-reference.md | 196 ++++++++++--------
.../verification/wasm_verification_method.rs | 19 ++
2 files changed, 124 insertions(+), 91 deletions(-)
diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index e83bbc81b6..8eede47999 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -187,8 +187,23 @@ working with storage backed DID documents.
## Members
-- CredentialStatus
-
+- StatusCheck
+Controls validation behaviour when checking whether or not a credential has been revoked by its
+credentialStatus
.
+
+- Strict
+Validate the status if supported, reject any unsupported
+credentialStatus
types.
+Only RevocationBitmap2022
is currently supported.
+This is the default.
+
+- SkipUnsupported
+Validate the status if supported, skip any unsupported
+credentialStatus
types.
+
+- SkipAll
+Skip all status checks.
+
- SubjectHolderRelationship
Declares how credential subjects must relate to the presentation holder.
See also the Subject-Holder Relationship section of the specification.
@@ -203,9 +218,10 @@ This variant is the default.
- Any
The holder is not required to have any kind of relationship to any credential subject.
-- StatusPurpose
-Purpose of a StatusList2021.
-
+- StateMetadataEncoding
+
+- MethodRelationship
+
- FailFast
Declares when validation should return if an error occurs.
@@ -215,34 +231,21 @@ This variant is the default.
- FirstError
Return after the first error occurs.
-- StatusCheck
-Controls validation behaviour when checking whether or not a credential has been revoked by its
-credentialStatus
.
-
-- Strict
-Validate the status if supported, reject any unsupported
-credentialStatus
types.
-Only RevocationBitmap2022
is currently supported.
-This is the default.
-
-- SkipUnsupported
-Validate the status if supported, skip any unsupported
-credentialStatus
types.
-
-- SkipAll
-Skip all status checks.
-
-- StateMetadataEncoding
-
-- MethodRelationship
+- CredentialStatus
+- StatusPurpose
+Purpose of a StatusList2021.
+
## Functions
-- start()
-Initializes the console error panic hook for better error messages
+- encodeB64(data) ⇒
string
+Encode the given bytes in url-safe base64.
+
+- decodeB64(data) ⇒
Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
- verifyEd25519(alg, signingInput, decodedSignature, publicKey)
Verify a JWS signature secured with the EdDSA
algorithm and curve Ed25519
.
@@ -252,11 +255,8 @@ This variant is the default.
This function does not check whether alg = EdDSA
in the protected header. Callers are expected to assert this
prior to calling the function.
-- encodeB64(data) ⇒
string
-Encode the given bytes in url-safe base64.
-
-- decodeB64(data) ⇒
Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
+- start()
+Initializes the console error panic hook for better error messages
@@ -1967,7 +1967,7 @@ if the object is being concurrently modified.
* _instance_
* [.id()](#IotaDocument+id) ⇒ [IotaDID
](#IotaDID)
* [.controller()](#IotaDocument+controller) ⇒ [Array.<IotaDID>
](#IotaDID)
- * [.setController(controllers)](#IotaDocument+setController)
+ * [.setController(controller)](#IotaDocument+setController)
* [.alsoKnownAs()](#IotaDocument+alsoKnownAs) ⇒ Array.<string>
* [.setAlsoKnownAs(urls)](#IotaDocument+setAlsoKnownAs)
* [.properties()](#IotaDocument+properties) ⇒ Map.<string, any>
@@ -2042,7 +2042,7 @@ during resolution and are omitted when publishing.
**Kind**: instance method of [IotaDocument
](#IotaDocument)
-### iotaDocument.setController(controllers)
+### iotaDocument.setController(controller)
Sets the controllers of the document.
Note: Duplicates will be ignored.
@@ -2052,7 +2052,7 @@ Use `null` to remove all controllers.
| Param | Type |
| --- | --- |
-| controllers | [CoreDID
](#CoreDID) \| [Array.<CoreDID>
](#CoreDID) \| null
|
+| controller | [Array.<IotaDID>
](#IotaDID) \| null
|
@@ -5967,6 +5967,7 @@ A DID Document Verification Method.
**Kind**: global class
* [VerificationMethod](#VerificationMethod)
+ * [new VerificationMethod(id, controller, type_, data)](#new_VerificationMethod_new)
* _instance_
* [.id()](#VerificationMethod+id) ⇒ [DIDUrl
](#DIDUrl)
* [.setId(id)](#VerificationMethod+setId)
@@ -5984,6 +5985,19 @@ A DID Document Verification Method.
* [.newFromJwk(did, key, [fragment])](#VerificationMethod.newFromJwk) ⇒ [VerificationMethod
](#VerificationMethod)
* [.fromJSON(json)](#VerificationMethod.fromJSON) ⇒ [VerificationMethod
](#VerificationMethod)
+
+
+### new VerificationMethod(id, controller, type_, data)
+Create a custom [VerificationMethod](#VerificationMethod).
+
+
+| Param | Type |
+| --- | --- |
+| id | [DIDUrl
](#DIDUrl) |
+| controller | [CoreDID
](#CoreDID) |
+| type_ | [MethodType
](#MethodType) |
+| data | [MethodData
](#MethodData) |
+
### verificationMethod.id() ⇒ [DIDUrl
](#DIDUrl)
@@ -6119,9 +6133,36 @@ Deserializes an instance from a JSON object.
| --- | --- |
| json | any
|
-
+
+
+## StatusCheck
+Controls validation behaviour when checking whether or not a credential has been revoked by its
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status).
+
+**Kind**: global variable
+
+
+## Strict
+Validate the status if supported, reject any unsupported
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+
+Only `RevocationBitmap2022` is currently supported.
+
+This is the default.
+
+**Kind**: global variable
+
+
+## SkipUnsupported
+Validate the status if supported, skip any unsupported
+[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+
+**Kind**: global variable
+
+
+## SkipAll
+Skip all status checks.
-## CredentialStatus
**Kind**: global variable
@@ -6150,11 +6191,13 @@ The holder must match the subject only for credentials where the [`nonTransferab
The holder is not required to have any kind of relationship to any credential subject.
**Kind**: global variable
-
+
-## StatusPurpose
-Purpose of a [StatusList2021](#StatusList2021).
+## StateMetadataEncoding
+**Kind**: global variable
+
+## MethodRelationship
**Kind**: global variable
@@ -6174,51 +6217,38 @@ Return all errors that occur during validation.
Return after the first error occurs.
**Kind**: global variable
-
-
-## StatusCheck
-Controls validation behaviour when checking whether or not a credential has been revoked by its
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status).
+
+## CredentialStatus
**Kind**: global variable
-
-
-## Strict
-Validate the status if supported, reject any unsupported
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
-
-Only `RevocationBitmap2022` is currently supported.
+
-This is the default.
+## StatusPurpose
+Purpose of a [StatusList2021](#StatusList2021).
**Kind**: global variable
-
+
-## SkipUnsupported
-Validate the status if supported, skip any unsupported
-[`credentialStatus`](https://www.w3.org/TR/vc-data-model/#status) types.
+## encodeB64(data) ⇒ string
+Encode the given bytes in url-safe base64.
-**Kind**: global variable
-
+**Kind**: global function
-## SkipAll
-Skip all status checks.
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
-**Kind**: global variable
-
+
-## StateMetadataEncoding
-**Kind**: global variable
-
+## decodeB64(data) ⇒ Uint8Array
+Decode the given url-safe base64-encoded slice into its raw bytes.
-## MethodRelationship
-**Kind**: global variable
-
+**Kind**: global function
-## start()
-Initializes the console error panic hook for better error messages
+| Param | Type |
+| --- | --- |
+| data | Uint8Array
|
-**Kind**: global function
## verifyEd25519(alg, signingInput, decodedSignature, publicKey)
@@ -6241,25 +6271,9 @@ prior to calling the function.
| decodedSignature | Uint8Array
|
| publicKey | [Jwk
](#Jwk) |
-
-
-## encodeB64(data) ⇒ string
-Encode the given bytes in url-safe base64.
-
-**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
-
-
+
-## decodeB64(data) ⇒ Uint8Array
-Decode the given url-safe base64-encoded slice into its raw bytes.
+## start()
+Initializes the console error panic hook for better error messages
**Kind**: global function
-
-| Param | Type |
-| --- | --- |
-| data | Uint8Array
|
-
diff --git a/bindings/wasm/src/verification/wasm_verification_method.rs b/bindings/wasm/src/verification/wasm_verification_method.rs
index 62b5103c9d..6f01436ffe 100644
--- a/bindings/wasm/src/verification/wasm_verification_method.rs
+++ b/bindings/wasm/src/verification/wasm_verification_method.rs
@@ -8,6 +8,7 @@ use crate::did::WasmCoreDID;
use crate::did::WasmDIDUrl;
use crate::error::Result;
use crate::error::WasmResult;
+use identity_iota::core::Object;
use identity_iota::did::CoreDID;
use identity_iota::verification::VerificationMethod;
use wasm_bindgen::prelude::*;
@@ -37,6 +38,24 @@ impl WasmVerificationMethod {
.wasm_result()
}
+ /// Create a custom {@link VerificationMethod}.
+ #[wasm_bindgen(constructor)]
+ pub fn new(
+ id: &WasmDIDUrl,
+ controller: &WasmCoreDID,
+ type_: &WasmMethodType,
+ data: &WasmMethodData,
+ ) -> Result {
+ VerificationMethod::builder(Object::new())
+ .type_(type_.0.clone())
+ .data(data.0.clone())
+ .controller(controller.0.clone())
+ .id(id.0.clone())
+ .build()
+ .map(Self)
+ .wasm_result()
+ }
+
/// Returns a copy of the {@link DIDUrl} of the {@link VerificationMethod}'s `id`.
#[wasm_bindgen]
pub fn id(&self) -> WasmDIDUrl {
From 0794379be3c18894745e5acad09488bdb3c773c6 Mon Sep 17 00:00:00 2001
From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com>
Date: Wed, 6 Mar 2024 14:16:00 +0100
Subject: [PATCH 23/23] Wasm bindings for `BlockChainAccountId` verification
method. (#1326)
---
bindings/wasm/docs/api-reference.md | 120 +++++++++++-------
.../wasm/src/verification/wasm_method_data.rs | 20 +++
.../wasm/src/verification/wasm_method_type.rs | 6 +
.../src/verification_method/material.rs | 14 ++
4 files changed, 113 insertions(+), 47 deletions(-)
diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md
index 8eede47999..73ff47d4c6 100644
--- a/bindings/wasm/docs/api-reference.md
+++ b/bindings/wasm/docs/api-reference.md
@@ -204,6 +204,24 @@ working with storage backed DID documents.
- SkipAll
Skip all status checks.
+- StatusPurpose
+Purpose of a StatusList2021.
+
+- MethodRelationship
+
+- CredentialStatus
+
+- StateMetadataEncoding
+
+- FailFast
+Declares when validation should return if an error occurs.
+
+- AllErrors
+Return all errors that occur during validation.
+
+- FirstError
+Return after the first error occurs.
+
- SubjectHolderRelationship
Declares how credential subjects must relate to the presentation holder.
See also the Subject-Holder Relationship section of the specification.
@@ -218,24 +236,6 @@ This variant is the default.
- Any
The holder is not required to have any kind of relationship to any credential subject.
-- StateMetadataEncoding
-
-- MethodRelationship
-
-- FailFast
-Declares when validation should return if an error occurs.
-
-- AllErrors
-Return all errors that occur during validation.
-
-- FirstError
-Return after the first error occurs.
-
-- CredentialStatus
-
-- StatusPurpose
-Purpose of a StatusList2021.
-
## Functions
@@ -4343,6 +4343,7 @@ Supported verification method data formats.
* [MethodData](#MethodData)
* _instance_
+ * [.tryBlockchainAccountId()](#MethodData+tryBlockchainAccountId) ⇒ string
* [.tryDecode()](#MethodData+tryDecode) ⇒ Uint8Array
* [.tryPublicKeyJwk()](#MethodData+tryPublicKeyJwk) ⇒ [Jwk
](#Jwk)
* [.toJSON()](#MethodData+toJSON) ⇒ any
@@ -4351,8 +4352,15 @@ Supported verification method data formats.
* [.newBase58(data)](#MethodData.newBase58) ⇒ [MethodData
](#MethodData)
* [.newMultibase(data)](#MethodData.newMultibase) ⇒ [MethodData
](#MethodData)
* [.newJwk(key)](#MethodData.newJwk) ⇒ [MethodData
](#MethodData)
+ * [.newBlockchainAccountId(data)](#MethodData.newBlockchainAccountId) ⇒ [MethodData
](#MethodData)
* [.fromJSON(json)](#MethodData.fromJSON) ⇒ [MethodData
](#MethodData)
+
+
+### methodData.tryBlockchainAccountId() ⇒ string
+Returns the wrapped blockchain account id if the format is `BlockchainAccountId`.
+
+**Kind**: instance method of [MethodData
](#MethodData)
### methodData.tryDecode() ⇒ Uint8Array
@@ -4419,6 +4427,17 @@ An error is thrown if the given `key` contains any private components.
| --- | --- |
| key | [Jwk
](#Jwk) |
+
+
+### MethodData.newBlockchainAccountId(data) ⇒ [MethodData
](#MethodData)
+Creates a new [MethodData](#MethodData) variant in CAIP-10 format.
+
+**Kind**: static method of [MethodData
](#MethodData)
+
+| Param | Type |
+| --- | --- |
+| data | string
|
+
### MethodData.fromJSON(json) ⇒ [MethodData
](#MethodData)
@@ -4570,6 +4589,7 @@ Supported verification method types.
* [.Ed25519VerificationKey2018()](#MethodType.Ed25519VerificationKey2018) ⇒ [MethodType
](#MethodType)
* [.X25519KeyAgreementKey2019()](#MethodType.X25519KeyAgreementKey2019) ⇒ [MethodType
](#MethodType)
* [.JsonWebKey()](#MethodType.JsonWebKey) ⇒ [MethodType
](#MethodType)
+ * [.EcdsaSecp256k1RecoverySignature2020()](#MethodType.EcdsaSecp256k1RecoverySignature2020) ⇒ [MethodType
](#MethodType)
* [.fromJSON(json)](#MethodType.fromJSON) ⇒ [MethodType
](#MethodType)
@@ -4604,6 +4624,12 @@ Deep clones the object.
A verification method for use with JWT verification as prescribed by the [Jwk](#Jwk)
in the `publicKeyJwk` entry.
+**Kind**: static method of [MethodType
](#MethodType)
+
+
+### MethodType.EcdsaSecp256k1RecoverySignature2020() ⇒ [MethodType
](#MethodType)
+The `EcdsaSecp256k1RecoverySignature2020` method type.
+
**Kind**: static method of [MethodType
](#MethodType)
@@ -6164,41 +6190,24 @@ Validate the status if supported, skip any unsupported
Skip all status checks.
**Kind**: global variable
-
-
-## SubjectHolderRelationship
-Declares how credential subjects must relate to the presentation holder.
-
-See also the [Subject-Holder Relationship](https://www.w3.org/TR/vc-data-model/#subject-holder-relationships) section of the specification.
-
-**Kind**: global variable
-
+
-## AlwaysSubject
-The holder must always match the subject on all credentials, regardless of their [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property.
-This variant is the default.
+## StatusPurpose
+Purpose of a [StatusList2021](#StatusList2021).
**Kind**: global variable
-
-
-## SubjectOnNonTransferable
-The holder must match the subject only for credentials where the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property is `true`.
+
+## MethodRelationship
**Kind**: global variable
-
-
-## Any
-The holder is not required to have any kind of relationship to any credential subject.
+
+## CredentialStatus
**Kind**: global variable
## StateMetadataEncoding
**Kind**: global variable
-
-
-## MethodRelationship
-**Kind**: global variable
## FailFast
@@ -6217,14 +6226,31 @@ Return all errors that occur during validation.
Return after the first error occurs.
**Kind**: global variable
-
+
+
+## SubjectHolderRelationship
+Declares how credential subjects must relate to the presentation holder.
+
+See also the [Subject-Holder Relationship](https://www.w3.org/TR/vc-data-model/#subject-holder-relationships) section of the specification.
-## CredentialStatus
**Kind**: global variable
-
+
-## StatusPurpose
-Purpose of a [StatusList2021](#StatusList2021).
+## AlwaysSubject
+The holder must always match the subject on all credentials, regardless of their [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property.
+This variant is the default.
+
+**Kind**: global variable
+
+
+## SubjectOnNonTransferable
+The holder must match the subject only for credentials where the [`nonTransferable`](https://www.w3.org/TR/vc-data-model/#nontransferable-property) property is `true`.
+
+**Kind**: global variable
+
+
+## Any
+The holder is not required to have any kind of relationship to any credential subject.
**Kind**: global variable
diff --git a/bindings/wasm/src/verification/wasm_method_data.rs b/bindings/wasm/src/verification/wasm_method_data.rs
index 5bba4aa5a9..809eab22e4 100644
--- a/bindings/wasm/src/verification/wasm_method_data.rs
+++ b/bindings/wasm/src/verification/wasm_method_data.rs
@@ -45,6 +45,26 @@ impl WasmMethodData {
Ok(Self(MethodData::PublicKeyJwk(key.0.clone())))
}
+ /// Creates a new {@link MethodData} variant in CAIP-10 format.
+ #[wasm_bindgen(js_name = newBlockchainAccountId)]
+ pub fn new_blockchain_account_id(data: String) -> Self {
+ Self(MethodData::new_blockchain_account_id(data))
+ }
+
+ /// Returns the wrapped blockchain account id if the format is `BlockchainAccountId`.
+ #[wasm_bindgen(js_name = tryBlockchainAccountId)]
+ pub fn try_blockchain_account_id(&self) -> Result {
+ self
+ .0
+ .blockchain_account_id()
+ .map(|id| id.to_string())
+ .ok_or(WasmError::new(
+ Cow::Borrowed("MethodDataFormatError"),
+ Cow::Borrowed("method data format is not BlockchainAccountId"),
+ ))
+ .wasm_result()
+ }
+
/// Returns a `Uint8Array` containing the decoded bytes of the {@link MethodData}.
///
/// This is generally a public key identified by a {@link MethodData} value.
diff --git a/bindings/wasm/src/verification/wasm_method_type.rs b/bindings/wasm/src/verification/wasm_method_type.rs
index 9fb1fff660..850ba08890 100644
--- a/bindings/wasm/src/verification/wasm_method_type.rs
+++ b/bindings/wasm/src/verification/wasm_method_type.rs
@@ -27,6 +27,12 @@ impl WasmMethodType {
WasmMethodType(MethodType::JSON_WEB_KEY)
}
+ /// The `EcdsaSecp256k1RecoverySignature2020` method type.
+ #[wasm_bindgen(js_name = EcdsaSecp256k1RecoverySignature2020)]
+ pub fn ecdsa_secp256k1_recovery_signature_2020() -> WasmMethodType {
+ WasmMethodType(MethodType::ECDSA_SECP256K1_RECOVERY_SIGNATURE_2020)
+ }
+
/// Returns the {@link MethodType} as a string.
#[allow(clippy::inherent_to_string)]
#[wasm_bindgen(js_name = toString)]
diff --git a/identity_verification/src/verification_method/material.rs b/identity_verification/src/verification_method/material.rs
index 4d5f5775aa..23a4843cc6 100644
--- a/identity_verification/src/verification_method/material.rs
+++ b/identity_verification/src/verification_method/material.rs
@@ -39,6 +39,11 @@ impl MethodData {
Self::PublicKeyMultibase(BaseEncoding::encode_multibase(&data, None))
}
+ /// Verification Material in CAIP-10 format.
+ pub fn new_blockchain_account_id(data: String) -> Self {
+ Self::BlockchainAccountId(data)
+ }
+
/// Returns a `Vec` containing the decoded bytes of the `MethodData`.
///
/// This is generally a public key identified by a `MethodType` value.
@@ -71,6 +76,15 @@ impl MethodData {
pub fn try_public_key_jwk(&self) -> Result<&Jwk> {
self.public_key_jwk().ok_or(Error::NotPublicKeyJwk)
}
+
+ /// Returns the wrapped Blockchain Account Id if the format is [`MethodData::BlockchainAccountId`].
+ pub fn blockchain_account_id(&self) -> Option<&str> {
+ if let Self::BlockchainAccountId(id) = self {
+ Some(id)
+ } else {
+ None
+ }
+ }
}
impl Debug for MethodData {