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
5 changes: 5 additions & 0 deletions .changeset/two-moons-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web5/dids": patch
---

DID:DHT - Only have <ID>. suffix for Root and Gateway Record names
2 changes: 1 addition & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The format is described: https://github.blog/2017-07-06-introducing-code-owners/

# These owners will be the default owners for everything in the repo.
* @frankhinek @csuwildcat @mistermoe
* @frankhinek @csuwildcat @mistermoe @thehenrytsai

# These are owners of any file in the `common`, `crypto`, `crypto-aws-kms`, `dids`, and
# `credentials` packages and their sub-directories.
Expand Down
2 changes: 1 addition & 1 deletion packages/dids/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"type": "node",
"request": "launch",
"name": "test:node",
"runtimeExecutable": "${workspaceFolder:dids}/node_modules/.bin/mocha",
"runtimeExecutable": "${workspaceFolder:dids}/../../node_modules/.bin/mocha",
"console": "internalConsole",
"preLaunchTask": "build tests",
"skipFiles": [
Expand Down
17 changes: 11 additions & 6 deletions packages/dids/src/methods/did-dht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1255,16 +1255,11 @@ export class DidDhtDocument {
// Add a DNS TXT record for the root record.
dnsAnswerRecords.push({
type : 'TXT',
name : '_did.',
name : '_did.' + DidDhtDocument.getUniqueDidSuffix(didDocument.id) + '.', // name of a Root Record MUST end in `<ID>.`
ttl : DNS_RECORD_TTL,
data : rootRecord.join(PROPERTY_SEPARATOR)
});

// Per the DID DHT specification, the method-specific identifier must be appended as the
// Origin of all records.
const [, , identifier] = didDocument.id.split(':');
dnsAnswerRecords.forEach(record => record.name += identifier);

// Create a DNS response packet with the authoritative answer flag set.
const dnsPacket: Packet = {
id : 0,
Expand All @@ -1275,6 +1270,16 @@ export class DidDhtDocument {

return dnsPacket;
}

/**
* Gets the unique portion of the DID identifier after the last `:` character.
* e.g. `did:dht:example` -> `example`
*
* @param did - The DID to extract the unique suffix from.
*/
private static getUniqueDidSuffix(did: string ): string {
return did.split(':')[2];
}
}

/**
Expand Down
16 changes: 8 additions & 8 deletions packages/dids/src/types/did-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,18 +563,18 @@ export enum DidVerificationRelationship {
keyAgreement = 'keyAgreement',

/**
* Specifies a mechanism used by the DID subject to delegate a cryptographic capability to another
* party. This can include delegating access to a specific resource or API.
* Specifies a verification method used by the DID subject to invoke a cryptographic capability.
* This is frequently associated with authorization actions, like updating the DID Document.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-delegation | DID Core Specification, § Capability Delegation}
* @see {@link https://www.w3.org/TR/did-core/#capability-invocation | DID Core Specification, § Capability Invocation}
*/
capabilityDelegation = 'capabilityDelegation',
capabilityInvocation = 'capabilityInvocation',

/**
* Specifies a verification method used by the DID subject to invoke a cryptographic capability.
* This is frequently associated with authorization actions, like updating the DID Document.
* Specifies a mechanism used by the DID subject to delegate a cryptographic capability to another
* party. This can include delegating access to a specific resource or API.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-invocation | DID Core Specification, § Capability Invocation}
* @see {@link https://www.w3.org/TR/did-core/#capability-delegation | DID Core Specification, § Capability Delegation}
*/
capabilityInvocation = 'capabilityInvocation'
capabilityDelegation = 'capabilityDelegation',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
"verificationMethod": [
{
"id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0",
"type": "JsonWebKey",
"controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
"publicKeyJwk": {
"kid": "0",
"alg": "Ed25519",
"crv": "Ed25519",
"kty": "OKP",
"x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
}
}
],
"authentication": [
"did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
],
"assertionMethod": [
"did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
],
"capabilityInvocation": [
"did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
],
"capabilityDelegation": [
"did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"name": "_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo.",
"type": "TXT",
"ttl": 7200,
"rdata": "v=0;vm=k0;auth=k0;asm=k0;inv=k0;del=k0"
},
{
"name": "_k0._did.",
"type": "TXT",
"ttl": 7200,
"rdata": "id=0;t=0;k=YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
}
]
46 changes: 39 additions & 7 deletions packages/dids/tests/methods/did-dht.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import type { PortableDid } from '../../src/types/portable-did.js';

import sinon from 'sinon';
import resolveTestVectors from '../../../../web5-spec/test-vectors/did_dht/resolve.json' assert { type: 'json' };
import officialTestVector1DidDocument from '../fixtures/test-vectors/did-dht/vector-1-did-document.json' assert { type: 'json' };
import officialTestVector1DnsRecords from '../fixtures/test-vectors/did-dht/vector-1-dns-records.json' assert { type: 'json' };

import { expect } from 'chai';
import { Convert } from '@web5/common';

import type { PortableDid } from '../../src/types/portable-did.js';

import { DidDocument } from '../../src/index.js';
import { DidErrorCode } from '../../src/did-error.js';
import { DidDht, DidDhtDocument, DidDhtRegisteredDidType } from '../../src/methods/did-dht.js';

import DidDhtResolveTestVector from '../../../../web5-spec/test-vectors/did_dht/resolve.json' assert { type: 'json' };

// Helper function to create a mocked fetch response that fails and returns a 404 Not Found.
const fetchNotFoundResponse = () => ({
status : 404,
Expand Down Expand Up @@ -431,10 +433,15 @@ describe('DidDht', () => {

it('throws an error if the resulting DID document would exceed the 1000 byte maximum', async () => {
try {
// Attempt to create a DID with 6 verification methods (Identity Key plus 5 additional).
// Attempt to create a DID with DID Document that exceeds the maximum size.
await DidDht.create({
options: {
verificationMethods: [
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
{ algorithm: 'Ed25519' },
Expand Down Expand Up @@ -1153,10 +1160,35 @@ describe('DidDhtDocument', () => {

describe('Web5TestVectorsDidDht', () => {
it('resolve', async () => {
for (const vector of DidDhtResolveTestVector.vectors as any[]) {
for (const vector of resolveTestVectors.vectors as any[]) {
Comment thread
thehenrytsai marked this conversation as resolved.
const didResolutionResult = await DidDht.resolve(vector.input.didUri);
expect(didResolutionResult.didResolutionMetadata.error).to.equal(vector.output.didResolutionMetadata.error);
}
}).timeout(30000); // Set timeout to 30 seconds for this test for did:dht resolution timeout test
});
});

// vectors come from https://did-dht.com/#test-vectors
describe('Official DID:DHT Vector tests', () => {
Comment thread
nitro-neal marked this conversation as resolved.
it('vector 1', async () => {
const dnsPacket = await DidDhtDocument.toDnsPacket({
didDocument : officialTestVector1DidDocument as DidDocument,
didMetadata : { published: false }
});

expect(dnsPacket.answers).to.have.length(officialTestVector1DnsRecords.length);

// NOTE: the DNS library we use uses name `data` instead of `rdata` used in DID:DHT spec,
// but prefer to keep the naming in test vector files identical to that of the DID:DHT spec,
// hence this additional normalization step
const normalizedConstructedRecords = dnsPacket.answers!.map(record => {
const { data: rdata, ...otherProperties } = record;
return {
...otherProperties,
rdata
};
});

expect(normalizedConstructedRecords).to.deep.include.members(officialTestVector1DnsRecords);
});
});
8 changes: 7 additions & 1 deletion web5-js.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@
"editor.codeActionsOnSave": {
"source.fixAll": "always"
},
"typescript.tsdk": "root/node_modules/typescript/lib"
"typescript.tsdk": "root/node_modules/typescript/lib",
"search.exclude": {
"**/dist/**": true,
"**/coverage/**": true,
"**/compiled/**": true

}
},
"launch": {
"version": "0.2.0",
Expand Down