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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @docknetwork/sdk-examples

## 0.22.3

### Patch Changes

- Updated dependencies
- @docknetwork/credential-sdk@0.54.18

## 0.22.2

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@docknetwork/sdk-examples",
"private": true,
"type": "module",
"version": "0.22.2",
"version": "0.22.3",
"scripts": {
"bbs-dock-example": "babel-node ./src/bbs-dock.js",
"claim-deduction-example": "babel-node ./src/claim-deduction.js",
Expand All @@ -18,7 +18,7 @@
"lint": "eslint \"src/**/*.js\""
},
"dependencies": {
"@docknetwork/credential-sdk": "0.54.17",
"@docknetwork/credential-sdk": "0.54.18",
"@docknetwork/cheqd-blockchain-api": "4.2.1",
"@docknetwork/cheqd-blockchain-modules": "4.0.8"
},
Expand Down
6 changes: 6 additions & 0 deletions packages/credential-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @docknetwork/credential-sdk

## 0.54.18

### Patch Changes

- Allow to resolve status list from http/https too

## 0.54.17

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@docknetwork/credential-sdk",
"version": "0.54.17",
"version": "0.54.18",
"license": "MIT",
"type": "module",
"files": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
import { ensureInstanceOf, ensureString } from '../../utils';
import AbstractStatusListCredentialModule from '../../modules/abstract/status-list-credential/module';
import { Resolver } from '../generic';
import jsonFetch from '../../utils/json-fetch';

const HTTP_PREFIXES = ['http://', 'https://'];
const STATUS_LIST_2021_TYPE = 'StatusList2021';
const STATUS_PURPOSES = new Set(['revocation', 'suspension']);

function isHttpUrl(id) {
return HTTP_PREFIXES.some((prefix) => id.startsWith(prefix));
}

function isStatusList2021CredentialLike(doc) {
if (doc == null || typeof doc !== 'object') return false;

const { credentialSubject } = doc;
if (credentialSubject == null || typeof credentialSubject !== 'object') {
return false;
}

return (
credentialSubject.type === STATUS_LIST_2021_TYPE
&& typeof credentialSubject.encodedList === 'string'
&& STATUS_PURPOSES.has(credentialSubject.statusPurpose)
);
}

class StatusListResolver extends Resolver {
prefix = 'status-list2021';
Expand All @@ -25,15 +49,28 @@ class StatusListResolver extends Resolver {
);
}

supports(id) {
const identifier = ensureString(id);

return isHttpUrl(identifier) || super.supports(identifier);
}

async resolve(id) {
const cred = await this.statusListCredentialModule.getStatusListCredential(ensureString(id));
const identifier = ensureString(id);
if (isHttpUrl(identifier)) {
const doc = await jsonFetch(identifier);

return isStatusList2021CredentialLike(doc) ? doc : null;
}

const cred = await this.statusListCredentialModule.getStatusListCredential(identifier);

return cred?.toJSON();
return cred?.toJSON ? cred.toJSON() : cred ?? null;
}
}

