Skip to content

Update did key v7 #3

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

Open
wants to merge 55 commits into
base: initial
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
74f3911
Start work on did & did:key errors & validation.
aljones15 Jul 29, 2022
e2b3a32
Add DidResolutionResult class and use it.
aljones15 Jul 29, 2022
c28c251
Use more except didKeyComponents over didComponents.
aljones15 Jul 29, 2022
38fde21
Correct mistake Number.parseInt not Number.parse.
aljones15 Jul 29, 2022
1299da9
Update lint stuff.
aljones15 Jul 29, 2022
34fc90d
Up engine to 16 & improve error reporting code.
aljones15 Jul 29, 2022
a17e0ea
Remove use strict & correct invalid jsdoc param.
aljones15 Jul 30, 2022
e26070b
Use bnid for public key length errors.
aljones15 Aug 1, 2022
d0b1f22
Use @bedrock/did-io latest.
aljones15 Aug 1, 2022
29b57ec
Convert to es6 module.
aljones15 Aug 1, 2022
992b590
Add MULTICODEC ed25519 header and get bytes.
aljones15 Aug 1, 2022
6dc9f64
Add check for invalidDidUrl.
aljones15 Aug 2, 2022
510f909
Add better tests for isDiDUrl & component split.
aljones15 Aug 2, 2022
963ab56
Get identifier & isDidUrl.
aljones15 Aug 2, 2022
6248cb6
Better separation of did url and identifier logic.
aljones15 Aug 2, 2022
bea2e99
Separate validators better.
aljones15 Aug 3, 2022
0a2e89f
Implement 100% success with latest did:key spec.
aljones15 Aug 3, 2022
38bc2cf
Update github actions node versions to 14 and 16 + .npmrc for legacy …
aljones15 Aug 3, 2022
98b2212
Add .npmrc to test project.
aljones15 Aug 3, 2022
cb0c52e
Upgrade github workflows to mongodb 4.4 add more install steps.
aljones15 Aug 3, 2022
ed6989f
Add statusCodes to errors.
aljones15 Aug 3, 2022
e2299ea
Add basic tests to test project.
aljones15 Aug 3, 2022
ad39610
Use c8 for coverage.
aljones15 Aug 3, 2022
7e69c10
Fully capitalize JSON-LD.
aljones15 Aug 3, 2022
c40562c
Capitalize DID in error message.
aljones15 Aug 3, 2022
629b79a
Separate publicKey into public key.
aljones15 Aug 3, 2022
ef6af7a
Expect whole thing and not part of a string.
aljones15 Aug 3, 2022
177f622
Remove validators moved to did-io.
aljones15 Aug 5, 2022
bc44d0b
Remove did key related validators.
aljones15 Aug 5, 2022
02c977c
Remove lib/didComponents, didErrors, & bnid.
aljones15 Aug 8, 2022
ae77629
Add @db/did-io to peerDeps & isDidUrl & parseDid.
aljones15 Aug 8, 2022
a47725f
Remove didKey and didResolution error files in favor of DidResolution…
aljones15 Aug 8, 2022
6aea527
Add function to turn error codes into statusCodes.
aljones15 Aug 8, 2022
23e0f63
Remove validators dir & make it a file.
aljones15 Aug 8, 2022
3364e4a
Switch route to /1.0/identifiers/resolve/:did.
aljones15 Aug 8, 2022
2c1c0d5
Improve naming of errorCodeToStatusCode & hasDereferencingMetadata.
aljones15 Aug 9, 2022
99ca721
Move metadata detection into DidResolutionResult.
aljones15 Aug 9, 2022
a05ff0e
Remove request options & move to did-method-key.
aljones15 Aug 9, 2022
d9d4794
Add formatResponse to handle requests that don't want metadata.
aljones15 Aug 9, 2022
db32c3a
Correct test makeRequest basePath.
aljones15 Aug 9, 2022
40eed63
Sort status codes ascending & add 501 for methodNotSupported.
aljones15 Aug 10, 2022
16d594f
Remove experimental from supportedMethods.
aljones15 Aug 10, 2022
8b06c20
Make supported methods a Set.
aljones15 Aug 10, 2022
d88e2de
Remove logic for supportedMethods.
aljones15 Aug 11, 2022
81a8d70
Use node 16-18 in ci actions.
aljones15 Aug 12, 2022
337f2ff
Remove unneeded line from https.js.
aljones15 Aug 15, 2022
4f16b24
Remove 'use strict' from logger.js.
aljones15 Aug 15, 2022
b25d609
Remove extra line in helpers.js.
aljones15 Aug 15, 2022
297950b
Remove 'use strict' from test.config.js.
aljones15 Aug 15, 2022
06560a3
Remove extra line from test.js.
aljones15 Aug 15, 2022
e83a8ce
Better document did and resolver options.
aljones15 Aug 15, 2022
5e918ab
Add @db/http-client to test project.
aljones15 Aug 15, 2022
c4ff86b
Change nyc opts to c8 opts.
aljones15 Aug 23, 2022
cae41cc
Remove assertNoError from lint test globals.
aljones15 Aug 23, 2022
809aaa3
Correct typo in jsdoc string for didOptions.
aljones15 Dec 29, 2022
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
14 changes: 14 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
env: {
node: true
},
extends: [
'eslint-config-digitalbazaar',
'eslint-config-digitalbazaar/jsdoc',
'eslint-config-digitalbazaar/module',
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
}
};
7 changes: 0 additions & 7 deletions .eslintrc.js

