From 4e43430c221a5e6029f446a6a6bca1617745ab53 Mon Sep 17 00:00:00 2001 From: DaevMithran <61043607+DaevMithran@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:32:23 +0530 Subject: [PATCH] feat: Add verify presentation API and update StatusList APIs [DEV-2811] & [DEV-2669] (#265) * feat: Init presentation * feat: Add did:key resolver * feat: Add uniresolver && update policies * feat: Add broadcast statusList api * feat: Update swagger * feat: Add did update && deactivate operations * feat: Update swagger * fix: External db bug && api paths * feat: Support urlencoded request body * feat: Update swagger * feat: Refactor inputs * fix: Array issues with urlencoded * feat: Add credential-status update api * fix: DID update in chunks * bump deps * feat: Update credential-status and verify api's * fix: credential verify * feat: Update indices mandatory in statusUpdate * Update package-lock.json * fix: Presentation api example * fix: Minor issues * Update package-lock.json --------- Co-authored-by: Ankur Banerjee --- package-lock.json | 552 +++++++++--- package.json | 4 +- src/app.ts | 30 +- src/controllers/credentials.ts | 62 +- src/controllers/issuer.ts | 153 +++- src/controllers/revocation.ts | 96 ++- src/helpers/helpers.ts | 37 +- src/middleware/middleware.ts | 26 + src/services/connectors/verida.ts | 2 +- src/services/credentials.ts | 8 +- src/services/identity/IIdentity.ts | 22 +- src/services/identity/agent.ts | 194 ++++- src/services/identity/local.ts | 39 +- src/services/identity/postgres.ts | 66 +- src/static/custom-button.ts | 30 +- src/static/swagger.json | 1250 ++++++++++++++++++++++------ src/types/types.ts | 36 +- 17 files changed, 2061 insertions(+), 546 deletions(-) create mode 100644 src/middleware/middleware.ts diff --git a/package-lock.json b/package-lock.json index c83ae879..9caf28f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@cheqd/credential-service", - "version": "2.4.0-develop.5", + "version": "2.4.0-develop.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cheqd/credential-service", - "version": "2.4.0-develop.5", + "version": "2.4.0-develop.6", "license": "Apache-2.0", "dependencies": { - "@cheqd/did-provider-cheqd": "3.3.1", + "@cheqd/did-provider-cheqd": "^3.4.1", "@cosmjs/amino": "^0.31.0", "@cosmjs/encoding": "^0.30.1", "@logto/express": "^2.0.2", @@ -18,13 +18,13 @@ "@veramo/credential-w3c": "^5.2.0", "@veramo/data-store": "^5.2.0", "@veramo/did-manager": "^5.1.2", - "@veramo/did-provider-key": "^5.2.0", "@veramo/did-resolver": "^5.2.0", "@veramo/key-manager": "^5.1.2", "@veramo/kms-local": "^5.1.2", "@verida/account-node": "^2.3.5", "@verida/client-ts": "^2.3.5", "@verida/types": "^2.3.1", + "@verida/vda-did-resolver": "^2.3.5", "cookie-parser": "^1.4.6", "copyfiles": "^2.4.1", "cors": "^2.8.5", @@ -2488,45 +2488,34 @@ } }, "node_modules/@cheqd/did-provider-cheqd": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@cheqd/did-provider-cheqd/-/did-provider-cheqd-3.3.1.tgz", - "integrity": "sha512-hIhv8NN3ckElwiDIJW97cSNDZrFN4ItaG7FDNc9jkBZT2XwkSaPci/rizuJoTIq6dg92X8A6Xr3sGSEexy5RfQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@cheqd/did-provider-cheqd/-/did-provider-cheqd-3.4.1.tgz", + "integrity": "sha512-+NBFOoLbOCt+5iQx4W6pxtuA4FHuWK0sJvmzbU8sf5Le45lQ155SBqnm4R7uOmSk4KOG7f8T2l5uI8lL/cmwgw==", "dependencies": { - "@cheqd/sdk": "^3.5.4", + "@cheqd/sdk": "^3.5.6", "@cheqd/ts-proto": "^3.2.0", - "@cosmjs/amino": "^0.30.1", - "@cosmjs/crypto": "^0.30.1", - "@cosmjs/proto-signing": "^0.30.1", - "@cosmjs/utils": "^0.30.1", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "@digitalbazaar/vc-status-list": "^7.0.0", - "@lit-protocol/lit-node-client": "^2.2.20", + "@lit-protocol/lit-node-client": "^2.2.33", "@veramo/core": "^5.2.0", "@veramo/did-manager": "^5.1.2", "@veramo/did-provider-key": "^5.2.0", "@veramo/key-manager": "^5.1.2", "@veramo/utils": "^5.2.0", "debug": "^4.3.4", - "did-jwt": "^7.2.0", + "did-jwt": "^7.2.4", "did-resolver": "^4.1.0", "generate-password": "^1.7.0", - "uint8arrays": "^4.0.3", + "uint8arrays": "^4.0.4", "uuid": "^9.0.0" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@cheqd/did-provider-cheqd/node_modules/@cosmjs/amino": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", - "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", - "dependencies": { - "@cosmjs/crypto": "^0.30.1", - "@cosmjs/encoding": "^0.30.1", - "@cosmjs/math": "^0.30.1", - "@cosmjs/utils": "^0.30.1" - } - }, "node_modules/@cheqd/sdk": { "version": "3.5.6", "resolved": "https://registry.npmjs.org/@cheqd/sdk/-/sdk-3.5.6.tgz", @@ -2564,6 +2553,78 @@ "@cosmjs/utils": "^0.30.1" } }, + "node_modules/@cheqd/sdk/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@cheqd/sdk/node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@cheqd/sdk/node_modules/@cosmjs/proto-signing/node_modules/cosmjs-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", + "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@cheqd/sdk/node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" + }, + "node_modules/@cheqd/sdk/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/@cheqd/sdk/node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/@cheqd/ts-proto": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@cheqd/ts-proto/-/ts-proto-3.2.1.tgz", @@ -2633,7 +2694,25 @@ "@cosmjs/utils": "^0.31.0" } }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/crypto": { + "node_modules/@cosmjs/amino/node_modules/@cosmjs/encoding": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz", + "integrity": "sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==", + "dependencies": { + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" + } + }, + "node_modules/@cosmjs/amino/node_modules/@cosmjs/math": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz", + "integrity": "sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw==", + "dependencies": { + "bn.js": "^5.2.0" + } + }, + "node_modules/@cosmjs/crypto": { "version": "0.31.0", "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.0.tgz", "integrity": "sha512-UaqCe6Tgh0pe1QlZ66E13t6FlIF86QrnBXXq+EN7Xe1Rouza3fJ1ojGlPleJZkBoq3tAyYVIOOqdZIxtVj/sIQ==", @@ -2647,7 +2726,7 @@ "libsodium-wrappers-sumo": "^0.7.11" } }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/encoding": { + "node_modules/@cosmjs/crypto/node_modules/@cosmjs/encoding": { "version": "0.31.0", "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz", "integrity": "sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==", @@ -2657,7 +2736,7 @@ "readonly-date": "^1.0.0" } }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/math": { + "node_modules/@cosmjs/crypto/node_modules/@cosmjs/math": { "version": "0.31.0", "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz", "integrity": "sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw==", @@ -2665,25 +2744,6 @@ "bn.js": "^5.2.0" } }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/utils": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0.tgz", - "integrity": "sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==" - }, - "node_modules/@cosmjs/crypto": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", - "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", - "dependencies": { - "@cosmjs/encoding": "^0.30.1", - "@cosmjs/math": "^0.30.1", - "@cosmjs/utils": "^0.30.1", - "@noble/hashes": "^1", - "bn.js": "^5.2.0", - "elliptic": "^6.5.4", - "libsodium-wrappers": "^0.7.6" - } - }, "node_modules/@cosmjs/encoding": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.30.1.tgz", @@ -2712,37 +2772,35 @@ } }, "node_modules/@cosmjs/proto-signing": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", - "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.0.tgz", + "integrity": "sha512-JNlyOJRkn8EKB9mCthkjr6lVX6eyVQ09PFdmB4/DR874E62dFTvQ+YvyKMAgN7K7Dcjj26dVlAD3f6Xs7YOGDg==", "dependencies": { - "@cosmjs/amino": "^0.30.1", - "@cosmjs/crypto": "^0.30.1", - "@cosmjs/encoding": "^0.30.1", - "@cosmjs/math": "^0.30.1", - "@cosmjs/utils": "^0.30.1", - "cosmjs-types": "^0.7.1", + "@cosmjs/amino": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/utils": "^0.31.0", + "cosmjs-types": "^0.8.0", "long": "^4.0.0" } }, - "node_modules/@cosmjs/proto-signing/node_modules/@cosmjs/amino": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", - "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", + "node_modules/@cosmjs/proto-signing/node_modules/@cosmjs/encoding": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.0.tgz", + "integrity": "sha512-NYGQDRxT7MIRSlcbAezwxK0FqnaSPKCH7O32cmfpHNWorFxhy9lwmBoCvoe59Kd0HmArI4h+NGzLEfX3OLnA4Q==", "dependencies": { - "@cosmjs/crypto": "^0.30.1", - "@cosmjs/encoding": "^0.30.1", - "@cosmjs/math": "^0.30.1", - "@cosmjs/utils": "^0.30.1" + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" } }, - "node_modules/@cosmjs/proto-signing/node_modules/cosmjs-types": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", - "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "node_modules/@cosmjs/proto-signing/node_modules/@cosmjs/math": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.0.tgz", + "integrity": "sha512-Sb/8Ry/+gKJaYiV6X8q45kxXC9FoV98XCY1WXtu0JQwOi61VCG2VXsURQnVvZ/EhR/CuT/swOlNKrqEs3da0fw==", "dependencies": { - "long": "^4.0.0", - "protobufjs": "~6.11.2" + "bn.js": "^5.2.0" } }, "node_modules/@cosmjs/proto-signing/node_modules/long": { @@ -2750,31 +2808,6 @@ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, - "node_modules/@cosmjs/proto-signing/node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, "node_modules/@cosmjs/socket": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.30.1.tgz", @@ -2816,6 +2849,39 @@ "@cosmjs/utils": "^0.30.1" } }, + "node_modules/@cosmjs/stargate/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@cosmjs/stargate/node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@cosmjs/stargate/node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" + }, "node_modules/@cosmjs/stargate/node_modules/cosmjs-types": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", @@ -2880,11 +2946,30 @@ "xstream": "^11.14.0" } }, - "node_modules/@cosmjs/utils": { + "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@cosmjs/tendermint-rpc/node_modules/@cosmjs/utils": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" }, + "node_modules/@cosmjs/utils": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.0.tgz", + "integrity": "sha512-nNcycZWUYLNJlrIXgpcgVRqdl6BXjF4YlXdxobQWpW9Tikk61bEGeAFhDYtC0PwHlokCNw0KxWiHGJL4nL7Q5A==" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -6170,6 +6255,172 @@ "tslib": "^2.3.0" } }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/@cosmjs/amino": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", + "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", + "dependencies": { + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1" + } + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/cosmjs-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", + "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/@cosmjs/amino": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", + "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", + "dependencies": { + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1" + } + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/cosmjs-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", + "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/@lit-protocol/lit-node-client/node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/@lit-protocol/lit-third-party-libs": { "version": "2.2.39", "resolved": "https://registry.npmjs.org/@lit-protocol/lit-third-party-libs/-/lit-third-party-libs-2.2.39.tgz", @@ -6182,6 +6433,89 @@ "tslib": "^2.3.0" } }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/@cosmjs/amino": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", + "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", + "dependencies": { + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1" + } + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==" + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/cosmjs-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", + "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/@lit-protocol/lit-third-party-libs/node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/@lit-protocol/misc": { "version": "2.2.39", "resolved": "https://registry.npmjs.org/@lit-protocol/misc/-/misc-2.2.39.tgz", @@ -11176,9 +11510,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@walletconnect/jsonrpc-ws-connection": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.12.tgz", - "integrity": "sha512-HAcadga3Qjt1Cqy+qXEW6zjaCs8uJGdGQrqltzl3OjiK4epGZRdvSzTe63P+t/3z+D2wG+ffEPn0GVcDozmN1w==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.13.tgz", + "integrity": "sha512-mfOM7uFH4lGtQxG+XklYuFBj6dwVvseTt5/ahOkkmpcAEgz2umuzu7fTR+h5EmjQBdrmYyEBOWADbeaFNxdySg==", "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", "@walletconnect/safe-json": "^1.0.2", @@ -13004,9 +13338,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001512", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", - "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "version": "1.0.30001513", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001513.tgz", + "integrity": "sha512-pnjGJo7SOOjAGytZZ203Em95MRM8Cr6jhCXNF/FAXTpCTRTECnqQWLpiTRqrFtdYcth8hf4WECUpkezuYsMVww==", "devOptional": true, "funding": [ { @@ -14676,9 +15010,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.451", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz", - "integrity": "sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA==", + "version": "1.4.453", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.453.tgz", + "integrity": "sha512-BU8UtQz6CB3T7RIGhId4BjmjJVXQDujb0+amGL8jpcluFJr6lwspBOvkUbnttfpZCm4zFMHmjrX1QrdPWBBMjQ==", "devOptional": true }, "node_modules/elliptic": { @@ -22392,9 +22726,9 @@ "devOptional": true }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "devOptional": true }, "node_modules/node-stream-zip": { diff --git a/package.json b/package.json index a12dcd7e..049a74d2 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "README.md" ], "dependencies": { - "@cheqd/did-provider-cheqd": "3.3.1", + "@cheqd/did-provider-cheqd": "^3.4.1", "@cosmjs/amino": "^0.31.0", "@cosmjs/encoding": "^0.30.1", "@logto/express": "^2.0.2", @@ -52,13 +52,13 @@ "@veramo/credential-w3c": "^5.2.0", "@veramo/data-store": "^5.2.0", "@veramo/did-manager": "^5.1.2", - "@veramo/did-provider-key": "^5.2.0", "@veramo/did-resolver": "^5.2.0", "@veramo/key-manager": "^5.1.2", "@veramo/kms-local": "^5.1.2", "@verida/account-node": "^2.3.5", "@verida/client-ts": "^2.3.5", "@verida/types": "^2.3.1", + "@verida/vda-did-resolver": "^2.3.5", "cookie-parser": "^1.4.6", "copyfiles": "^2.4.1", "cors": "^2.8.5", diff --git a/src/app.ts b/src/app.ts index 5daca4e4..82398c74 100644 --- a/src/app.ts +++ b/src/app.ts @@ -4,7 +4,6 @@ import cors from 'cors' import swaggerUi from 'swagger-ui-express' import session from 'express-session' import cookieParser from 'cookie-parser' -import {withLogto, handleAuthRoutes } from '@logto/express' import { CredentialController } from './controllers/credentials.js' import { StoreController } from './controllers/store.js' @@ -13,7 +12,7 @@ import { CustomerController } from './controllers/customer.js' import { Authentication } from './middleware/authentication.js' import { Connection } from './database/connection/connection.js' import { RevocationController } from './controllers/revocation.js' -import { CORS_ERROR_MSG, configLogToExpress } from './types/constants.js' +import { CORS_ERROR_MSG } from './types/constants.js' import swaggerJSONDoc from './static/swagger.json' assert { type: "json" } @@ -22,6 +21,8 @@ dotenv.config() import { UserInfo } from './controllers/user_info.js' import path from 'path' +import e from 'express' +import { Middleware } from './middleware/middleware.js' let swagger_options = {} if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -42,7 +43,8 @@ class App { private middleware() { this.express.use(express.json({ limit: '50mb' })) - this.express.use(express.urlencoded({ extended: false })) + this.express.use(express.urlencoded({ extended: true })) + this.express.use(Middleware.parseUrlEncodedJson) this.express.use(Helmet()) this.express.use(cors({ origin: function(origin, callback){ @@ -61,7 +63,9 @@ class App { // Authentication funcitons/methods this.express.use(Authentication.wrapperHandleAuthRoutes) this.express.use(Authentication.withLogtoWrapper) - this.express.use(Authentication.guard) + } + if (process.env.ENABLE_EXTERNAL_DB === 'true') { + this.express.use(Authentication.guard) } this.express.use(express.text()) @@ -89,9 +93,15 @@ class App { app.post('/credential/suspend', new CredentialController().suspend) app.post('/credential/reinstate', new CredentialController().reinstate) - //credential-status - app.post('/credential-status/statusList2021/create', RevocationController.didValidator, RevocationController.statusListValidator, new RevocationController().createStatusList) - app.get('/credential-status/statusList2021/list', RevocationController.didValidator, new RevocationController().fetchStatusList) + // presentation + app.post(`/presentation/verify`, CredentialController.presentationValidator, new CredentialController().verifyPresentation) + + //revocation + app.post('/credential-status/create', RevocationController.queryValidator, RevocationController.statusListValidator, new RevocationController().createStatusList) + app.post('/credential-status/update', RevocationController.updateValidator, new RevocationController().updateStatusList) + app.post('/credential-status/publish', RevocationController.queryValidator, new RevocationController().createStatusList) + app.get('/credential-status/search', RevocationController.queryValidator, new RevocationController().fetchStatusList) + // store app.post(`/store`, new StoreController().set) app.get(`/store/:id`, new StoreController().get) @@ -99,10 +109,12 @@ class App { // issuer app.post(`/key/create`, new IssuerController().createKey) app.get(`/key/:kid`, new IssuerController().getKey) - app.post(`/did/create`, IssuerController.didValidator, new IssuerController().createDid) + app.post(`/did/create`, IssuerController.createValidator, new IssuerController().createDid) + app.post(`/did/update`, IssuerController.updateValidator, new IssuerController().updateDid) + app.post(`/did/deactivate/:did`, IssuerController.deactivateValidator, new IssuerController().deactivateDid) app.get(`/did/list`, new IssuerController().getDids) app.get(`/did/:did`, new IssuerController().getDids) - app.post(`/:did/create-resource`, IssuerController.resourceValidator, new IssuerController().createResource) + app.post(`/resource/create/:did`, IssuerController.resourceValidator, new IssuerController().createResource) // customer app.post(`/account`, new CustomerController().create) diff --git a/src/controllers/credentials.ts b/src/controllers/credentials.ts index c657e964..a636e9e8 100644 --- a/src/controllers/credentials.ts +++ b/src/controllers/credentials.ts @@ -1,7 +1,7 @@ import type { Request, Response } from 'express' import type { VerifiableCredential } from '@veramo/core' -import { check, validationResult } from 'express-validator' +import { check, query, validationResult } from 'express-validator' import { Credentials } from '../services/credentials.js' import { Identity } from '../services/identity/index.js' @@ -16,8 +16,6 @@ export class CredentialController { check('attributes') .exists().withMessage('attributes are required') .isObject().withMessage('attributes should be an object'), - check('type').optional().isArray().withMessage('type should be a string array'), - check('@context').optional().isArray().withMessage('@context should be a string array'), check('expirationDate').optional().isDate().withMessage('Invalid expiration date'), check('format').optional().isString().withMessage('Invalid credential format') ] @@ -31,7 +29,18 @@ export class CredentialController { return false }) .withMessage('Entry must be a jwt string or an credential'), - check('publish').optional().isBoolean().withMessage('publish should be a boolean value') + query('publish').optional().isBoolean().withMessage('publish should be a boolean value') + ] + + public static presentationValidator = [ + check('presentation').exists().withMessage('W3c verifiable presentation was not provided') + .custom((value) => { + if (typeof value === 'string' || typeof value === 'object') { + return true + } + return false + }) + .withMessage('Entry must be a jwt string or a presentation'), ] public async issue(request: Request, response: Response) { @@ -39,6 +48,15 @@ export class CredentialController { if (!result.isEmpty()) { return response.status(400).json({ error: result.array()[0].msg }) } + + // Handles string input instead of an array + if(typeof request.body.type === 'string') { + request.body.type = [request.body.type] + } + if(typeof request.body['@context'] === 'string') { + request.body['@context'] = [request.body['@context']] + } + try { const credential: VerifiableCredential = await Credentials.instance.issue_credential(request.body, response.locals.customerId) response.status(200).json(credential) @@ -59,7 +77,14 @@ export class CredentialController { return response.status(400).json({ error: result.array()[0].msg }) } try { - return response.status(200).json(await Credentials.instance.verify_credentials(request.body.credential, request.body.statusOptions, response.locals.customerId)) + const result = await Credentials.instance.verify_credentials(request.body.credential, request.body.statusOptions, response.locals.customerId) + if (result.error) { + return response.status(400).json({ + verified: result.verified, + error: result.error + }) + } + return response.status(200).json(result) } catch (error) { return response.status(500).json({ error: `${error}` @@ -72,9 +97,10 @@ export class CredentialController { if (!result.isEmpty()) { return response.status(400).json({ error: result.array()[0].msg }) } - + + const publish = request.query.publish === 'false' ? false : true try { - return response.status(200).json(await Identity.instance.revokeCredentials(request.body.credential, request.body.publish, response.locals.customerId)) + return response.status(200).json(await Identity.instance.revokeCredentials(request.body.credential, publish, response.locals.customerId)) } catch (error) { return response.status(500).json({ error: `${error}` @@ -111,4 +137,26 @@ export class CredentialController { }) } } + + public async verifyPresentation(request: Request, response: Response) { + const result = validationResult(request) + if (!result.isEmpty()) { + return response.status(400).json({ error: result.array()[0].msg }) + } + + try { + const result = await Identity.instance.verifyPresentation(request.body.presentation, request.body.statusOptions, response.locals.customerId) + if (result.error) { + return response.status(400).json({ + verified: result.verified, + error: result.error + }) + } + return response.status(200).json(result) + } catch (error) { + return response.status(500).json({ + error: `${error}` + }) + } + } } diff --git a/src/controllers/issuer.ts b/src/controllers/issuer.ts index abfeb2e2..bc7a5a01 100644 --- a/src/controllers/issuer.ts +++ b/src/controllers/issuer.ts @@ -1,43 +1,53 @@ import type { Request, Response } from 'express' import { check, param, validationResult } from 'express-validator' import { fromString } from 'uint8arrays' -import { DIDDocument } from 'did-resolver' +import { DIDDocument, Service, VerificationMethod } from 'did-resolver' import { v4 } from 'uuid' import { MethodSpecificIdAlgo, VerificationMethods, CheqdNetwork } from '@cheqd/sdk' import { MsgCreateResourcePayload } from '@cheqd/ts-proto/cheqd/resource/v2/index.js' import { Identity } from '../services/identity/index.js' -import { generateDidDoc, validateSpecCompliantPayload } from '../helpers/helpers.js' +import { generateDidDoc, isValidService, isValidVerificationMethod, validateSpecCompliantPayload } from '../helpers/helpers.js' export class IssuerController { - public static didValidator = [ - check('didDocument').optional().isArray().custom((value)=>{ + public static createValidator = [ + check('didDocument').optional().isObject().custom((value)=>{ const { valid } = validateSpecCompliantPayload(value) return valid }).withMessage('Invalid didDocument'), - check('secret.verificationMethod.type') + check('verificationMethodType') .optional() .isString() .isIn([VerificationMethods.Ed255192020, VerificationMethods.Ed255192018, VerificationMethods.JWK]) - .withMessage('Invalid verificationMethod'), - check('secret.verificationMethod.id') - .optional() - .isString() - .withMessage('Invalid verificationMethod'), - check('options.methodSpecificIdAlgo').optional().isString().isIn([MethodSpecificIdAlgo.Base58, MethodSpecificIdAlgo.Uuid]).withMessage('Invalid methodSpecificIdAlgo'), - check('options.network').optional().isString().isIn([CheqdNetwork.Mainnet, CheqdNetwork.Testnet]).withMessage('Invalid network'), + .withMessage('Invalid verificationMethod'), + check('methodSpecificIdAlgo').optional().isString().isIn([MethodSpecificIdAlgo.Base58, MethodSpecificIdAlgo.Uuid]).withMessage('Invalid methodSpecificIdAlgo'), + check('network').optional().isString().isIn([CheqdNetwork.Mainnet, CheqdNetwork.Testnet]).withMessage('Invalid network'), + ] + + public static updateValidator = [ + check('didDocument').custom((value, {req})=>{ + if(value) { + const { valid } = validateSpecCompliantPayload(value) + return valid + } else { + const { did, service, verificationMethod, authentication } = req.body + return did && (service || verificationMethod || authentication ) + } + }).withMessage('Provide a valid DIDDocument or a DID and atleast one field to update') + ] + + public static deactivateValidator = [ + param('did').exists().isString().contains('did:cheqd').withMessage('Invalid DID') ] public static resourceValidator = [ param('did').exists().isString().contains('did:cheqd').withMessage('Invalid DID'), - check('jobId').custom((value, {req})=>{ - if(!value && !(req.body.name && req.body.type && req.body.data)) return false - return true - }).withMessage('name, type and data are required'), - check('name').optional().isString().withMessage('Invalid name'), - check('type').optional().isString().withMessage('Invalid type'), - check('data').optional().isString().withMessage('Invalid data'), + check('name').exists().withMessage('name is required').isString().withMessage('Invalid name'), + check('type').exists().withMessage('type is required').isString().withMessage('Invalid type'), + check('data').exists().withMessage('data is required').isString().withMessage('Invalid data'), + check('encoding').exists().withMessage('encoding is required') + .isString().isIn(['hex', 'base64', 'base64url']).withMessage('Invalid encoding'), check('alsoKnownAs').optional().isArray().withMessage('Invalid alsoKnownAs'), check('alsoKnownAs.*.uri').isString().withMessage('Invalid uri'), check('alsoKnownAs.*.description').isString().withMessage('Invalid description') @@ -73,32 +83,105 @@ export class IssuerController { }) } - const { options, secret } = request.body - const { methodSpecificIdAlgo, network, versionId = v4()} = options - const verificationMethod = secret?.verificationMethod + const { methodSpecificIdAlgo, network, verificationMethodType, assertionMethod=true, serviceEndpoint } = request.body let didDocument: DIDDocument - let kids: string[] = [] try { - if (options.didDocument) { - didDocument = options.didDocument - } else if (verificationMethod) { + if (request.body.didDocument) { + didDocument = request.body.didDocument + } else if (verificationMethodType) { const key = await Identity.instance.createKey('Ed25519', response.locals.customerId) - kids.push(key.kid) didDocument = generateDidDoc({ - verificationMethod: verificationMethod.type, - verificationMethodId: verificationMethod.id || 'key-1', + verificationMethod: verificationMethodType || VerificationMethods.Ed255192018, + verificationMethodId: 'key-1', methodSpecificIdAlgo: (methodSpecificIdAlgo as MethodSpecificIdAlgo) || MethodSpecificIdAlgo.Uuid, network, publicKey: key.publicKeyHex }) - didDocument.assertionMethod = didDocument.authentication + + if (assertionMethod) { + didDocument.assertionMethod = didDocument.authentication + } + + if (serviceEndpoint) { + didDocument.service = [{ + id: `${didDocument.id}#service-1`, + type: 'service-1', + serviceEndpoint: [serviceEndpoint] + }] + } + } else { + return response.status(400).json({ + error: 'Provide a DID Document or the network type to create a DID' + }) + } + + const did = await Identity.instance.createDid(network || didDocument.id.split(':')[2], didDocument, response.locals.customerId) + return response.status(200).json(did) + } catch (error) { + return response.status(500).json({ + error: `${error}` + }) + } + } + + public async updateDid(request: Request, response: Response) { + const result = validationResult(request) + if (!result.isEmpty()) { + return response.status(400).json({ + error: result.array()[0].msg + }) + } + + try { + + const { did, service, verificationMethod, authentication } = request.body as { did: string, service: Service[], verificationMethod: VerificationMethod[], authentication: string[] } + let updatedDocument: DIDDocument + if (request.body.didDocument) { + updatedDocument = request.body.didDocument + } else if (did && (service || verificationMethod || authentication)) { + let resolvedResult = await Identity.instance.resolveDid(did) + if(!resolvedResult?.didDocument || resolvedResult.didDocumentMetadata.deactivated) { + return response.status(400).send({ + error: `${did} is either Deactivated or Not found` + }) + } + const resolvedDocument = resolvedResult.didDocument + if (service) { + resolvedDocument.service = Array.isArray(service) ? service : [service] + } + if (verificationMethod) { + resolvedDocument.verificationMethod = Array.isArray(verificationMethod) ? verificationMethod : [verificationMethod] + } + if (authentication) { + resolvedDocument.authentication = Array.isArray(authentication) ? authentication : [authentication] + } + + updatedDocument = resolvedDocument } else { return response.status(400).json({ - error: 'Provide a DID Document or atleast one verification method' + error: 'Provide a DID Document or atleast one field to update' }) } - const did = await Identity.instance.createDid(network, didDocument, response.locals.customerId) + const result = await Identity.instance.updateDid(updatedDocument, response.locals.customerId) + return response.status(200).json(result) + } catch (error) { + return response.status(500).json({ + error: `${error}` + }) + } + } + + public async deactivateDid(request: Request, response: Response) { + const result = validationResult(request) + if (!result.isEmpty()) { + return response.status(400).json({ + error: result.array()[0].msg + }) + } + + try { + const did = await Identity.instance.deactivateDid(request.params.did, response.locals.customerId) return response.status(200).json(did) } catch (error) { return response.status(500).json({ @@ -116,7 +199,7 @@ export class IssuerController { } const { did } = request.params - let { data, name, type, alsoKnownAs, version, network } = request.body + let { data, encoding, name, type, alsoKnownAs, version, network } = request.body let resourcePayload: Partial = {} try { @@ -124,7 +207,7 @@ export class IssuerController { let resolvedDocument: any = await Identity.instance.resolveDid(did) if(!resolvedDocument?.didDocument || resolvedDocument.didDocumentMetadata.deactivated) { return response.status(400).send({ - error: `${did} is a Deactivated DID` + error: `${did} is a either Deactivated or Not found` }) } else { resolvedDocument = resolvedDocument.didDocument @@ -135,7 +218,7 @@ export class IssuerController { id: v4(), name, resourceType: type, - data: fromString(data, 'base64'), + data: fromString(data, encoding), version, alsoKnownAs } diff --git a/src/controllers/revocation.ts b/src/controllers/revocation.ts index 4d7ce436..ec23e71d 100644 --- a/src/controllers/revocation.ts +++ b/src/controllers/revocation.ts @@ -4,19 +4,34 @@ import { fromString } from 'uint8arrays' import { Identity } from '../services/identity/index.js' import { Veramo } from '../services/identity/agent.js' -import { ResourceMetadata } from '../types/types.js' +import { ResourceMetadata, StatusList2021ResourceTypes } from '../types/types.js' export class RevocationController { static statusListValidator = [ - check('length').isNumeric().withMessage('length should be a number'), - check('data').optional().isString().withMessage('data should be string'), - check('encoding').optional().isIn(['base64', 'base64url', 'hex']).withMessage('invalid encoding') + check('length').optional().isNumeric().withMessage('length should be a number'), + check('encodedList').optional().isString().withMessage('data should be string'), + check('encoding').optional().isIn(['base64', 'base64url', 'hex']).withMessage('invalid encoding'), + check('statusPurpose').optional().isIn(['revocation', 'suspension']).withMessage('invalid statusPurpose') ] - static didValidator = [ - query('did').isString().withMessage('DID is required') - .contains('did:cheqd:').withMessage('Provide a valid cheqd DID') + static queryValidator = [ + check('did').isString().withMessage('DID is required') + .contains('did:cheqd:').withMessage('Provide a valid cheqd DID'), + query('statusPurpose').optional().isString().withMessage('statusPurpose should be a string') + .isIn(['suspension', 'revocation']).withMessage('Invalid statuspurpose'), + query('encrypted').optional().isBoolean().withMessage('encrypted should be a boolean value') + ] + + static updateValidator = [ + check('indices').custom((value)=>{ + return value && (Array.isArray(value) || typeof value === 'number') + }).withMessage('An array of indices should be provided'), + check('statusListName').exists().withMessage('StatusListName is required').isString(), + check('statusListVerion').optional().isString().withMessage('Invalid statusListVersion'), + query('statusAction').exists().withMessage('StatusAction is required') + .isIn(['revoke', 'suspend', 'reinstate']), + query('publish').isBoolean().withMessage('publish should be a boolean value') ] async createStatusList(request: Request, response: Response) { @@ -25,18 +40,21 @@ export class RevocationController { return response.status(400).json({ error: result.array()[0].msg }) } - let { length, encoding } = request.body - let { data, name, type, alsoKnownAs, version, network } = request.body + let { did, encodedList, statusListName, alsoKnownAs, statusListVersion, length, encoding } = request.body + const { statusPurpose } = request.query as { statusPurpose: 'revocation' | 'suspension' } - const did = request.query.did as string - network = network || (did.split(':'))[2] - data = data ? fromString(data, 'base64') : undefined + const data = encodedList ? fromString(encodedList, encoding) : undefined try { - const result = await Identity.instance.createStatusList2021(did, network, { data, name, alsoKnownAs, version, resourceType: type }, { length, encoding }, response.locals.customerId) - return response.status(200).json({ - success: result - }) + let result: any + if (data) { + result = await Identity.instance.broadcastStatusList2021(did, { data, name: statusListName, alsoKnownAs, version: statusListVersion }, { encoding, statusPurpose }, response.locals.customerId) + } + result = await Identity.instance.createStatusList2021(did, { name: statusListName, alsoKnownAs, version: statusListVersion }, { length, encoding, statusPurpose }, response.locals.customerId) + if (result.error) { + return response.status(400).json(result) + } + return response.status(200).json(result) } catch (error) { return response.status(500).json({ error: `Internal error: ${error}` @@ -51,15 +69,26 @@ export class RevocationController { } try { - let result = await Veramo.instance.resolve(`${request.query.did}?resourceType=StatusList2021&resourceMetadata=true`) - result = result.contentStream?.linkedResourceMetadata || [] - const statusList = result - .filter((resource: ResourceMetadata)=>resource.mediaType=='application/octet-stream' || resource.mediaType=='application/gzip') + const statusPurpose = request.query.statusPurpose as 'revocation' | 'suspension' + const resourceTypes = statusPurpose ? [StatusList2021ResourceTypes[`${statusPurpose}`]] : [StatusList2021ResourceTypes.revocation, StatusList2021ResourceTypes.suspension] + let metadata: ResourceMetadata[] = [] + + for (const resourceType of resourceTypes) { + const result = await Veramo.instance.resolve(`${request.query.did}?resourceType=${resourceType}&resourceMetadata=true`) + metadata = metadata.concat(result.contentStream?.linkedResourceMetadata || []) + } + const statusList = metadata + .filter((resource: ResourceMetadata)=>{ + if (request.query.statusListName) { + return resource.resourceName === request.query.statusListName && resource.mediaType == 'application/json' + } + return resource.mediaType == 'application/json' + }) .map((resource: ResourceMetadata)=>{ return { statusListName: resource.resourceName, + statusPurpose: resource.resourceType, statusListVersion: resource.resourceVersion, - mediaType: resource.mediaType, statusListId: resource.resourceId, statusListNextVersion: resource.nextVersionId } @@ -71,4 +100,29 @@ export class RevocationController { }) } } + + async updateStatusList(request: Request, response: Response) { + const result = validationResult(request) + if (!result.isEmpty()) { + return response.status(400).json({ error: result.array()[0].msg }) + } + + let { did, statusListName, statusListVersion, indices } = request.body + const { statusAction } = request.query as { statusAction: 'revoke' | 'suspend' | 'reinstate' } + const publish = request.query.publish === 'false' ? false : true + indices = typeof indices === 'number' ? [indices] : indices + + try { + let result: any + result = await Identity.instance.updateStatusList2021(did, { indices, statusListName, statusListVersion, statusAction }, publish, response.locals.customerId) + if (result.error) { + return response.status(400).json(result) + } + return response.status(200).json(result) + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${error}` + }) + } + } } diff --git a/src/helpers/helpers.ts b/src/helpers/helpers.ts index 2247a101..1d2f4d8f 100644 --- a/src/helpers/helpers.ts +++ b/src/helpers/helpers.ts @@ -24,29 +24,34 @@ export function validateSpecCompliantPayload(didDocument: DIDDocument): SpecVali if (!didDocument.verificationMethod.length) return { valid: false, error: 'verificationMethod must be not be empty' } // verificationMethod types must be supported - const isValidVerificationMethod = didDocument.verificationMethod.every((vm) => { - switch (vm.type) { - case VerificationMethods.Ed255192020: - return vm.publicKeyMultibase != null - case VerificationMethods.JWK: - return vm.publicKeyJwk != null - case VerificationMethods.Ed255192018: - return vm.publicKeyBase58 != null - default: - return false - } - }) + if (!isValidVerificationMethod(didDocument)) return { valid: false, error: 'verificationMethod publicKey is Invalid' } - if (!isValidVerificationMethod) return { valid: false, error: 'verificationMethod publicKey is Invalid' } + if (!isValidService(didDocument)) return { valid: false, error: 'Service is Invalid' } + return { valid: true } as SpecValidationResult +} - const isValidService = didDocument.service +export function isValidService(didDocument: DIDDocument) : boolean { + return didDocument.service ? didDocument?.service?.every((s) => { return s?.serviceEndpoint && s?.id && s?.type }) : true +} - if (!isValidService) return { valid: false, error: 'Service is Invalid' } - return { valid: true } as SpecValidationResult +export function isValidVerificationMethod(didDocument: DIDDocument) : boolean { + if (!didDocument.verificationMethod) return false + return didDocument.verificationMethod.every((vm) => { + switch (vm.type) { + case VerificationMethods.Ed255192020: + return vm.publicKeyMultibase != null + case VerificationMethods.JWK: + return vm.publicKeyJwk != null + case VerificationMethods.Ed255192018: + return vm.publicKeyBase58 != null + default: + return false + } + }) } export function generateDidDoc(options: IDidDocOptions) { diff --git a/src/middleware/middleware.ts b/src/middleware/middleware.ts new file mode 100644 index 00000000..729336fb --- /dev/null +++ b/src/middleware/middleware.ts @@ -0,0 +1,26 @@ +import { Request, Response, NextFunction } from 'express' + +export class Middleware { + static async parseUrlEncodedJson(request: Request, response: Response, next: NextFunction) { + // Check if the request content type is URL-encoded + if (request.is('application/x-www-form-urlencoded')) { + // Parse the inner JSON strings + for (const key in request.body) { + try { + if (request.body[key] === '') { + request.body[key] = undefined + } else { + if (typeof request.body[key] === 'string' && request.body[key].includes(',')) { + // Check if the value contains commas + request.body[key] = request.body[key].split(',') + } + request.body[key] = JSON.parse(request.body[key]) + } + } catch (error) { + // Failed to parse the value as JSON, leave it as is + } + } + } + next() + } +} \ No newline at end of file diff --git a/src/services/connectors/verida.ts b/src/services/connectors/verida.ts index c270976d..2b924161 100644 --- a/src/services/connectors/verida.ts +++ b/src/services/connectors/verida.ts @@ -3,7 +3,7 @@ import { Context, Network } from '@verida/client-ts' import { AutoAccount } from '@verida/account-node' import { CredentialDataRecord, DataRecord } from '../../types/verida.js' -import { VC_CONTEXT, VERIDA_APP_NAME, VERIDA_CREDENTIAL_RECORD_SCHEMA } from '../../types/constants.js' +import { VERIDA_APP_NAME, VERIDA_CREDENTIAL_RECORD_SCHEMA } from '../../types/constants.js' import * as dotenv from 'dotenv' import { VerifiableCredential } from '@veramo/core' diff --git a/src/services/credentials.ts b/src/services/credentials.ts index 09682753..d8ddadd6 100644 --- a/src/services/credentials.ts +++ b/src/services/credentials.ts @@ -4,7 +4,7 @@ import { VC_CONTEXT, VC_TYPE } from '../types/constants.js' -import { CredentialRequest, VerifyStatusOptions } from '../types/types.js' +import { CredentialRequest, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../types/types.js' import { Identity } from './identity/index.js' import { VeridaService } from '../services/connectors/verida.js' import { v4 } from 'uuid' @@ -51,14 +51,14 @@ export class Credentials { return verifiable_credential } - async verify_credentials(credential: W3CVerifiableCredential | string, statusOptions: VerifyStatusOptions | null, agentId: string): Promise { + async verify_credentials(credential: W3CVerifiableCredential | string, statusOptions: VerifyCredentialStatusOptions | null, agentId: string): Promise { const result = await Identity.instance.verifyCredential(credential, statusOptions, agentId) delete(result.payload) return result } - async verify_presentation(presentation: W3CVerifiablePresentation, agentId: string): Promise { - const result = await Identity.instance.verifyPresentation(presentation, agentId) + async verify_presentation(presentation: W3CVerifiablePresentation, statusOptions: VerifyPresentationStatusOptions | null, agentId: string): Promise { + const result = await Identity.instance.verifyPresentation(presentation, statusOptions, agentId) return result } } diff --git a/src/services/identity/IIdentity.ts b/src/services/identity/IIdentity.ts index cf5b41b7..d57394a5 100644 --- a/src/services/identity/IIdentity.ts +++ b/src/services/identity/IIdentity.ts @@ -11,8 +11,8 @@ import type { } from '@veramo/core' import type { AbstractPrivateKeyStore } from '@veramo/key-manager' import type { ResourcePayload } from '@cheqd/did-provider-cheqd' -import type { RevocationResult, SuspensionResult, UnsuspensionResult } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' -import type { CreateStatusListOptions, CredentialRequest, StatusOptions, VeramoAgent, VerifyStatusOptions } from '../../types/types' +import type { BulkRevocationResult, BulkSuspensionResult, BulkUnsuspensionResult, CreateEncryptedStatusList2021Result, CreateStatusList2021Result, RevocationResult, SuspensionResult, UnsuspensionResult } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' +import type { BroadCastStatusListOptions, CreateStatusListOptions, CredentialRequest, StatusOptions, UpdateStatusListOptions, VeramoAgent, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../../types/types' export interface IIdentity { agent?: TAgent @@ -22,16 +22,20 @@ export interface IIdentity { createKey(type: 'Ed25519' | 'Secp256k1', agentId?: string): Promise getKey(kid: string, agentId?: string): Promise createDid(network: string, didDocument: DIDDocument, agentId?: string): Promise + updateDid(didDocument: DIDDocument, agentId?: string): Promise + deactivateDid(did: string, agentId?: string): Promise listDids(agentId?: string): Promise resolveDid(did: string): Promise getDid(did: string, agentId?: string): Promise importDid(did: string, privateKeyHex: string, publicKeyHex: string, agentId?: string): Promise createResource(network: string, payload: ResourcePayload, agentId?: string): Promise - createCredential(credential: CredentialPayload, format: CredentialRequest['format'], statusListOptions: StatusOptions | null, agentId?: string): Promise - verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyStatusOptions | null, agentId?: string): Promise - verifyPresentation(presentation: VerifiablePresentation | string, agentId?: string): Promise - createStatusList2021(did: string, network: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions, agentId: string): Promise - revokeCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise - suspendCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise - reinstateCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise + createCredential(credential: CredentialPayload, format: CredentialRequest['format'], statusOptions: StatusOptions | null, agentId?: string): Promise + verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyCredentialStatusOptions | null, agentId?: string): Promise + verifyPresentation(presentation: VerifiablePresentation | string, statusOptions: VerifyPresentationStatusOptions, agentId?: string): Promise + createStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions, agentId: string): Promise + updateStatusList2021(did: string, statusOptions: UpdateStatusListOptions, publish?: boolean, agentId?: string): Promise + broadcastStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: BroadCastStatusListOptions, agentId?: string): Promise + revokeCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise + suspendCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise + reinstateCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise } diff --git a/src/services/identity/agent.ts b/src/services/identity/agent.ts index 6dcba88e..962d805a 100644 --- a/src/services/identity/agent.ts +++ b/src/services/identity/agent.ts @@ -19,21 +19,24 @@ import { import { KeyManager } from '@veramo/key-manager' import { DIDStore, KeyStore } from '@veramo/data-store' import { DIDManager } from '@veramo/did-manager' -import { DIDResolverPlugin } from '@veramo/did-resolver' +import { DIDResolverPlugin, getUniversalResolver as UniversalResolver } from '@veramo/did-resolver' +import { getResolver as VeridaResolver } from '@verida/vda-did-resolver' import { CredentialPlugin } from '@veramo/credential-w3c' import { CredentialIssuerLD, LdDefaultContexts, VeramoEd25519Signature2018 } from '@veramo/credential-ld' import { Cheqd, getResolver as CheqdDidResolver, ResourcePayload } from '@cheqd/did-provider-cheqd' +import { getDidKeyResolver as KeyDidResolver } from '@veramo/did-provider-key' import { CheqdNetwork } from '@cheqd/sdk' import { Resolver, ResolverRegistry } from 'did-resolver' -import { fromString } from 'uint8arrays' -import { +import type { + ICheqdBroadcastStatusList2021Args, ICheqdCreateStatusList2021Args, - ICheqdGenerateStatusList2021Args, - ICheqdVerifyCredentialWithStatusList2021Args -} from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd.js' -import { v4 } from 'uuid' - + ICheqdDeactivateIdentifierArgs, + ICheqdRevokeBulkCredentialsWithStatusList2021Args, + ICheqdUpdateIdentifierArgs, + ICheqdVerifyCredentialWithStatusList2021Args, +} from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' import { + BroadCastStatusListOptions, cheqdDidRegex, CreateAgentRequest, CreateStatusListOptions, @@ -41,8 +44,10 @@ import { RevocationStatusOptions, StatusOptions, SuspensionStatusOptions, + UpdateStatusListOptions, VeramoAgent, - VerifyStatusOptions + VerifyCredentialStatusOptions, + VerifyPresentationStatusOptions } from '../../types/types.js' import { VC_PROOF_FORMAT, VC_REMOVE_ORIGINAL_FIELDS } from '../../types/constants.js' @@ -80,7 +85,10 @@ export class Veramo { plugins.push( new DIDResolverPlugin({ resolver: new Resolver({ - ...CheqdDidResolver({ url: process.env.RESOLVER_URL }) as ResolverRegistry + ...CheqdDidResolver({ url: process.env.RESOLVER_URL }) as ResolverRegistry, + ...KeyDidResolver(), + ...VeridaResolver(), + ...UniversalResolver() }) }) ) @@ -128,6 +136,38 @@ export class Veramo { } } + async updateDid(agent: VeramoAgent, didDocument: DIDDocument): Promise { + try { + const [kms] = await agent.keyManagerGetKeyManagementSystems() + + const result = await agent.cheqdUpdateIdentifier({ + kms, + document: didDocument, + } satisfies ICheqdUpdateIdentifierArgs) + return {...result, provider: 'cheqd'} + } catch (error) { + throw new Error(`${error}`) + } + } + + async deactivateDid(agent: VeramoAgent, did: string): Promise { + try { + const [kms] = await agent.keyManagerGetKeyManagementSystems() + const didDocument = (await this.resolveDid(agent, did)).didDocument + + if (!didDocument) { + throw new Error('DID document not found') + } + const result = await agent.cheqdDeactivateIdentifier({ + kms, + document: didDocument + } satisfies ICheqdDeactivateIdentifierArgs) + return result + } catch (error) { + throw new Error(`${error}`) + } + } + async listDids(agent: TAgent) { return (await agent.didManagerFind()).map((res)=>res.did) } @@ -196,46 +236,93 @@ export class Veramo { } } - async verifyCredential(agent: VeramoAgent, credential: string | VerifiableCredential, statusOptions: VerifyStatusOptions | null): Promise { - if(typeof credential !== 'string') { + async verifyCredential(agent: VeramoAgent, credential: string | VerifiableCredential, statusOptions: VerifyCredentialStatusOptions | null): Promise { + if(typeof credential !== 'string' && credential.credentialStatus) { return await agent.cheqdVerifyCredential({ credential: credential as VerifiableCredential, fetchList: true, ...statusOptions } as ICheqdVerifyCredentialWithStatusList2021Args) } - return await agent.verifyCredential({ credential, fetchRemoteContexts: true }) - } - async verifyPresentation(agent: VeramoAgent, presentation: VerifiablePresentation | string): Promise { - return await agent.verifyPresentation({ presentation, fetchRemoteContexts: true }) + const result = await agent.verifyCredential({ credential, fetchRemoteContexts: true }) + if (result.didResolutionResult) { + delete(result.didResolutionResult) + } + + if (result.jwt) { + delete(result.jwt) + } + + if (result.verifiableCredential) { + delete(result.verifiableCredential) + } + return result } - async createStatusList2021(agent: VeramoAgent, did: string, network: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions) { - const statusList = await agent.cheqdGenerateStatusList2021({ - buffer: resourceOptions.data, - length: statusOptions.length, - bitstringEncoding: statusOptions.encoding - } as ICheqdGenerateStatusList2021Args) + async verifyPresentation(agent: VeramoAgent, presentation: VerifiablePresentation | string, statusOptions: VerifyPresentationStatusOptions | null): Promise { + // TODO: expose domain in did-provider-cheqd + // if(typeof presentation !== 'string') { + // return await agent.cheqdVerifyPresentation({ + // presentation: presentation as VerifiablePresentation, + // fetchList: true, + // ...statusOptions + // } as ICheqdVerifyPresentationWithStatusList2021Args) + // } + const result = await agent.verifyPresentation({ presentation, fetchRemoteContexts: true, policies: {audience: false} }) + if (result.didResolutionResult) { + delete(result.didResolutionResult) + } + + if (result.jwt) { + delete(result.jwt) + } + if (result.verifiablePresentation) { + delete(result.verifiablePresentation) + } + return result + } + + async createStatusList2021(agent: VeramoAgent, did: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions) { const [kms] = await agent.keyManagerGetKeyManagementSystems() + if (!resourceOptions.name) { + throw new Error(`StatusList name is required`) + } return await agent.cheqdCreateStatusList2021({ kms, - payload: { - collectionId: did.split(':')[3], - data: fromString(statusList, statusOptions.encoding || 'base64url'), - resourceType: 'StatusList2021', - version: resourceOptions.version, - name: resourceOptions.name, - id: v4(), - }, - network: network as CheqdNetwork - } as ICheqdCreateStatusList2021Args) + issuerDid: did, + statusListName: resourceOptions.name, + statusPurpose: statusOptions.statusPurpose || 'revocation', + statusListEncoding: statusOptions.encoding || 'base64url', + statusListLength: statusOptions.length, + encrypted: statusOptions.encrypted || false, + resourceVersion: resourceOptions.version + } satisfies ICheqdCreateStatusList2021Args) + } + + async broadcastStatusList2021(agent: VeramoAgent, did: string, resourceOptions: ResourcePayload, statusOptions: BroadCastStatusListOptions) { + const [kms] = await agent.keyManagerGetKeyManagementSystems() + + if (!resourceOptions.data) { + throw new Error(`StatusList data is required`) + } + + return await agent.cheqdBroadcastStatusList2021({ + kms, + payload: { + ...resourceOptions, + collectionId: did.split(':')[3], + data: resourceOptions.data, + resourceType: statusOptions.statusPurpose === 'revocation' ? 'StatusList2021Revocation' : 'StatusList2021Suspension' + }, + network: did.split(':')[2] as CheqdNetwork, + } satisfies ICheqdBroadcastStatusList2021Args) } async revokeCredentials(agent: VeramoAgent, credentials: VerifiableCredential | VerifiableCredential[], publish: boolean=true) { - if (Array.isArray(credentials)) return await agent.cheqdRevokeCredentials({ credentials, fetchList: true, publish: true }) + if (Array.isArray(credentials)) return await agent.cheqdRevokeCredentials({ credentials, fetchList: true, publish: true } satisfies ICheqdRevokeBulkCredentialsWithStatusList2021Args) return await agent.cheqdRevokeCredential({ credential: credentials, fetchList: true, publish }) } @@ -256,4 +343,45 @@ export class Veramo { if (Array.isArray(credentials)) return await agent.cheqdUnsuspendCredentials({ credentials, fetchList: true, publish }) return await agent.cheqdUnsuspendCredential({ credential: credentials, fetchList: true, publish }) } + + async updateStatusList2021(agent: VeramoAgent, did: string, statusOptions: UpdateStatusListOptions, publish: boolean=true) { + switch(statusOptions.statusAction) { + case 'revoke': + return await agent.cheqdRevokeCredentials({ + revocationOptions: { + issuerDid: did, + statusListIndices: statusOptions.indices, + statusListName: statusOptions.statusListName, + statusListVersion: statusOptions.statusListVersion + }, + fetchList: true, + publish, + returnUpdatedStatusList: !publish + }) + case 'suspend': + return await agent.cheqdSuspendCredentials({ + suspensionOptions: { + issuerDid: did, + statusListIndices: statusOptions.indices, + statusListName: statusOptions.statusListName, + statusListVersion: statusOptions.statusListVersion + }, + fetchList: true, + publish, + returnUpdatedStatusList: !publish + }) + case 'reinstate': + return await agent.cheqdUnsuspendCredentials({ + unsuspensionOptions: { + issuerDid: did, + statusListIndices: statusOptions.indices, + statusListName: statusOptions.statusListName, + statusListVersion: statusOptions.statusListVersion + }, + fetchList: true, + publish, + returnUpdatedStatusList: !publish + }) + } + } } diff --git a/src/services/identity/local.ts b/src/services/identity/local.ts index 6cd1019e..87eb5564 100644 --- a/src/services/identity/local.ts +++ b/src/services/identity/local.ts @@ -9,9 +9,10 @@ import { import { AbstractPrivateKeyStore, MemoryPrivateKeyStore } from '@veramo/key-manager' import { KeyManagementSystem } from '@veramo/kms-local' import { CheqdDIDProvider, ResourcePayload } from '@cheqd/did-provider-cheqd' +import { BulkRevocationResult, BulkSuspensionResult, BulkUnsuspensionResult, CreateEncryptedStatusList2021Result, CreateStatusList2021Result, ICheqdBroadcastEncryptedStatusList2021Args } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' import { CheqdNetwork } from '@cheqd/sdk' -import { CreateStatusListOptions, CredentialRequest, DefaultRPCUrl, StatusOptions, VeramoAgent, VerifyStatusOptions } from '../../types/types.js' +import { BroadCastStatusListOptions, CreateStatusListOptions, CredentialRequest, DefaultRPCUrl, StatusOptions, UpdateStatusListOptions, VeramoAgent, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../../types/types.js' import { Connection } from '../../database/connection/connection.js' import { IIdentity } from './IIdentity.js' import { Veramo } from './agent.js' @@ -93,6 +94,18 @@ export class LocalIdentity implements IIdentity { throw new Error('Not supported') } + async updateDid(): Promise { + throw new Error('Not supported') + } + + async deactivateDid(did: string): Promise { + try { + return await Veramo.instance.deactivateDid(this.initAgent(), did) + } catch (error) { + throw new Error(`${error}`) + } + } + async listDids() { return [(await this.importDid()).did] } @@ -133,27 +146,35 @@ export class LocalIdentity implements IIdentity { } } - async verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyStatusOptions | null): Promise { + async verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyCredentialStatusOptions | null): Promise { return await Veramo.instance.verifyCredential(this.initAgent(), credential, statusOptions) } - async verifyPresentation(presentation: VerifiablePresentation | string): Promise { - return await Veramo.instance.verifyPresentation(this.initAgent(), presentation) + async verifyPresentation(presentation: VerifiablePresentation | string, statusOptions: VerifyPresentationStatusOptions | null): Promise { + return await Veramo.instance.verifyPresentation(this.initAgent(), presentation, statusOptions) + } + + async createStatusList2021(did: string, resourceOptions: ResourcePayload, statusListOptions: CreateStatusListOptions): Promise { + return await Veramo.instance.createStatusList2021(this.initAgent(), did, resourceOptions, statusListOptions) + } + + async updateStatusList2021(did: string, statusOptions: UpdateStatusListOptions, publish: boolean): Promise { + return await Veramo.instance.updateStatusList2021(this.initAgent(), did, statusOptions, publish) } - async createStatusList2021(did: string, network: string, resourceOptions: ResourcePayload, statusListOptions: CreateStatusListOptions): Promise { - return await Veramo.instance.createStatusList2021(this.initAgent(), did, network, resourceOptions, statusListOptions) + async broadcastStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: BroadCastStatusListOptions): Promise { + return await Veramo.instance.broadcastStatusList2021(this.initAgent(), did, resourceOptions, statusOptions) } - async revokeCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId: string) { + async revokeCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean) { return await Veramo.instance.revokeCredentials(this.initAgent(), credentials, publish) } - async suspendCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId: string) { + async suspendCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean) { return await Veramo.instance.suspendCredentials(this.initAgent(), credentials, publish) } - async reinstateCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId: string) { + async reinstateCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean) { return await Veramo.instance.unsuspendCredentials(this.initAgent(), credentials, publish) } } diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index d662eb5e..bf02d63c 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -16,7 +16,7 @@ import { KeyManagementSystem, SecretBox } from '@veramo/kms-local' import { PrivateKeyStore } from '@veramo/data-store' import { CheqdDIDProvider, ResourcePayload } from '@cheqd/did-provider-cheqd' import { CheqdNetwork } from '@cheqd/sdk' -import { cheqdDidRegex, CreateStatusListOptions, CredentialRequest, DefaultRPCUrl, StatusOptions, VeramoAgent, VerifyStatusOptions } from '../../types/types.js' +import { BroadCastStatusListOptions, cheqdDidRegex, CreateStatusListOptions, CredentialRequest, DefaultRPCUrl, StatusOptions, UpdateStatusListOptions, VeramoAgent, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../../types/types.js' import { Connection } from '../../database/connection/connection.js' import { CustomerEntity } from '../../database/entities/customer.entity.js' import { IIdentity } from './IIdentity.js' @@ -24,6 +24,7 @@ import { CustomerService } from '../customer.js' import { Veramo } from './agent.js' import * as dotenv from 'dotenv' +import { BulkRevocationResult, BulkSuspensionResult, BulkUnsuspensionResult, CreateEncryptedStatusList2021Result, CreateStatusList2021Result } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd.js' dotenv.config() const { @@ -60,6 +61,9 @@ export class PostgresIdentity implements IIdentity { } async createAgent(agentId: string) : Promise { + if(!agentId) { + throw new Error('Customer not found') + } const customer = await CustomerService.instance.get(agentId) as CustomerEntity const dbConnection = Connection.instance.dbConnection @@ -103,6 +107,9 @@ export class PostgresIdentity implements IIdentity { } async createKey(type: 'Ed25519' | 'Secp256k1'='Ed25519', agentId: string): Promise { + if(!agentId) { + throw new Error('Customer not found') + } const key = await Veramo.instance.createKey(this.agent, type) if(await CustomerService.instance.find(agentId, {})) await CustomerService.instance.update(agentId, { kids: [key.kid] }) return key @@ -121,10 +128,11 @@ export class PostgresIdentity implements IIdentity { } async createDid(network: string, didDocument: DIDDocument, agentId: string): Promise { + if(!agentId) { + throw new Error('Customer not found') + } try { const agent = await this.createAgent(agentId) - if (!agent) throw new Error('No initialised agent found.') - const identifier: IIdentifier = await Veramo.instance.createDid(agent, network, didDocument) await CustomerService.instance.update(agentId, { dids: [identifier.did] }) return identifier @@ -133,7 +141,35 @@ export class PostgresIdentity implements IIdentity { } } + async updateDid(didDocument: DIDDocument, agentId: string): Promise { + if(!agentId) { + throw new Error('Customer not found') + } + try { + const agent = await this.createAgent(agentId) + const identifier: IIdentifier = await Veramo.instance.updateDid(agent, didDocument) + return identifier + } catch (error) { + throw new Error(`${error}`) + } + } + + async deactivateDid(did: string, agentId: string): Promise { + if(!agentId) { + throw new Error('Customer not found') + } + try { + const agent = await this.createAgent(agentId) + return await Veramo.instance.deactivateDid(agent, did) + } catch (error) { + throw new Error(`${error}`) + } + } + async listDids(agentId: string) { + if(!agentId) { + throw new Error('Customer not found') + } const customer = await CustomerService.instance.get(agentId) as CustomerEntity return customer?.dids || [] } @@ -165,32 +201,42 @@ export class PostgresIdentity implements IIdentity { } } - async createCredential(credential: CredentialPayload, format: CredentialRequest['format'], statusListOptions: StatusOptions | null, agentId: string): Promise { + async createCredential(credential: CredentialPayload, format: CredentialRequest['format'], statusOptions: StatusOptions | null, agentId: string): Promise { try { const did = typeof(credential.issuer) == 'string' ? credential.issuer : credential.issuer.id if (!await CustomerService.instance.find(agentId, {did})) { throw new Error(`${did} not found in wallet`) } const agent = await this.createAgent(agentId) - return await Veramo.instance.createCredential(agent, credential, format, statusListOptions) + return await Veramo.instance.createCredential(agent, credential, format, statusOptions) } catch (error) { throw new Error(`${error}`) } } - async verifyCredential(credential: string | VerifiableCredential, statusOptions: VerifyStatusOptions | null, agentId: string): Promise { + async verifyCredential(credential: string | VerifiableCredential, statusOptions: VerifyCredentialStatusOptions | null, agentId: string): Promise { const agent = await this.createAgent(agentId) return await Veramo.instance.verifyCredential(agent, credential, statusOptions) } - async verifyPresentation(presentation: VerifiablePresentation | string, agentId: string): Promise { + async verifyPresentation(presentation: VerifiablePresentation | string, statusOptions: VerifyPresentationStatusOptions | null, agentId: string): Promise { + const agent = await this.createAgent(agentId) + return await Veramo.instance.verifyPresentation(agent, presentation, statusOptions) + } + + async createStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions, agentId: string): Promise { + const agent = await this.createAgent(agentId) + return await Veramo.instance.createStatusList2021(agent, did, resourceOptions, statusOptions) + } + + async updateStatusList2021(did: string, statusOptions: UpdateStatusListOptions, publish: boolean, agentId: string): Promise { const agent = await this.createAgent(agentId) - return await Veramo.instance.verifyPresentation(agent, presentation) + return await Veramo.instance.updateStatusList2021(agent, did, statusOptions, publish) } - async createStatusList2021(did: string, network: string, resourceOptions: ResourcePayload, statusListOptions: CreateStatusListOptions, agentId: string): Promise { + async broadcastStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: BroadCastStatusListOptions, agentId: string): Promise { const agent = await this.createAgent(agentId) - return await Veramo.instance.createStatusList2021(agent, did, network, resourceOptions, statusListOptions) + return await Veramo.instance.broadcastStatusList2021(agent, did, resourceOptions, statusOptions) } async revokeCredentials(credentials: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId: string) { diff --git a/src/static/custom-button.ts b/src/static/custom-button.ts index d645d07a..8dbe90d6 100644 --- a/src/static/custom-button.ts +++ b/src/static/custom-button.ts @@ -1,22 +1,22 @@ window.addEventListener("load", function () { - const base_url: string = window.location.origin; + const base_url: string = window.location.origin - const login_button: HTMLButtonElement = document.createElement('button'); - login_button.innerHTML = 'Log in'; - login_button.classList.add('btn', 'authorize'); + const login_button: HTMLButtonElement = document.createElement('button') + login_button.innerHTML = 'Log in' + login_button.classList.add('btn', 'authorize') login_button.onclick = function () { - window.location.href = base_url + '/logto/sign-in'; - }; + window.location.href = base_url + '/logto/sign-in' + } - const logout_button: HTMLButtonElement = document.createElement('button'); - logout_button.innerHTML = 'Log out'; - logout_button.classList.add('btn', 'authorize'); + const logout_button: HTMLButtonElement = document.createElement('button') + logout_button.innerHTML = 'Log out' + logout_button.classList.add('btn', 'authorize') logout_button.onclick = function () { - window.location.href = base_url + '/logto/sign-out'; - }; + window.location.href = base_url + '/logto/sign-out' + } - const auth_pan: Element = document.getElementsByClassName('auth-wrapper')[0]; - auth_pan.appendChild(login_button); - auth_pan.appendChild(logout_button); - }); + const auth_pan: Element = document.getElementsByClassName('auth-wrapper')[0] + auth_pan.appendChild(login_button) + auth_pan.appendChild(logout_button) + }) \ No newline at end of file diff --git a/src/static/swagger.json b/src/static/swagger.json index 632a04b4..95a8b36b 100644 --- a/src/static/swagger.json +++ b/src/static/swagger.json @@ -130,7 +130,7 @@ "DID" ], "summary": "Create a DID", - "description": "

This endpoint creates a DID by taking DID document or a verification method as an input.

", + "description": "

This endpoint creates a DID by taking a set of input parameters or the whole didDocument itself

", "security": [ { "bearerAuth": [] @@ -138,61 +138,86 @@ ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DIDCreateRequest" + } + }, "application/json": { "schema": { - "type": "object", - "required": [ - "options" - ], - "properties": { - "options": { - "type": "object", - "properties": { - "network": { - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "methodSpecificIdAlgo": { - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - } - } - }, - "secret": { - "type": "object", - "properties": { - "verificationMethod": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - }, - "id": { - "type": "string", - "example": "key-1" - } - } - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } + "$ref": "#/components/schemas/DIDCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Invalid Request" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" } } } } + } + } + }, + "/did/update": { + "post": { + "tags": [ + "DID" + ], + "summary": "Update a DID", + "description": "

This endpoint updates a DID by taking DID document or the particular fields needed to be updated

", + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DIDUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DIDUpdateRequest" + } + } + } }, "responses": { "200": { @@ -237,13 +262,78 @@ } } }, + "/did/deactivate/{did}": { + "post": { + "tags": [ + "DID" + ], + "summary": "Deactivate a DID", + "description": "

This endpoint deactivates a DID by taking DID document or a verification method as an input.

", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "did", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Invalid Request" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, "/did/list": { "get": { "tags": [ "DID" ], "summary": "Fetch DIDs from wallet", - "description": "

This endpoint creates a DID by taking DID document as an input.

", + "description": "

This endpoint returns the list of DIDs controlled by the account

", "security": [ { "bearerAuth": [] @@ -300,8 +390,8 @@ "tags": [ "DID" ], - "summary": "Fetch DIDs from wallet", - "description": "

This endpoint creates a DID by taking DID document as an input.

", + "summary": "Resolve a DID", + "description": "

This endpoint resolved a DID

", "security": [ { "bearerAuth": [] @@ -366,7 +456,7 @@ "Credential" ], "summary": "Issue a credential", - "description": "

This endpoint creates a DID. As input it takes the list of attributes, subjectDid, context and expiration date of the credential to be issued.

", + "description": "

This endpoint issues a credential. As input it takes the list of attributes, subjectDid, context and expiration date of the credential to be issued.

", "security": [ { "bearerAuth": [] @@ -374,6 +464,11 @@ ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, "application/json": { "schema": { "$ref": "#/components/schemas/CredentialRequest" @@ -439,14 +534,14 @@ ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, "application/json": { "schema": { - "properties": { - "credential": { - "type": "string", - "example": "" - } - } + "$ref": "#/components/schemas/CredentialVerifyRequest" } } } @@ -507,19 +602,27 @@ "bearerAuth": [] } ], + "parameters": [ + { + "in": "query", + "name": "publish", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, "application/json": { "schema": { - "properties": { - "credential": { - "type": "object" - }, - "publish": { - "type": "boolean", - "example": true - } - } + "$ref": "#/components/schemas/CredentialRevokeRequest" } } } @@ -530,7 +633,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/credentialStatusResult" + "$ref": "#/components/schemas/RevocationResult" } } } @@ -580,19 +683,25 @@ "bearerAuth": [] } ], + "parameters": [ + { + "in": "query", + "name": "publish", + "schema": { + "type": "boolean" + } + } + ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, "application/json": { "schema": { - "properties": { - "credential": { - "type": "object" - }, - "publish": { - "type": "boolean", - "example": true - } - } + "$ref": "#/components/schemas/CredentialRevokeRequest" } } } @@ -653,19 +762,25 @@ "bearerAuth": [] } ], + "parameters": [ + { + "in": "query", + "name": "publish", + "schema": { + "type": "boolean" + } + } + ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, "application/json": { "schema": { - "properties": { - "credential": { - "type": "object" - }, - "publish": { - "type": "boolean", - "example": true - } - } + "$ref": "#/components/schemas/CredentialRevokeRequest" } } } @@ -713,25 +828,40 @@ } } }, - "/account": { + "/presentation/verify": { "post": { "tags": [ - "Account" + "Presentation" ], - "summary": "Create a client", - "description": "

This endpoint verifies the JWT token and creates a customer if they don't exist

", + "summary": "Verify a credential presentation", + "description": "

This endpoint verifies the credential presentation. As input it takes the entire presentation itself

", + "operationId": "presentation", "security": [ { "bearerAuth": [] } ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationRequest" + } + } + } + }, "responses": { "200": { "description": "The request was successful", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Customer" + "$ref": "#/components/schemas/IVerifyResult" } } } @@ -766,12 +896,14 @@ } } } - }, - "get": { + } + }, + "/account": { + "post": { "tags": [ "Account" ], - "summary": "Fetch a client", + "summary": "Create a client", "description": "

This endpoint verifies the JWT token and creates a customer if they don't exist

", "security": [ { @@ -819,45 +951,37 @@ } } } - } - }, - "/{did}/create-resource": { - "post": { + }, + "get": { "tags": [ - "Resource" + "Account" ], - "summary": "Create a Resource", - "parameters": [ + "summary": "Fetch a client", + "description": "

This endpoint verifies the JWT token and creates a customer if they don't exist

", + "security": [ { - "in": "path", - "name": "did", - "required": true, - "schema": { - "type": "string" - } + "bearerAuth": [] } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, "responses": { "200": { - "description": "The resource is created successfully" - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "description": "The request was successful", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { "error": "Invalid Request" } } @@ -882,15 +1006,15 @@ } } }, - "/credential-status/statusList2021/create": { + "/resource/create/{did}": { "post": { "tags": [ - "Revocation" + "Resource" ], - "summary": "Create statuslist 2021", + "summary": "Create a Resource", "parameters": [ { - "in": "query", + "in": "path", "name": "did", "required": true, "schema": { @@ -900,33 +1024,280 @@ ], "requestBody": { "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/CreateResourceRequest" - }, - { - "type": "object", - "properties": { - "length": { - "type": "number" - } - } - } - ], + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The resource is created successfully" + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Invalid Request" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/credential-status/create": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create statuslist 2021", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "encrypted", + "required": true, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "StatusList is created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Invalid Request" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/credential-status/update": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Publish statuslist 2021", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + }, + { + "in": "query", + "name": "publish", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "StatusList is published successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Invalid Request" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, "example": { - "length": 20, - "name": "cheqd-employee-credentials", - "version": "2023" + "error": "Internal Error" } } } } + } + } + }, + "/credential-status/publish": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Publish statuslist 2021", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "encrypted", + "required": true, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusPublishRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusPublishRequest" + } + } + } }, "responses": { "200": { - "description": "StatusList is created successfully" + "description": "StatusList is published successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusResult" + } + } + } }, "400": { "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", @@ -960,12 +1331,12 @@ } } }, - "/credential-status/statusList2021/list": { + "/credential-status/search": { "get": { "tags": [ - "Revocation" + "Credential Status" ], - "summary": "List published statuslist 2021", + "summary": "Fetch statusList's published by a DID", "parameters": [ { "in": "query", @@ -974,6 +1345,24 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "statusPurpose", + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "statusListName", + "schema": { + "type": "string" + } } ], "responses": { @@ -992,10 +1381,6 @@ "statusListVersion": { "type": "string" }, - "mediaType": { - "type": "string", - "enum": ["application/gzip", "application/octet-stream"] - }, "statusListId": { "type": "string" }, @@ -1092,7 +1477,7 @@ } }, "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See https://identity.foundation/did-registration/#diddocument.", + "description": "This input field contains a complete DID document", "type": "object", "properties": { "context": { @@ -1193,6 +1578,10 @@ "type": "string", "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" }, + "publicKeyBase58": { + "type": "string", + "example": "so1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt" + }, "publicKeyMultibase": { "type": "string", "example": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt" @@ -1203,6 +1592,12 @@ "type": "string" } } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" } }, "Service": { @@ -1210,11 +1605,11 @@ "properties": { "id": { "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#rand," + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#rand" }, "type": { "type": "string", - "example": "rand," + "example": "rand" }, "serviceEndpoint": { "type": "array", @@ -1241,24 +1636,29 @@ "type": "string" }, "attributes": { + "description": "Json input of the attributes", "type": "object" }, "@context": { + "description": "Additional contexts to be included in the credential", "type": "array", "items": { "type": "string" } }, "type": { + "description": "Additional type property to be included in the credential", "type": "array", "items": { "type": "string" } }, "expirationDate": { + "description": "Optional expiration date according to the specification", "type": "string" }, "format": { + "description": "Select one of the supported credential formats, jwt by default", "type": "string", "enum": [ "jwt", @@ -1266,7 +1666,12 @@ ] }, "credentialStatus": { + "description": "Optional field to support revocation or suspension, which takes statusListName and statusListPurpose as inputs.", "type": "object", + "required": [ + "statusPurpose", + "statusListName" + ], "properties": { "statusPurpose": { "type": "string", @@ -1293,6 +1698,10 @@ "indexNotIn": { "type": "number" } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" } } }, @@ -1358,8 +1767,32 @@ } } }, - "issuanceDate": { - "type": "string" + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "statusListIndex": { + "type": "string" + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + }, + "type": { + "type": "string", + "enum": [ + "StatusList2021Entry" + ] + } + } + }, + "issuanceDate": { + "type": "string" }, "proof": { "type": "object", @@ -1375,26 +1808,32 @@ }, "example": { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" ], "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusListIndex": "20", + "statusPurpose": "suspension", + "type": "StatusList2021Entry" }, "issuanceDate": "2023-06-08T13:49:28.000Z", "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" }, "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" }, "type": [ - "VerifiableCredential", - "Person" + "VerifiableCredential", + "Person" ] } }, @@ -1435,9 +1874,6 @@ "verified": { "type": "boolean" }, - "didResolutionResult": { - "type": "object" - }, "issuer": { "type": "string" }, @@ -1452,94 +1888,47 @@ } }, "example": { - "didResolutionResult": { - "@context": "https://w3id.org/did-resolution/v1", - "didDocument": { - "@context": [ - "https://www.w3.org/ns/did/v1", - "https://w3id.org/security/suites/ed25519-2018/v1" - ], - "assertionMethod": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "verificationMethod": [ - { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - ] - }, - "didDocumentMetadata": { - "created": "2023-06-07T15:53:59.629128532Z", - "versionId": "8e286b55-7a25-44bb-af93-f0f8fd9df1b7" - }, - "didResolutionMetadata": { - "contentType": "application/did+ld+json", - "did": { - "didString": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "method": "cheqd", - "methodSpecificId": "7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "retrieved": "2023-06-08T13:51:18Z" - } - }, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "verified": true, "policies": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - }, - "verifiableCredential": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": [ - "VerifiableCredential", - "Person" - ] - }, - "verified": true + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } } }, "CreateResourceRequest": { "description": "Input fields for the resource creation", "type": "object", "additionalProperties": false, + "required": [ + "name", + "type", + "data", + "encoding" + ], "properties": { "data": { + "description": "Provide encoded string for the resource data", "type": "string" }, + "encoding": { + "description": "The encoding format of the resource data", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, "name": { + "description": "Resource name", "type": "string" }, "type": { + "description": "Resource type", "type": "string" }, "alsoKnownAs": { @@ -1566,31 +1955,374 @@ "type": "TextDocument" } }, - "credentialStatusResult": { + "RevocationResult": { "properties": { "revoked": { "type": "boolean" } } }, - "SuspensionResult": { + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean" + }, + "statusList": { + "type": "string" + } + } + }, + "UnSuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean" + }, + "statusList": { + "type": "string" + } + } + }, + "DIDCreateRequest": { + "type": "object", + "properties": { + "network": { + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "methodSpecificIdAlgo": { + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "verificationMethodType": { + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + }, + "serviceEndpoint": { + "type": "string" + }, + "assertionMethod": { + "description": "An assertion method is required to issue JSONLD credentials", + "type": "boolean", + "default": true + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DIDUpdateRequest": { + "type": "object", "properties": { - "suspended": { - "type": "boolean" - }, - "statusList": { - "type": "string" - } + "did": { + "type": "string" + }, + "service": { + "type": "array", + "description": "This input field assigns the provided service array to the didDocument", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "This input field assigns the provided verificationMethod array to the didDocument", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "This input field assigns the provided authentication array to the didDocument", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } } }, - "UnSuspensionResult": { + "CredentialVerifyRequest": { + "type": "object", "properties": { - "unsuspended": { - "type": "boolean" - }, - "statusList": { - "type": "string" - } + "credential": { + "description": "This input field takes the credential object or the JWT string", + "allOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + } + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "This input field takes the credential object or the JWT string", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + } + } + }, + "CredentialStatusCreateRequest": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "statusListName" + ], + "properties": { + "did": { + "description": "The DID of the statuslist publisher", + "type": "string" + }, + "statusListName": { + "description": "The name of the statusList to be created", + "type": "string" + }, + "length": { + "description": "The length of the statusList to be created, The default and minimum length is 140000 which is 16kb", + "type": "number" + }, + "encoding": { + "description": "The encoding format of the statusList to be published", + "type": "string", + "default": "base64url", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "This input field is OPTIONAL, If present assigns the version to be assigned to the statusList", + "type": "string" + }, + "alsoKnownAs": { + "description": "The input field is OPTIONAL. If present, the value MUST be a set where each item in the set is a uri", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials" + } + }, + "CredentialStatusUpdateRequest": { + "type": "object", + "required": [ + "did", + "statusListName", + "indices" + ], + "properties": { + "did": { + "description": "The DID of the statuslist publisher", + "type": "string" + }, + "statusListName": { + "description": "The name of the statusList to be created", + "type": "string" + }, + "indices": { + "description": "Provide the list of indices to be updated", + "type": "array", + "items": { + "type": "number" + } + }, + "statusListVersion": { + "description": "This input field is OPTIONAL, If present uses the provided statusListVersion for the update operation", + "type": "string" + } + } + }, + "CredentialStatusPublishRequest": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "encodedList", + "statusListName", + "encoding" + ], + "properties": { + "did": { + "description": "The DID of the statuslist publisher", + "type": "string" + }, + "statusListName": { + "description": "The name of the statusList to be published", + "type": "string" + }, + "encodedList": { + "description": "Provide encoded string for the resource data", + "type": "string" + }, + "encoding": { + "description": "The encoding format of the statusList provided", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "This input field is OPTIONAL, If present assigns the version to be assigned to the statusList", + "type": "string" + }, + "alsoKnownAs": { + "description": "The input field is OPTIONAL. If present, the value MUST be a set where each item in the set is a uri", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "name": "cheqd-employee-credentials", + "version": "2023", + "data": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA", + "encoding": "base64url" + } + }, + "PresentationRequest": { + "type": "object", + "required": [ + "presentation" + ], + "properties": { + "presentation": { + "description": "This input field takes the presentation object or the JWT string", + "allOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + }, + "CredentialStatusResult": { + "type": "object", + "properties": { + "success": { + "type": "object", + "properties": { + "created": { + "type": "boolean" + }, + "resourceNetadata": { + "type": "object" + }, + "statusList2021": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string" + }, + "type": { + "type": "string" + }, + "validFrom": { + "type": "string" + } + } + } + } + }, + "metadata": { + "type": "string", + "properties": { + "encoding": { + "type": "string" + }, + "encrypted": { + "type": "boolean" + } + } + } + } + } + }, + "example": { + "created": true, + "resource": { + "StatusList2021": { + "encodedList": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA", + "type": "StatusList2021Revocation", + "validFrom": "2023-06-26T11:45:19.349Z" + }, + "metadata": { + "encoding": "base64url", + "encrypted": false + } + }, + "resourceMetadata": { + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "created": "2023-06-26T11:45:20Z", + "mediaType": "application/json", + "nextVersionId": null, + "previousVersionId": null, + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-1", + "resourceType": "StatusList2021Revocation", + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceVersion": "2023-06-26T11:45:19.349Z" + } } } } diff --git a/src/types/types.ts b/src/types/types.ts index b878501c..53b6403e 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -8,7 +8,7 @@ import { W3CVerifiableCredential, TAgent } from '@veramo/core' -import { ICheqd, ICheqdStatusList2021Options } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' +import { AccessControlConditionBalanceArgs, AccessControlConditionMemoNonceArgs, ICheqd, ICheqdStatusList2021Options } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd' import { ICredentialIssuerLD } from '@veramo/credential-ld' import { AbstractIdentifierProvider } from '@veramo/did-manager' import { AbstractKeyManagementSystem } from '@veramo/key-manager' @@ -111,13 +111,22 @@ export type CreateAgentRequest = { enableCredential?: boolean } +export const StatusList2021ResourceTypes = { + revocation: 'StatusList2021Revocation', + suspension: 'StatusList2021Suspension' +} + export type CreateStatusListOptions = { length?: number | undefined, encoding?: 'base64' | 'base64url' | 'hex' | undefined + statusPurpose: 'revocation' | 'suspension' + encrypted?: boolean } +export type BroadCastStatusListOptions = Omit + export type StatusOptions = { - statusPurpose: 'revocation' | 'suspension' + statusPurpose: CreateStatusListOptions['statusPurpose'] statusListName: string statusListIndex?: number statusListVersion?: string @@ -129,7 +138,7 @@ export type StatusOptions = { export type RevocationStatusOptions = StatusOptions & { statusPurpose: 'revocation' } export type SuspensionStatusOptions = StatusOptions & { statusPurpose: 'suspension' } -export type VerifyStatusOptions = { +export type VerifyCredentialStatusOptions = { fetchList?: boolean encryptedSymmetricKey?: string options?: ICheqdStatusList2021Options @@ -139,6 +148,12 @@ export type VerifyStatusOptions = { bootstrapOptions: {} } +export type VerifyPresentationStatusOptions = Omit & { + decryptionOptions: { + accessControlConditions: (AccessControlConditionMemoNonceArgs | AccessControlConditionBalanceArgs)[] + } +} + export interface ResourceMetadata { collectionId: string resourceId: string @@ -148,8 +163,15 @@ export interface ResourceMetadata { mediaType: string created: | Date - | undefined; - checksum: string; - previousVersionId: string; - nextVersionId: string; + | undefined + checksum: string + previousVersionId: string + nextVersionId: string +} + +export interface UpdateStatusListOptions { + indices: number[] + statusListName: string + statusListVersion?: string + statusAction: 'revoke' | 'suspend' | 'reinstate' } \ No newline at end of file