diff --git a/CODEOWNERS b/CODEOWNERS index b0f6d2cd7..eb01b33a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,19 +8,28 @@ # These owners will be the default owners for everything in the repo. * @frankhinek @csuwildcat @mistermoe @thehenrytsai @lirancohen +# These are owners who can approve folders under the root directory and other CICD and QoL directories. +# Should be the union list of all owners of sub-directories, optionally minus the default owners. +/* @diehuxx @shamilovtim @nitro-neal +/.changeset @diehuxx @shamilovtim @nitro-neal +/.codesandbox @diehuxx @shamilovtim @nitro-neal +/.github @diehuxx @shamilovtim @nitro-neal +/.vscode @diehuxx @shamilovtim @nitro-neal +/scripts @diehuxx @shamilovtim @nitro-neal + # These are owners of any file in the `common`, `crypto`, `crypto-aws-kms`, `dids`, and # `credentials` packages and their sub-directories. -/packages/common @diehuxx @mistermoe @frankhinek @thehenrytsai @nitro-neal -/packages/crypto @diehuxx @mistermoe @frankhinek @thehenrytsai -/packages/crypto-aws-kms @diehuxx @mistermoe @frankhinek @thehenrytsai -/packages/dids @diehuxx @mistermoe @frankhinek @thehenrytsai @nitro-neal -/packages/credentials @diehuxx @mistermoe @frankhinek @thehenrytsai @nitro-neal +/packages/common @diehuxx @thehenrytsai @nitro-neal +/packages/crypto @diehuxx @thehenrytsai +/packages/crypto-aws-kms @diehuxx @thehenrytsai +/packages/dids @diehuxx @thehenrytsai @nitro-neal +/packages/credentials @diehuxx @thehenrytsai @nitro-neal # These are owners of any file in the `agent`, `user-agent`, `proxy-agent`, `identity-agent`, and # `api` packages and their sub-directories. -/packages/agent @lirancohen @frankhinek @csuwildcat @mistermoe @shamilovtim -/packages/proxy-agent @lirancohen @frankhinek @csuwildcat @mistermoe @shamilovtim -/packages/user-agent @lirancohen @frankhinek @csuwildcat @mistermoe @shamilovtim -/packages/identity-agent @lirancohen @frankhinek @csuwildcat @mistermoe @shamilovtim -/packages/api @lirancohen @frankhinek @csuwildcat @mistermoe @shamilovtim @nitro-neal +/packages/agent @lirancohen @csuwildcat @shamilovtim +/packages/proxy-agent @lirancohen @csuwildcat @shamilovtim +/packages/user-agent @lirancohen @csuwildcat @shamilovtim +/packages/identity-agent @lirancohen @csuwildcat @shamilovtim +/packages/api @lirancohen @csuwildcat @shamilovtim @nitro-neal diff --git a/packages/dids/.c8rc.json b/packages/dids/.c8rc.json index c44b67aba..e96f8a5a3 100644 --- a/packages/dids/.c8rc.json +++ b/packages/dids/.c8rc.json @@ -14,6 +14,7 @@ ], "reporter": [ "cobertura", + "html", "text" ] } \ No newline at end of file diff --git a/packages/dids/src/methods/did-dht.ts b/packages/dids/src/methods/did-dht.ts index b5acb8b25..8add749c0 100644 --- a/packages/dids/src/methods/did-dht.ts +++ b/packages/dids/src/methods/did-dht.ts @@ -1,4 +1,4 @@ -import type { Packet, TxtAnswer, TxtData } from '@dnsquery/dns-packet'; +import type { Packet, StringAnswer, TxtAnswer, TxtData } from '@dnsquery/dns-packet'; import type { Jwk, Signer, @@ -533,17 +533,17 @@ export class DidDht extends DidMethod { // Generate random key material for the Identity Key and any additional verification methods. // Add verification methods to the DID document. - for (const vm of verificationMethodsToAdd) { + for (const verificationMethod of verificationMethodsToAdd) { // Generate a random key for the verification method, or if its the Identity Key's // verification method (`id` is 0) use the key previously generated. - const keyUri = (vm.id && vm.id.split('#').pop() === '0') + const keyUri = (verificationMethod.id && verificationMethod.id.split('#').pop() === '0') ? identityKeyUri - : await keyManager.generateKey({ algorithm: vm.algorithm }); + : await keyManager.generateKey({ algorithm: verificationMethod.algorithm }); const publicKey = await keyManager.getPublicKey({ keyUri }); // Use the given ID, the key's ID, or the key's thumbprint as the verification method ID. - let methodId = vm.id ?? publicKey.kid ?? await computeJwkThumbprint({ jwk: publicKey }); + let methodId = verificationMethod.id ?? publicKey.kid ?? await computeJwkThumbprint({ jwk: publicKey }); methodId = `${didUri}#${extractDidFragment(methodId)}`; // Remove fragment prefix, if any. // Initialize the `verificationMethod` array if it does not already exist. @@ -553,12 +553,12 @@ export class DidDht extends DidMethod { document.verificationMethod.push({ id : methodId, type : 'JsonWebKey', - controller : vm.controller ?? didUri, + controller : verificationMethod.controller ?? didUri, publicKeyJwk : publicKey, }); // Add the verification method to the specified purpose properties of the DID document. - for (const purpose of vm.purposes ?? []) { + for (const purpose of verificationMethod.purposes ?? []) { // Initialize the purpose property if it does not already exist. if (!document[purpose]) document[purpose] = []; // Add the verification method to the purpose property. @@ -825,8 +825,9 @@ export class DidDhtDocument { }): Promise { // Convert the DID document and DID metadata (such as DID types) to a DNS packet. const dnsPacket = await DidDhtDocument.toDnsPacket({ - didDocument : did.document, - didMetadata : did.metadata + didDocument : did.document, + didMetadata : did.metadata, + authoritativeGatewayUris : [gatewayUri] }); // Create a signed BEP44 put message from the DNS packet. @@ -1118,22 +1119,25 @@ export class DidDhtDocument { * @param params - The parameters to use when converting a DID document to a DNS packet. * @param params.didDocument - The DID document to convert to a DNS packet. * @param params.didMetadata - The DID metadata to include in the DNS packet. + * @param params.authoritativeGatewayUris - The URIs of the Authoritative Gateways to generate NS records from. * @returns A promise that resolves to a DNS packet. */ - public static async toDnsPacket({ didDocument, didMetadata }: { + public static async toDnsPacket({ didDocument, didMetadata, authoritativeGatewayUris }: { didDocument: DidDocument; didMetadata: DidMetadata; + authoritativeGatewayUris?: string[]; }): Promise { - const dnsAnswerRecords: TxtAnswer[] = []; + const txtRecords: TxtAnswer[] = []; + const nsRecords: StringAnswer[] = []; const idLookup = new Map(); const serviceIds: string[] = []; const verificationMethodIds: string[] = []; // Add DNS TXT records if the DID document contains an `alsoKnownAs` property. if (didDocument.alsoKnownAs) { - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', - name : '_aka.did.', + name : '_aka._did.', ttl : DNS_RECORD_TTL, data : didDocument.alsoKnownAs.join(VALUE_SEPARATOR) }); @@ -1144,25 +1148,25 @@ export class DidDhtDocument { const controller = Array.isArray(didDocument.controller) ? didDocument.controller.join(VALUE_SEPARATOR) : didDocument.controller; - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', - name : '_cnt.did.', + name : '_cnt._did.', ttl : DNS_RECORD_TTL, data : controller }); } // Add DNS TXT records for each verification method. - for (const [index, vm] of didDocument.verificationMethod?.entries() ?? []) { + for (const [index, verificationMethod] of didDocument.verificationMethod?.entries() ?? []) { const dnsRecordId = `k${index}`; verificationMethodIds.push(dnsRecordId); - let methodId = vm.id.split('#').pop()!; // Remove fragment prefix, if any. + let methodId = verificationMethod.id.split('#').pop()!; // Remove fragment prefix, if any. idLookup.set(methodId, dnsRecordId); - const publicKey = vm.publicKeyJwk; + const publicKey = verificationMethod.publicKeyJwk; if (!(publicKey?.crv && publicKey.crv in AlgorithmToKeyTypeMap)) { - throw new DidError(DidErrorCode.InvalidPublicKeyType, `Verification method '${vm.id}' contains an unsupported key type: ${publicKey?.crv ?? 'undefined'}`); + throw new DidError(DidErrorCode.InvalidPublicKeyType, `Verification method '${verificationMethod.id}' contains an unsupported key type: ${publicKey?.crv ?? 'undefined'}`); } // Use the public key's `crv` property to get the DID DHT key type. @@ -1175,13 +1179,13 @@ export class DidDhtDocument { const publicKeyBase64Url = Convert.uint8Array(publicKeyBytes).toBase64Url(); // Define the data for the DNS TXT record. - const txtData = [`id=${methodId}`, `t=${keyType}`, `k=${publicKeyBase64Url}`]; + const txtData = [`t=${keyType}`, `k=${publicKeyBase64Url}`]; // Add the controller property, if set to a value other than the Identity Key (DID Subject). - if (vm.controller !== didDocument.id) txtData.push(`c=${vm.controller}`); + if (verificationMethod.controller !== didDocument.id) txtData.push(`c=${verificationMethod.controller}`); // Add a TXT record for the verification method. - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', name : `_${dnsRecordId}._did.`, ttl : DNS_RECORD_TTL, @@ -1203,7 +1207,7 @@ export class DidDhtDocument { ); // Add a TXT record for the verification method. - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', name : `_${dnsRecordId}._did.`, ttl : DNS_RECORD_TTL, @@ -1244,7 +1248,7 @@ export class DidDhtDocument { const types = didMetadata.types as (DidDhtRegisteredDidType | keyof typeof DidDhtRegisteredDidType)[]; const typeIntegers = types.map(type => typeof type === 'string' ? DidDhtRegisteredDidType[type] : type); - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', name : '_typ._did.', ttl : DNS_RECORD_TTL, @@ -1253,19 +1257,29 @@ export class DidDhtDocument { } // Add a DNS TXT record for the root record. - dnsAnswerRecords.push({ + txtRecords.push({ type : 'TXT', name : '_did.' + DidDhtDocument.getUniqueDidSuffix(didDocument.id) + '.', // name of a Root Record MUST end in `.` ttl : DNS_RECORD_TTL, data : rootRecord.join(PROPERTY_SEPARATOR) }); + // Add an NS record for each authoritative gateway URI. + for (const gatewayUri of authoritativeGatewayUris || []) { + nsRecords.push({ + type : 'NS', + name : '_did.' + DidDhtDocument.getUniqueDidSuffix(didDocument.id) + '.', // name of an NS record a authoritative gateway MUST end in `.` + ttl : DNS_RECORD_TTL, + data : gatewayUri + '.' + }); + } + // Create a DNS response packet with the authoritative answer flag set. const dnsPacket: Packet = { id : 0, type : 'response', flags : AUTHORITATIVE_ANSWER, - answers : dnsAnswerRecords + answers : [...txtRecords, ...nsRecords] }; return dnsPacket; @@ -1412,9 +1426,31 @@ export class DidDhtUtils { */ public static keyConverter(curve: string): AsymmetricKeyConverter { const converters: Record = { - 'Ed25519' : Ed25519, - 'P-256' : Secp256r1, - 'secp256k1' : Secp256k1 + 'Ed25519' : Ed25519, + 'P-256' : { + // Wrap the key converter which produces uncompressed public key bytes to produce compressed key bytes as required by the DID DHT spec. + // See https://did-dht.com/#representing-keys for more info. + publicKeyToBytes: async ({ publicKey }: { publicKey: Jwk }): Promise => { + const publicKeyBytes = await Secp256r1.publicKeyToBytes({ publicKey }); + const compressedPublicKey = await Secp256r1.compressPublicKey({ publicKeyBytes }); + return compressedPublicKey; + }, + bytesToPublicKey : Secp256r1.bytesToPublicKey, + privateKeyToBytes : Secp256r1.privateKeyToBytes, + bytesToPrivateKey : Secp256r1.bytesToPrivateKey, + }, + 'secp256k1': { + // Wrap the key converter which produces uncompressed public key bytes to produce compressed key bytes as required by the DID DHT spec. + // See https://did-dht.com/#representing-keys for more info. + publicKeyToBytes: async ({ publicKey }: { publicKey: Jwk }): Promise => { + const publicKeyBytes = await Secp256k1.publicKeyToBytes({ publicKey }); + const compressedPublicKey = await Secp256k1.compressPublicKey({ publicKeyBytes }); + return compressedPublicKey; + }, + bytesToPublicKey : Secp256k1.bytesToPublicKey, + privateKeyToBytes : Secp256k1.privateKeyToBytes, + bytesToPrivateKey : Secp256k1.bytesToPrivateKey, + } }; const converter = converters[curve]; diff --git a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-did-document.json b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-did-document.json deleted file mode 100644 index 3b20263c6..000000000 --- a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-did-document.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "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" - ] -} \ No newline at end of file diff --git a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-dns-records.json b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-dns-records.json deleted file mode 100644 index a749bfd0d..000000000 --- a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1-dns-records.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "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" - } -] \ No newline at end of file diff --git a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1.json b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1.json new file mode 100644 index 000000000..3627b06c6 --- /dev/null +++ b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-1.json @@ -0,0 +1,45 @@ +{ + "didDocument": { + "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" + ] + }, + "dnsRecords": [ + { + "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": "t=0;k=YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE" + } + ] +} \ No newline at end of file diff --git a/packages/dids/tests/fixtures/test-vectors/did-dht/vector-2.json b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-2.json new file mode 100644 index 000000000..72a212672 --- /dev/null +++ b/packages/dids/tests/fixtures/test-vectors/did-dht/vector-2.json @@ -0,0 +1,105 @@ +{ + "didDocument": { + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo", + "controller": "did:example:abcd", + "alsoKnownAs": ["did:example:efgh", "did:example:ijkl"], + "verificationMethod": [ + { + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0", + "type": "JsonWebKey", + "controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo", + "publicKeyJwk": { + "kid": "0", + "alg": "Ed25519", + "crv": "Ed25519", + "kty": "OKP", + "x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE" + } + }, + { + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "type": "JsonWebKey", + "controller": "did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y", + "publicKeyJwk": { + "kid": "0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw", + "alg": "ES256K", + "crv": "secp256k1", + "kty": "EC", + "x": "1_o0IKHGNamet8-3VYNUTiKlhVK-LilcKrhJSPHSNP0", + "y": "qzU8qqh0wKB6JC_9HCu8pHE-ZPkDpw4AdJ-MsV2InVY" + } + } + ], + "authentication": [ + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0" + ], + "assertionMethod": [ + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0", + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw" + ], + "capabilityInvocation": [ + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0", + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0GkvkdCGu3DL7Mkv0W1DhTMCBT9-z0CkFqZoJQtw7vw" + ], + "capabilityDelegation": [ + "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#0" + ], + "service": [ + { + "id": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo#service-1", + "type": "TestService", + "serviceEndpoint": ["https://test-service.com/1", "https://test-service.com/2"] + } + ] + }, + "dnsRecords": [ + { + "name": "_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo.", + "type": "NS", + "ttl": 7200, + "rdata": "gateway1.example-did-dht-gateway.com." + }, + { + "name": "_did.cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo.", + "type": "TXT", + "ttl": 7200, + "rdata": "v=0;vm=k0,k1;auth=k0;asm=k0,k1;inv=k0,k1;del=k0;svc=s0" + }, + { + "name": "_cnt._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "did:example:abcd" + }, + { + "name": "_aka._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "did:example:efgh,did:example:ijkl" + }, + { + "name": "_k0._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "t=0;k=YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE" + }, + { + "name": "_k1._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "t=1;k=Atf6NCChxjWpnrfPt1WDVE4ipYVSvi4pXCq4SUjx0jT9;c=did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y" + }, + { + "name": "_s0._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "id=service-1;t=TestService;se=https://test-service.com/1,https://test-service.com/2" + }, + { + "name": "_typ._did.", + "type": "TXT", + "ttl": 7200, + "rdata": "id=1,2,3" + } + ] +} \ No newline at end of file diff --git a/packages/dids/tests/methods/did-dht.spec.ts b/packages/dids/tests/methods/did-dht.spec.ts index 929362888..5bc39dcd5 100644 --- a/packages/dids/tests/methods/did-dht.spec.ts +++ b/packages/dids/tests/methods/did-dht.spec.ts @@ -2,10 +2,11 @@ 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 officialTestVector1 from '../fixtures/test-vectors/did-dht/vector-1.json' assert { type: 'json' }; +import officialTestVector2 from '../fixtures/test-vectors/did-dht/vector-2.json' assert { type: 'json' }; import { expect } from 'chai'; +import { Answer } from '@dnsquery/dns-packet'; import { Convert } from '@web5/common'; import { DidDocument } from '../../src/index.js'; import { DidErrorCode } from '../../src/did-error.js'; @@ -1172,23 +1173,48 @@ describe('DidDhtDocument', () => { describe('Official DID:DHT Vector tests', () => { it('vector 1', async () => { const dnsPacket = await DidDhtDocument.toDnsPacket({ - didDocument : officialTestVector1DidDocument as DidDocument, + didDocument : officialTestVector1.didDocument as DidDocument, didMetadata : { published: false } }); - expect(dnsPacket.answers).to.have.length(officialTestVector1DnsRecords.length); + expect(dnsPacket.answers).to.have.length(officialTestVector1.dnsRecords.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 - }; + const normalizedConstructedRecords = normalizeDnsRecords(dnsPacket.answers!); + expect(normalizedConstructedRecords).to.deep.include.members(officialTestVector1.dnsRecords); + }); + + it('vector 2', async () => { + const dnsPacket = await DidDhtDocument.toDnsPacket({ + didDocument : officialTestVector2.didDocument as DidDocument, + didMetadata : { + published : false, + types : [DidDhtRegisteredDidType.Organization, DidDhtRegisteredDidType.Government, DidDhtRegisteredDidType.Corporation] + }, + authoritativeGatewayUris: ['gateway1.example-did-dht-gateway.com'] }); - expect(normalizedConstructedRecords).to.deep.include.members(officialTestVector1DnsRecords); + expect(dnsPacket.answers).to.have.length(officialTestVector2.dnsRecords.length); + + const normalizedConstructedRecords = normalizeDnsRecords(dnsPacket.answers!); + expect(normalizedConstructedRecords).to.deep.include.members(officialTestVector2.dnsRecords); }); }); + +/** + * Normalizes the DNS records in the format of the DNS library we use to the format used in the test vectors. + * + * 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. + */ +function normalizeDnsRecords(dnsRecords: Answer[]): Record { + + const normalizedRecords = dnsRecords.map(record => { + const { data: rdata, ...otherProperties } = record; + return { + ...otherProperties, + rdata + }; + }); + + return normalizedRecords; +} \ No newline at end of file