<h1 align="center">
  <br>
  <a href="https://www.sphereon.com"><img src="https://sphereon.com/content/themes/sphereon/assets/img/logo.svg" alt="Sphereon" width="400"></a>
  <br>Well Known DID client
  <br>
</h1>

[![CI](https://github.com/Sphereon-Opensource/wellknown-did-client/actions/workflows/main.yaml/badge.svg)](https://github.com/Sphereon-Opensource/wellknown-did-client/actions/workflows/main.yaml)  [![codecov](https://codecov.io/gh/Sphereon-Opensource/wellknown-did-client/branch/develop/graph/badge.svg?token=N7DH65LYDU)](https://codecov.io/gh/Sphereon-Opensource/wellknown-did-client) [![NPM Version](https://img.shields.io/npm/v/@sphereon/wellknown-dids-client.svg)](https://npm.im/@sphereon/wellknown-dids-client)

### Wellknown-dids client
The wellknown-dids-client is a library to create DID configuration resources and domain linkage credentials and to be able to verify these conforming to the DIF [spec for well-known DID Configurations](https://identity.foundation/.well-known/resources/did-configuration/) 
It is written in Typescript and can be compiled to any target JavaScript version.

### Supported actions
 * Creating a DID configuration resource.
 * Creating a domain linkage credential.
 * Verifying domain linkage based on a DID document.
 * Verifying an endpoint descriptor.
 * Verifying a DID configuration resource (option for remote possible).
 * Verifying a domain linkage credential (JWT or JSONLD).

### Requirements
#### Well-Known DID issuer
For the well-known DID issuer, an issue callback is required that does the actual issuing of the credential. This can be supplied by using a config to the issuer or as a parameter to the functions.
#### Well-Known DID verifier
For the well-known DIr verifier, a verification callback is required that does the signature verification of the credential. This can be supplied by using a config to the issuer or as a parameter to the functions.

#### Examples

NOTE: VC-JS is being used as an example. Any issuer should be able to be used.

##### DID configuration resource creation
 ```typescript
import { WellKnownDidIssuer } from '@sphereon/wellknown-dids-client';
import vc from '@digitalbazaar/vc';
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';

const issueCallback = async (args: IIssueCallbackArgs): Promise<any> => {
  const keyPair = await Ed25519VerificationKey2020.generate();
  const suite = new Ed25519Signature2020({key: keyPair});
  suite.verificationMethod = args.credential.credentialSubject.id
  const { defaultDocumentLoader } = vc;

  return await vc.issue({ credential: args.credential, suite, documentLoader: defaultDocumentLoader });
};

const issuer: WellKnownDidIssuer = new WellKnownDidIssuer({
  issueCallback: (args: IIssueCallbackArgs) => issueCallback(args),
});

const args = {
  issuances: [
    {
      did: 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM',
      origin: 'https://example.com',
      issuanceDate: new Date().toDateString(),
      expirationDate: new Date(new Date().getFullYear() + 10, new Date().getMonth(), new Date().getDay()).toISOString(),
      options: { proofFormat: ProofFormatTypesEnum.JSON_LD },
    },
  ],
};

issuer.issueDidConfigurationResource(args) 
  .then(result => 'success')
  .catch(error => 'failed');
 ```

##### Domain linkage credential creation
 ```typescript
import { WellKnownDidIssuer } from '@sphereon/wellknown-dids-client';
import vc from '@digitalbazaar/vc';
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';

const issueCallback = async (args: IIssueCallbackArgs): Promise<any> => {
  const keyPair = await Ed25519VerificationKey2020.generate();
  const suite = new Ed25519Signature2020({key: keyPair});
  suite.verificationMethod = args.credential.credentialSubject.id
  const { defaultDocumentLoader } = vc;

  return await vc.issue({ credential: args.credential, suite, documentLoader: defaultDocumentLoader });
};

const issuer: WellKnownDidIssuer = new WellKnownDidIssuer();

const args = {
  issuances: [
    {
      did: 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM',
      origin: 'https://example.com',
      issuanceDate: new Date().toDateString(),
      expirationDate: new Date(new Date().getFullYear() + 10, new Date().getMonth(), new Date().getDay()).toISOString(),
      options: { proofFormat: ProofFormatTypesEnum.JSON_WEB_TOKEN },
      issueCallback: (args: IIssueCallbackArgs) => issueCallback(args)
    },
  ],
};

issuer.issueDomainLinkageCredential(args)
  .then(result => 'success')
  .catch(error => 'failed');
 ```

##### Domain linkage verification
 ```typescript
import { WellKnownDidIssuer } from '@sphereon/wellknown-dids-client';
import vc from '@digitalbazaar/vc';
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';

const verifySignatureCallback = async (args: IVerifyCallbackArgs): Promise<IVerifyCredentialResult> => {
  const keyPair = await getKeyPair();
  const suite = new Ed25519Signature2020({key: keyPair});
  const { defaultDocumentLoader } = vc;
  
  return await vc.verifyCredential({ credential: args.credential, suite, documentLoader: defaultDocumentLoader });
}

const verifier: WellKnownDidVerifier = new WellKnownDidVerifier({
  verifySignatureCallback: (args: IVerifyCallbackArgs) => verifySignatureCallback(args),
});

const didDoccument = {
  ...
};

verifier.verifyDomainLinkage({ didDoccument, onlyVerifyServiceDid: false })
  .then(result => 'success')
  .catch(error => 'failed');
 ```

##### DID configuration resource verification
 ```typescript
import { WellKnownDidIssuer } from '@sphereon/wellknown-dids-client';
import vc from '@digitalbazaar/vc';
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';

const verifySignatureCallback = async (args: IVerifyCallbackArgs): Promise<IVerifyCredentialResult> => {
  const keyPair = await getKeyPair();
  const suite = new Ed25519Signature2020({key: keyPair});
  const { defaultDocumentLoader } = vc;

  return await vc.verifyCredential({ credential: args.credential, suite, documentLoader: defaultDocumentLoader });
}

const verifier: WellKnownDidVerifier = new WellKnownDidVerifier();

const didConfigurationResource = {
  '@context': 'https://identity.foundation/.well-known/did-configuration/v1',
  linked_dids: [
    {
      '@context': [
        'https://www.w3.org/2018/credentials/v1',
        'https://identity.foundation/.well-known/did-configuration/v1'
      ],
      'issuer': 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM',
      'issuanceDate': '2020-12-04T14:08:28-06:00',
      'expirationDate': '2025-12-04T14:08:28-06:00',
      'type': [
        'VerifiableCredential',
        'DomainLinkageCredential'
      ],
      'credentialSubject': {
        'id': 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM',
        'origin': 'https://identity.foundation'
      },
      'proof': {
        'type': 'Ed25519Signature2018',
        'created': '2020-12-04T20:08:28.540Z',
        'jws': 'eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..D0eDhglCMEjxDV9f_SNxsuU-r3ZB9GR4vaM9TYbyV7yzs1WfdUyYO8rFZdedHbwQafYy8YOpJ1iJlkSmB4JaDQ',
        'proofPurpose': 'assertionMethod',
        'verificationMethod': 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM#z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM'
      },
      'eyJhbGciOiJSUzI1NiIsImtpZCI6ImRpZDprZXk6ejZNa29USHNnTk5yYnk4SnpDTlExaVJMeVc1UVE2UjhYdXU2QUE4aWdHck1WUFVNI3o2TWtvVEhzZ05OcmJ5OEp6Q05RMWlSTHlXNVFRNlI4WHV1NkFBOGlnR3JNVlBVTSJ9.eyJleHAiOjE3NjQ4NzkxMzksImlzcyI6ImRpZDprZXk6b3RoZXIiLCJuYmYiOjE2MDcxMTI3MzksInN1YiI6ImRpZDprZXk6b3RoZXIiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vaWRlbnRpdHkuZm91bmRhdGlvbi8ud2VsbC1rbm93bi9kaWQtY29uZmlndXJhdGlvbi92MSJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDprZXk6b3RoZXIiLCJvcmlnaW4iOiJodHRwczovL2lkZW50aXR5LmZvdW5kYXRpb24ifSwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTEyLTA0VDE0OjEyOjE5LTA2OjAwIiwiaXNzdWFuY2VEYXRlIjoiMjAyMC0xMi0wNFQxNDoxMjoxOS0wNjowMCIsImlzc3VlciI6ImRpZDprZXk6b3RoZXIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRG9tYWluTGlua2FnZUNyZWRlbnRpYWwiXX19.rRuc-ojuEgyq8p_tBYK7BayuiNTBeXNyAnC14Rnjs-jsnhae4_E1Q12W99K2NGCGBi5KjNsBcZmdNJPxejiKPrjjcB99poFCgTY8tuRzDjVo0lIeBwfx9qqjKHTRTUR8FGM_imlOpVfBF4AHYxjkHvZn6c9lYvatYcDpB2UfH4BNXkdSVrUXy_kYjpMpAdRtyCAnD_isN1YpEHBqBmnfuVUbYcQK5kk6eiokRFDtWruL1OEeJMYPqjuBSd2m-H54tSM84Oic_pg2zXDjjBlXNelat6MPNT2QxmkwJg7oyewQWX2Ot2yyhSp9WyAQWMlQIe2x84R0lADUmZ1TPQchNw'
    ],
  };

  verifier.verifyResource({ 
    configuration: didConfigurationResource,
    did: 'did:key:z6MkoTHsgNNrby8JzCNQ1iRLyW5QQ6R8Xuu6AA8igGrMVPUM',
    verifySignatureCallback: (args: IVerifyCallbackArgs) => verifySignatureCallback(args),
  })
  .then(result => 'success')
  .catch(error => 'failed');
 ```

### Build
```shell
yarn build
```

### Test
The test command runs:
* `eslint`
* `prettier`
* `unit`
* `coverage`

You can also run only a single section of these tests, using for example `yarn test:unit`.
```shell
yarn test
```

### Utility scripts
There are several other utility scripts that help with development.

* `yarn fix` - runs `eslint --fix` as well as `prettier` to fix code style.
* `yarn cov` - generates code coverage report.