/**
* Resolves `StatusList2021Credential`s with identifier `status-list2021:dock:*`.
* Resolves `StatusList2021Credential`s with identifier `status-list2021:*` or `http(s)` URL.
* @type {StatusListResolver}
*/
export default StatusListResolver;
4 changes: 2 additions & 2 deletions packages/credential-sdk/src/vc/document-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ function documentLoader(resolver = null) {
if (uriString.startsWith('data:')) {
document = parseEmbeddedDataURI(uriString);
} else if (resolver?.supports(uriString)) {
// Try to resolve a DID and throw if cannot resolve
document = await resolver.resolve(uriString);
// Try to resolve using resolver; if not found, return null and let upstream loaders continue.
document = (await resolver.resolve(uriString)) ?? null;
} else {
// Strip ending slash from uri to determine cache key
const cacheKey = uriString.endsWith('/')
Expand Down
83 changes: 83 additions & 0 deletions packages/credential-sdk/tests/resolvers.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Ed25519Keypair } from "../src/keypairs";
import { AbstractDIDModule } from "../src/modules";
import AbstractApiProvider from "../src/modules/abstract/common/abstract-api-provider";
import AbstractStatusListCredentialModule from "../src/modules/abstract/status-list-credential/module";
import { createCredential, createList } from "@digitalcredentials/vc-status-list";
import {
Resolver,
ResolverRouter,
Expand All @@ -10,6 +12,7 @@ import {
createResolver,
DIDResolver,
DIDKeyResolver,
StatusList2021Resolver,
} from "../src/resolver";
import {
CheqdTestnetDIDDocument,
Expand Down Expand Up @@ -102,6 +105,27 @@ class WildcardPrefixAndMethodResolver extends Resolver {
}
}

class TestStatusListCredentialModule extends AbstractStatusListCredentialModule {
constructor(getStatusListCredentialImpl) {
super();
this.getStatusListCredentialImpl = getStatusListCredentialImpl;
}

methods() {
return ["dock"];
}

async getStatusListCredential(id) {
return await this.getStatusListCredentialImpl(id);
}

async createStatusListCredentialTx() {}

async updateStatusListCredentialTx() {}

async removeStatusListCredentialTx() {}
}

describe("Resolvers", () => {
it("checks `DIDResolverWithDIDReplacement`", async () => {
const did = "did:dock:5EbpmcZhMPPLCyP4mDwo4bNtwZBi3dZuKzz65PGk2Amnvek5";
Expand Down Expand Up @@ -164,6 +188,65 @@ describe("Resolvers", () => {
).toMatchSnapshot();
});

it("checks `StatusList2021Resolver` supports `http(s)` and dock identifiers", async () => {
const statusListModule = new TestStatusListCredentialModule(async (id) => ({
toJSON: () => ({ id, source: "module" }),
}));
const resolver = new StatusList2021Resolver(statusListModule);
const statusListId = "status-list2021:dock:0x123";
const httpsStatusListId = "https://example.com/status-list/1";
const httpStatusListId = "http://example.com/status-list/1";
const statusList = await createList({ length: 16 });
const httpStatusListCredential = await createCredential({
id: httpsStatusListId,
list: statusList,
statusPurpose: "revocation",
});
const fetchMock = jest.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: async () => httpStatusListCredential,
});

expect(resolver.supports(statusListId)).toBe(true);
expect(resolver.supports(httpsStatusListId)).toBe(true);
expect(resolver.supports(httpStatusListId)).toBe(true);
expect(await resolver.resolve(statusListId)).toEqual({
id: statusListId,
source: "module",
});
expect(await resolver.resolve(httpsStatusListId)).toMatchObject({
id: httpsStatusListId,
credentialSubject: {
type: "StatusList2021",
statusPurpose: "revocation",
},
});
expect(fetchMock).toHaveBeenCalledWith(httpsStatusListId, undefined);

fetchMock.mockRestore();
});

it("checks `StatusList2021Resolver` skips non-status-list JSON over `http(s)`", async () => {
const statusListModule = new TestStatusListCredentialModule(async (id) => ({
toJSON: () => ({ id, source: "module" }),
}));
const resolver = new StatusList2021Resolver(statusListModule);
const httpsStatusListId = "https://example.com/not-a-status-list";
const fetchMock = jest.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: async () => ({
"@context": ["https://www.w3.org/2018/credentials/v1"],
id: httpsStatusListId,
type: ["VerifiableCredential"],
}),
});

expect(await resolver.resolve(httpsStatusListId)).toBeNull();
expect(fetchMock).toHaveBeenCalledWith(httpsStatusListId, undefined);

fetchMock.mockRestore();
});

it("checks `ResolverRouter`", async () => {
expect(() => new ResolverRouter()).toThrowError(
"No resolvers were provided. You need to either implement `resolve` or provide a list of resolvers"
Expand Down
7 changes: 7 additions & 0 deletions scripts/bench/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @docknetwork/benchmarks

## 0.4.22

### Patch Changes

- Updated dependencies
- @docknetwork/credential-sdk@0.54.18

## 0.4.21

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions scripts/bench/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"name": "@docknetwork/benchmarks",
"private": true,
"type": "module",
"version": "0.4.21",
"version": "0.4.22",
"scripts": {
"bench": "babel-node src/main.js"
},
"dependencies": {
"@docknetwork/cheqd-blockchain-api": "4.2.1",
"@docknetwork/cheqd-blockchain-modules": "4.0.8",
"@docknetwork/credential-sdk": "0.54.17",
"@docknetwork/credential-sdk": "0.54.18",
"@docknetwork/crypto-wasm-ts": "^0.63.0"
},
"devDependencies": {
Expand Down
Loading