Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: vc api for the holder and the verifier #107

Merged
merged 12 commits into from
Jul 6, 2023
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
17 changes: 9 additions & 8 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@
"@vckit/remote-client": "^1.0.0-beta.5",
"@vckit/remote-server": "^1.0.0-beta.5",
"@vckit/renderer": "^1.0.0-beta.5",
"@veramo/credential-eip712": "^5.1.2",
"@veramo/credential-ld": "^5.1.2",
"@veramo/credential-w3c": "^5.1.2",
"@veramo/data-store": "^5.1.2",
"@veramo/did-comm": "^5.1.2",
"@vckit/vc-api": "workspace:1.0.0-beta.5",
"@veramo/credential-eip712": "^5.2.0",
"@veramo/credential-ld": "^5.2.0",
"@veramo/credential-w3c": "^5.2.0",
"@veramo/data-store": "^5.2.0",
"@veramo/did-comm": "^5.2.0",
"@veramo/did-discovery": "^5.1.2",
"@veramo/did-jwt": "^5.1.2",
"@veramo/did-jwt": "^5.2.0",
"@veramo/did-manager": "^5.1.2",
"@veramo/did-provider-ethr": "^5.1.2",
"@veramo/did-provider-key": "^5.1.2",
"@veramo/did-provider-key": "^5.2.0",
"@veramo/did-provider-pkh": "^5.1.2",
"@veramo/did-provider-web": "^5.1.2",
"@veramo/did-resolver": "^5.1.2",
Expand All @@ -64,7 +65,7 @@
"@veramo/message-handler": "^5.1.2",
"@veramo/selective-disclosure": "^5.1.2",
"@veramo/url-handler": "^5.1.2",
"@veramo/utils": "^5.1.2",
"@veramo/utils": "^5.2.0",
"blessed": "^0.1.81",
"commander": "^10.0.0",
"console-table-printer": "^2.10.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-ld/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@transmute/json-web-signature": "^0.7.0-unstable.79",
"@vckit/core-types": "^1.0.0-beta.5",
"@veramo-community/lds-ecdsa-secp256k1-recovery2020": "uport-project/EcdsaSecp256k1RecoverySignature2020",
"@veramo/utils": "^5.1.2",
"@veramo/utils": "^5.2.0",
"cross-fetch": "^3.1.5",
"debug": "^4.3.3",
"did-resolver": "^4.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-oa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@govtechsg/open-attestation": "^6.6.0",
"@vckit/core-types": "^1.0.0-beta.5",
"@veramo/message-handler": "^5.1.2",
"@veramo/utils": "^5.1.2"
"@veramo/utils": "^5.2.0"
},
"devDependencies": {
"@types/debug": "4.1.7",
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-w3c/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@govtechsg/open-attestation": "^6.6.0",
"@vckit/core-types": "^1.0.0-beta.5",
"@veramo/message-handler": "^5.1.2",
"@veramo/utils": "^5.1.2",
"@veramo/utils": "^5.2.0",
"canonicalize": "^1.0.8",
"debug": "^4.3.3",
"did-jwt": "^6.11.0",
Expand Down
4 changes: 3 additions & 1 deletion packages/remote-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
"@vckit/app": "^1.0.0-beta.4",
"@vckit/core-types": "^1.0.0-beta.5",
"@vckit/remote-client": "^1.0.0-beta.5",
"@veramo/utils": "5.2.0",
"debug": "^4.3.3",
"did-resolver": "^4.0.1",
"express": "^4.18.2",
"passport": "^0.6.0",
"passport-http-bearer": "^1.0.1",
"url-parse": "^1.5.4"
"url-parse": "^1.5.4",
"uint8arrays": "^4.0.3"
},
"devDependencies": {
"@types/debug": "4.1.7",
Expand Down
105 changes: 67 additions & 38 deletions packages/remote-server/src/web-did-doc-router.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import { IIdentifier, IDIDManager, TAgent, TKeyType } from '@vckit/core-types'
import { Request, Router } from 'express'
import { ServiceEndpoint } from 'did-resolver'
import { IIdentifier, IDIDManager, TAgent, TKeyType } from '@vckit/core-types';
import { Request, Router } from 'express';
import { ServiceEndpoint } from 'did-resolver';
import * as u8a from 'uint8arrays';

interface RequestWithAgentDIDManager extends Request {
agent?: TAgent<IDIDManager>
agent?: TAgent<IDIDManager>;
}

/**
* The URL path to the DID document, used by did:web when the identifier is a hostname.
*
* @public
*/
export const didDocEndpoint = '/.well-known/did.json'
export const didDocEndpoint = '/.well-known/did.json';

const keyMapping: Record<TKeyType, string> = {
Secp256k1: 'EcdsaSecp256k1VerificationKey2019',
Secp256r1: 'EcdsaSecp256r1VerificationKey2019',
Ed25519: 'Ed25519VerificationKey2018',
X25519: 'X25519KeyAgreementKey2019',
Ed25519: 'Ed25519VerificationKey2020',
X25519: 'X25519KeyAgreementKey2020',
Bls12381G1: 'Bls12381G1Key2020',
Bls12381G2: 'Bls12381G2Key2020',
}
};