This file was deleted.

12 changes: 7 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [14.x]
node-version: [16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand All @@ -24,19 +24,20 @@ jobs:
timeout-minutes: 10
services:
mongodb:
image: mongo:4.2
image: mongo:4.4
ports:
- 27017:27017
strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: |
npm install
cd test
npm install
- name: Run test with Node.js ${{ matrix.node-version }}
Expand All @@ -49,19 +50,20 @@ jobs:
timeout-minutes: 10
services:
mongodb:
image: mongo:4.2
image: mongo:4.4
ports:
- 27017:27017
strategy:
matrix:
node-version: [14.x]
node-version: [16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: |
npm install
cd test
npm install
- name: Generate coverage report
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
36 changes: 36 additions & 0 deletions lib/DidResolutionResult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
* Copyright (c) 2022 Digital Bazaar, Inc. All rights reserved.
*/
import {isDidUrl} from '@digitalbazaar/did-io';

/**
* Creates the JSON-LD for the response.
*
* @param {object} options - Options to use.
* @param {string} [options.did=''] - The did being resolved.
* @param {object} [options.didDocument={}] - The didDocument for the
* response.
* @param {object|null} [options.didDocumentMetadata=null] - Meta data
* for the didDocument.
* @param {Error} options.error - An error if any was raised.
*/
export class DidResolutionResult {
constructor({
did = '',
didDocument = {},
didDocumentMetadata = null,
error
}) {
this['@context'] = 'https://w3id.org/did-resolution/v1';
this.didDocument = didDocument;
this.didDocumentMetadata = didDocumentMetadata;
const hasDereferencingMetadata = isDidUrl({did});
const metadataProperty = hasDereferencingMetadata ?
'didDereferencingMetadata' : 'didResolutionMetadata';
this[metadataProperty] = {};
// only define error if it was passed in
if(error) {
this[metadataProperty].error = error.code || 'internalError';
}
}
}
8 changes: 2 additions & 6 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
/*!
* Copyright (c) 2021 Digital Bazaar, Inc. All rights reserved.
*/
import bedrock from 'bedrock';
const {config} = bedrock;
import {config} from '@bedrock/core';

const namespace = 'bedrock-did-resolver-http';
const cfg = config[namespace] = {};

// support did:key and veres one keys by default
cfg.supportedMethods = ['key', 'v1'];

const basePath = '/1.0/resolve/identifiers/:did';
const basePath = '/1.0/identifiers/resolve/:did';
cfg.routes = {basePath};
152 changes: 152 additions & 0 deletions lib/didResolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*!
* Copyright (c) 2022 Digital Bazaar, Inc. All rights reserved.
*/
import {didIo} from '@bedrock/did-io';
import {DidResolutionResult} from './DidResolutionResult.js';
import logger from './logger.js';

/**
* Resolves a did after validating it.
*
* @param {object} options - Options to use.
* @param {string} options.did - The did or didUrl being resolved.
* @param {object} options.didOptions - Options to be passed to the did
* method driver.
* @param {object} options.resolverOptions - Options for the resolver such as
* the format of the response data.
*
* @returns {object} - Returns a status code and the resolution data.
*/
export const resolveDid = async ({
did,
didOptions: rawOptions,
resolverOptions
}) => {
let error;
let didDocument;
try {
const didOptions = _convertDidOptions({didOptions: rawOptions});
didDocument = await didIo.get({did, options: didOptions});
} catch(e) {
logger.error(`DID resolution error: ${did}`, {error: e});
error = e;
}
return _formatResponse({resolverOptions, didDocument, error, did});
};

/**
* Did Resolvers can return the didDocument itself or wrapped with metadata.
*
* @private
*
* @param {object} options - Options to use.
* @param {object} options.resolverOptions - Options for the did resolver
* usually found in headers.
* @param {object} options.didDocument - A didDocument.
* @param {Error} [options.error] - An error.
* @param {string} options.did - The did being resolved or derefernced.
*
* @returns {{statusCode: number, resolutionResult: object}} - What to return
* as the response.
*/
function _formatResponse({resolverOptions, didDocument, error, did}) {
const {accept = ''} = resolverOptions;
const didResolutionContext = 'https://w3id.org/did-resolution';
const addMetadata = accept.includes(didResolutionContext);
if(!addMetadata) {
if(error) {
throw error;
}
return {
// FIXME services are not handled here yet
statusCode: 200,
resolutionResult: didDocument
};
}
return {
//FIXME services should return 303
statusCode: error ? _errorCodeToStatusCode({code: error.code}) : 200,
resolutionResult: new DidResolutionResult({did, didDocument, error})
};
}

/**
* Matches an error.code to a status code or 500.
*
* @see https://w3c-ccg.github.io/did-resolution/
* @private
*
* @param {object} options - Options to use.
* @param {string} options.code - An error.
*
* @returns {number} - An http status code.
*/
function _errorCodeToStatusCode({code}) {
const statuses = [
// if the did resolves to a service return 303
{statusCode: 303, codes: ['service']},
{
statusCode: 400,
// FIXME these codes should have more specific statusCodes soon
codes: [
'invalidDid',
'invalidDidUrl',
'unsupportedPublicKeyType',
'invalidPublicKeyType',
'invalidPublicKey',
'invalidPublicKeyLength'
]
},
{statusCode: 404, codes: ['notFound']},
// if the did has been deactivated return 410
{statusCode: 410, codes: ['deactivated']},
{statusCode: 406, codes: ['representationNotSupported']},
{statusCode: 500, codes: ['internalError']},
{statusCode: 501, codes: ['methodNotSupported']},
];
const {statusCode = 500} = statuses.find(
({codes}) => codes.includes(code)) || {};
return statusCode;
}

// takes in search params / url queries
// and then converts properties that should be booleans
// to booleans
function _convertDidOptions({didOptions}) {
if(!didOptions) {
return;
}
if(didOptions.enableExperimentalPublicKeyTypes) {
didOptions.enableExperimentalPublicKeyTypes = _convertSearchParamToBoolean({
param: didOptions.enableExperimentalPublicKeyTypes
});
}
return didOptions;
}

/**
* Search Params are encoded as strings so this turns
* strings of value '0' or 'false' into false.
*
* @param {object} options - Options to use.
* @param {string} options.param - The param value.
*
* @returns {boolean} Returns a boolean.
*/
function _convertSearchParamToBoolean({param}) {
if(typeof param !== 'string') {
return Boolean(param);
}
// the param must start & end with one of these values ignoring case
const booleanParam = /^((?<false>0|false)|(?<true>1|true))$/i;
const {groups} = booleanParam.exec(param.trim()) || {};
if(!groups) {
throw new Error(
`Expected search param to be 0, "false", 1, or "true" received ${param}`);
}
// if we captured a false value return false
if(groups.false !== undefined) {
return false;
}
return true;
}
69 changes: 22 additions & 47 deletions lib/http.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
/*!
* Copyright (c) 2022 Digital Bazaar, Inc. All rights reserved.
*/
import {asyncHandler} from 'bedrock-express';
import bedrock from 'bedrock';
import {didIo} from 'bedrock-did-io';
import logger from './logger';
import * as bedrock from '@bedrock/core';
import {asyncHandler} from '@bedrock/express';
import logger from './logger.js';
import {resolveDid} from './didResolver.js';
const {config} = bedrock;

bedrock.events.on('bedrock-express.configure.routes', app => {
const {routes, supportedMethods} = config['bedrock-did-resolver-http'];
const {
routes,
supportedMethods,
} = config['bedrock-did-resolver-http'];
app.get(
routes.basePath,
asyncHandler(async (req, res) => {
// this can be resolution or dereferencing meta data
const metaData = {};
const resolutionResult = {
'@context': 'https://w3id.org/did-resolution/v1',
didDocument: {},
didDocumentMetadata: null,
didResolutionMetadata: metaData
};
const {did} = req.params;
const parsedDid = new URL(did);
// if there is a fragment `#` or a service `?service`
// then we are dereferencing a did url
const didUrl = (parsedDid.hash || parsedDid.search);
if(didUrl) {
// add a did dereferencing meta
resolutionResult.didDereferencingMetadata = metaData;
// delete the resolution metadata
delete resolutionResult.didResolutionMetadata;
}
// the second value should always be the method
const [prefix, method, id] = did.split(':');
// a did must have a did prefix, method, and id
if(!((prefix === 'did') && method && id)) {
metaData.error = didUrl ? 'invalidDidUrl' : 'invalidDid';
return res.status(400).json(resolutionResult);
}
if(!supportedMethods.includes(method)) {
//FIXME this might not be the right error code
metaData.error = 'representationNotSupported';
return res.status(406).json(resolutionResult);
}
// did options are passed to the resolver via url queries
const didOptions = {...req.query};
// the accept header tells the resolver how to format the response data
const resolverOptions = {...req.headers};
try {
resolutionResult.didDocument = await didIo.get({did});
} catch(e) {
//FIXME the did resolver error could contain invalidDid, notFound,
//or representationNotSupported we need to check for those errors
//and newer errors and add that information in the future
logger.error('DID Resolution error', {error: e});
// the spec doesn't seem to handle what occurs if the
// did resolver fails for reasons unrelated to the did such
// as database timeouts.
metaData.error = 'InternalError';
return res.status(500).json(resolutionResult);
const {statusCode, resolutionResult} = await resolveDid({
did,
supportedMethods,
didOptions,
resolverOptions
});
res.status(statusCode).json(resolutionResult);
} catch(error) {
logger.error(`DID resolution error ${did}`, {error});
throw error;
}
res.json(resolutionResult);
}));
});
9 changes: 4 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/*!
* Copyright (c) 2021 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2021-2022 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';
import '@bedrock/express';

// translate `main.js` to CommonJS
require = require('esm')(module);
module.exports = require('./main.js');
import './config.js';
import './http.js';
4 changes: 1 addition & 3 deletions lib/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
/*!
* Copyright (c) 2022 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

import bedrock from 'bedrock';
import * as bedrock from '@bedrock/core';

const logger = bedrock.loggers.get('app').child('bedrock-did-resolver-http');

Expand Down
Loading