/**
* @public
*/
export interface WebDidDocRouterOptions {
services?: ServiceEndpoint[]
services?: ServiceEndpoint[];
}

/**
Expand All @@ -38,22 +39,26 @@ export interface WebDidDocRouterOptions {
* @public
*/
export const WebDidDocRouter = (options: WebDidDocRouterOptions): Router => {
const router = Router()
const router = Router();

const didDocForIdentifier = (identifier: IIdentifier) => {
const allKeys = identifier.keys.map((key) => ({
id: identifier.did + '#' + key.kid,
type: keyMapping[key.type],
controller: identifier.did,
publicKeyHex: key.publicKeyHex,
}))
publicKeyMultibase: hexToMultibase(key.publicKeyHex),
}));
// ed25519 keys can also be converted to x25519 for key agreement
const keyAgreementKeyIds = allKeys
.filter((key) => ['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019'].includes(key.type))
.map((key) => key.id)
.filter((key) =>
['Ed25519VerificationKey2020', 'X25519KeyAgreementKey2020'].includes(
key.type
)
)
.map((key) => key.id);
const signingKeyIds = allKeys
.filter((key) => key.type !== 'X25519KeyAgreementKey2019')
.map((key) => key.id)
.filter((key) => key.type !== 'X25519KeyAgreementKey2020')
.map((key) => key.id);

const didDoc = {
'@context': 'https://w3id.org/did/v1',
Expand All @@ -63,42 +68,66 @@ export const WebDidDocRouter = (options: WebDidDocRouterOptions): Router => {
assertionMethod: signingKeyIds,
keyAgreement: keyAgreementKeyIds,
service: [...(options?.services || []), ...(identifier?.services || [])],
}
};

return didDoc
}
return didDoc;
};

const getAliasForRequest = (req: Request) => {
return encodeURIComponent(req.get('host') || req.hostname)
}
return encodeURIComponent(req.get('host') || req.hostname);
};

router.get(didDocEndpoint, async (req: RequestWithAgentDIDManager, res) => {
if (req.agent) {
try {
const serverIdentifier = await req.agent.didManagerGet({
did: 'did:web:' + getAliasForRequest(req),
})
const didDoc = didDocForIdentifier(serverIdentifier)
res.json(didDoc)
});
const didDoc = didDocForIdentifier(serverIdentifier);
res.json(didDoc);
} catch (e) {
res.status(404).send(e)
res.status(404).send(e);
}
}
})
});

router.get(/^\/(.+)\/did.json$/, async (req: RequestWithAgentDIDManager, res) => {
if (req.agent) {
try {
const identifier = await req.agent.didManagerGet({
did: 'did:web:' + getAliasForRequest(req) + ':' + req.params[0].replace(/\//g, ':'),
})
const didDoc = didDocForIdentifier(identifier)
res.json(didDoc)
} catch (e) {
res.status(404).send(e)
router.get(
/^\/(.+)\/did.json$/,
async (req: RequestWithAgentDIDManager, res) => {
if (req.agent) {
try {
const identifier = await req.agent.didManagerGet({
did:
'did:web:' +
getAliasForRequest(req) +
':' +
req.params[0].replace(/\//g, ':'),
});
const didDoc = didDocForIdentifier(identifier);
res.json(didDoc);
} catch (e) {
res.status(404).send(e);
}
}
}
})
);

return router;
};

/**
* Converts a hex string to a multibase encoded string
* The sourcecode is copied from https://github.com/uport-project/veramo/pull/1082/files#
*/

const MULTIBASE_BASE58BTC_PREFIX = 'z';
const MULTICODEC_PREFIX = [0xed, 0x01];

return router
function hexToMultibase(hexString: string): string {
const hexBytes = u8a.fromString(hexString, 'hex');
const modifiedKey = u8a.concat([MULTICODEC_PREFIX, hexBytes]);
return `${MULTIBASE_BASE58BTC_PREFIX}${u8a.toString(
modifiedKey,
'base58btc'
)}`;
}
103 changes: 79 additions & 24 deletions packages/vc-api/README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,94 @@
# vc-api agent router
# vc-api Router

- This agent router conform to vc-api standard that to achieve interoperability's goal between various parties.
This repository contains an agent router that adheres to the vc-api standard, aiming to achieve interoperability between various parties.

## Usage

- This plugin follow the `veramo` architecture , so you can configure it with `agent.yml`
The router follows the `veramo` architecture, allowing you to configure it using the `agent.yml` file. Below is an example of how to set up the router with different functionalities:

```jsx
```yaml
# API base path
- - /issuer
- $require: '@vckit/vc-api-issuer?t=function#AgentRouter'
$args:
- createCredential: createVerifiableCredential
updateCredentialStatus: updateVerifiableCredentialStatus
- - $require: '@vckit/vc-api?t=function#HolderRouter'
- - $require: '@vckit/vc-api?t=function#IssuerRouter'
$args:
- createCredential: createVerifiableCredential
updateCredentialStatus: updateVerifiableCredentialStatus
- - $require: '@vckit/vc-api?t=function#VerifierRouter'
$args:
- verifyCredential: verifyCredential
verifyPresentation: verifyPresentation

# VC API docs path
- - /vc-api.json
- $require: '@vckit/vc-api?t=function#VCApiSchemaRouter'
$args:
- basePath: :3332

- - /vc-api-docs
- $require: '@vckit/vc-api?t=function#VCApiDocsRouter'
```

## Test with test-suite

- Clone the test suite: https://github.com/w3c-ccg/vc-api-issuer-test-suite
- Go to `node_modules/vc-api-test-suite-implementations/implementations` , create files except the index file
- Create new implementation file:
To test the agent router, you can use the vc-api test suite. Follow the steps below:

1. Clone the test suite repositories: vc-api-issuer-test-suite and vc-api-verifier-test-suite.

2. Navigate to node_modules/vc-api-test-suite-implementations/implementations, and create a new implementation file with the following content:

```jsx
```json
{
"name": "GoSource",
"implementation": "GoSource Verifiable Credentials",
"issuers": [{
"id": "YOUR_DID_MANAGED_BY_YOUR_KMS",
"endpoint": "http://localhost:3332/agent/credentials/issue",
"options": {
"type": "Ed25519Signature2020"
},
"tags": ["vc-api", "Ed25519Signature2020"]
}]
"name": "XYZ",
"implementation": "Verifiable Credentials",
"issuers": [
{
"id": "DID_WEB",
"endpoint": "http://localhost:3332/credentials/issue",
"method": "POST",
"tags": ["vc-api", "Ed25519Signature2020"]
}
],
"verifiers": [
{
"id": "DID_WEB",
"endpoint": "http://localhost:3332/credentials/verify",
"method": "POST",
"tags": ["vc-api", "Ed25519Signature2020"]
}
]
}
```

- Run the test command `npm run test`
3. Modify the W3C credentialPlugin in `agent.yml` to use the appropriate signature suite. For example, if the test suite is using `Ed25519Signature2020`, replace `VeramoEd25519Signature2018` with `VeramoEd25519Signature2020`:

```yaml
# W3C credentialPlugin
credentialIssuerLD:
$require: '@veramo/credential-ld#CredentialIssuerLD'
$args:
- suites:
- $require: '@veramo/credential-ld#VeramoEd25519Signature2020'
- $require: '@veramo/credential-ld#VeramoEcdsaSecp256k1RecoverySignature2020'
contextMaps:
# The LdDefaultContext is a "catch-all" for now.
- $require: '@veramo/credential-ld?t=object#LdDefaultContexts'
- $require: '@transmute/credentials-context?t=object#contexts'
# others should be included here
```

4. Create a `did:web` by using the API, as shown in the following example using `curl`:

```bash
curl -X POST "http://localhost:3332/agent/didManagerCreate" \
-H "accept: application/json; charset=utf-8"\
-H "authorization: Bearer test123"\
-H "content-type: application/json" \
-d '{"alias":"ngrok_host","provider":"did:web","kms":"local","options":{"keyType":"Ed25519"}}'

```

Replace `ngrok_host` with the host of your ngrok tunnel on port 3332.

5. Update the implementation file with your newly created `did:web`.

6. Run the test command: `npm run test`.
Loading