Comparing version 5.9.0 to 5.10.0
@@ -1262,4 +1262,4 @@ import * as u8a from 'uint8arrays'; | ||
async function resolveX25519Encrypters(dids, resolver) { | ||
const encryptersForDID = async did => { | ||
var _didDocument$keyAgree; | ||
const encryptersForDID = async (did, resolved = []) => { | ||
var _didDocument$keyAgree, _didDocument$keyAgree2, _agreementKeys$filter; | ||
@@ -1270,2 +1270,3 @@ const { | ||
} = await resolver.resolve(did); | ||
resolved.push(did); | ||
@@ -1276,4 +1277,19 @@ if (didResolutionMetadata != null && didResolutionMetadata.error || didDocument == null) { | ||
if (!didDocument.keyAgreement) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
const agreementKeys = (_didDocument$keyAgree = didDocument.keyAgreement) == null ? void 0 : _didDocument$keyAgree.map(key => { | ||
let controllerEncrypters = []; | ||
if (!didDocument.controller && !didDocument.keyAgreement) { | ||
throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
} | ||
if (didDocument.controller) { | ||
let controllers = Array.isArray(didDocument.controller) ? didDocument.controller : [didDocument.controller]; | ||
controllers = controllers.filter(c => !resolved.includes(c)); | ||
const encrypterPromises = controllers.map(did => encryptersForDID(did, resolved).catch(() => { | ||
return []; | ||
})); | ||
const encrypterArrays = await Promise.all(encrypterPromises); | ||
controllerEncrypters = [].concat(...encrypterArrays); | ||
} | ||
const agreementKeys = (_didDocument$keyAgree = didDocument.keyAgreement) == null ? void 0 : (_didDocument$keyAgree2 = _didDocument$keyAgree.map(key => { | ||
if (typeof key === 'string') { | ||
@@ -1284,9 +1300,9 @@ return [...(didDocument.publicKey || []), ...(didDocument.verificationMethod || [])].find(pk => pk.id === key); | ||
return key; | ||
}).filter(key => typeof key !== 'undefined'); | ||
const pks = agreementKeys.filter(key => { | ||
})) == null ? void 0 : _didDocument$keyAgree2.filter(key => typeof key !== 'undefined'); | ||
const pks = (_agreementKeys$filter = agreementKeys == null ? void 0 : agreementKeys.filter(key => { | ||
// TODO: should be able to use non base58 keys too | ||
return key.type === 'X25519KeyAgreementKey2019' && Boolean(key.publicKeyBase58); | ||
}); | ||
if (!pks.length) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
return pks.map(pk => x25519Encrypter(base58ToBytes(pk.publicKeyBase58), pk.id)); | ||
})) != null ? _agreementKeys$filter : []; | ||
if (!pks.length && !controllerEncrypters.length) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
return pks.map(pk => x25519Encrypter(base58ToBytes(pk.publicKeyBase58), pk.id)).concat(...controllerEncrypters); | ||
}; | ||
@@ -1293,0 +1309,0 @@ |
@@ -1400,3 +1400,3 @@ import * as u8a from 'uint8arrays'; | ||
try { | ||
const encryptersForDID = function (did) { | ||
const encryptersForDID = function (did, resolved = []) { | ||
try { | ||
@@ -1407,4 +1407,22 @@ return Promise.resolve(resolver.resolve(did)).then(function ({ | ||
}) { | ||
var _didDocument$keyAgree; | ||
function _temp4() { | ||
var _didDocument$keyAgree, _didDocument$keyAgree2, _agreementKeys$filter; | ||
const agreementKeys = (_didDocument$keyAgree = didDocument.keyAgreement) == null ? void 0 : (_didDocument$keyAgree2 = _didDocument$keyAgree.map(key => { | ||
if (typeof key === 'string') { | ||
return [...(didDocument.publicKey || []), ...(didDocument.verificationMethod || [])].find(pk => pk.id === key); | ||
} | ||
return key; | ||
})) == null ? void 0 : _didDocument$keyAgree2.filter(key => typeof key !== 'undefined'); | ||
const pks = (_agreementKeys$filter = agreementKeys == null ? void 0 : agreementKeys.filter(key => { | ||
// TODO: should be able to use non base58 keys too | ||
return key.type === 'X25519KeyAgreementKey2019' && Boolean(key.publicKeyBase58); | ||
})) != null ? _agreementKeys$filter : []; | ||
if (!pks.length && !controllerEncrypters.length) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
return pks.map(pk => x25519Encrypter(base58ToBytes(pk.publicKeyBase58), pk.id)).concat(...controllerEncrypters); | ||
} | ||
resolved.push(did); | ||
if (didResolutionMetadata != null && didResolutionMetadata.error || didDocument == null) { | ||
@@ -1414,16 +1432,22 @@ throw new Error(`resolver_error: Could not resolve ${did}: ${didResolutionMetadata.error}, ${didResolutionMetadata.message}`); | ||
if (!didDocument.keyAgreement) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
const agreementKeys = (_didDocument$keyAgree = didDocument.keyAgreement) == null ? void 0 : _didDocument$keyAgree.map(key => { | ||
if (typeof key === 'string') { | ||
return [...(didDocument.publicKey || []), ...(didDocument.verificationMethod || [])].find(pk => pk.id === key); | ||
let controllerEncrypters = []; | ||
if (!didDocument.controller && !didDocument.keyAgreement) { | ||
throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
} | ||
const _temp3 = function () { | ||
if (didDocument.controller) { | ||
let controllers = Array.isArray(didDocument.controller) ? didDocument.controller : [didDocument.controller]; | ||
controllers = controllers.filter(c => !resolved.includes(c)); | ||
const encrypterPromises = controllers.map(did => encryptersForDID(did, resolved).catch(() => { | ||
return []; | ||
})); | ||
return Promise.resolve(Promise.all(encrypterPromises)).then(function (encrypterArrays) { | ||
controllerEncrypters = [].concat(...encrypterArrays); | ||
}); | ||
} | ||
}(); | ||
return key; | ||
}).filter(key => typeof key !== 'undefined'); | ||
const pks = agreementKeys.filter(key => { | ||
// TODO: should be able to use non base58 keys too | ||
return key.type === 'X25519KeyAgreementKey2019' && Boolean(key.publicKeyBase58); | ||
}); | ||
if (!pks.length) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`); | ||
return pks.map(pk => x25519Encrypter(base58ToBytes(pk.publicKeyBase58), pk.id)); | ||
return _temp3 && _temp3.then ? _temp3.then(_temp4) : _temp4(_temp3); | ||
}); | ||
@@ -1723,3 +1747,3 @@ } catch (e) { | ||
function _temp4() { | ||
function _temp6() { | ||
// Key Encryption Key | ||
@@ -1740,3 +1764,3 @@ const kek = concatKDF(sharedSecret, keyLen, alg); // Content Encryption Key | ||
const _temp3 = function () { | ||
const _temp5 = function () { | ||
if (receiverSecret instanceof Uint8Array) { | ||
@@ -1751,3 +1775,3 @@ sharedSecret = sharedKey(receiverSecret, publicKey); | ||
return Promise.resolve(_temp3 && _temp3.then ? _temp3.then(_temp4) : _temp4(_temp3)); | ||
return Promise.resolve(_temp5 && _temp5.then ? _temp5.then(_temp6) : _temp6(_temp5)); | ||
} catch (e) { | ||
@@ -1778,3 +1802,3 @@ return Promise.reject(e); | ||
function _temp6() { | ||
function _temp8() { | ||
const sharedSecret = new Uint8Array(zE.length + zS.length); | ||
@@ -1805,3 +1829,3 @@ sharedSecret.set(zE); | ||
const _temp5 = function () { | ||
const _temp7 = function () { | ||
if (recipientSecret instanceof Uint8Array) { | ||
@@ -1820,3 +1844,3 @@ zE = sharedKey(recipientSecret, publicKey); | ||
return Promise.resolve(_temp5 && _temp5.then ? _temp5.then(_temp6) : _temp6(_temp5)); | ||
return Promise.resolve(_temp7 && _temp7.then ? _temp7.then(_temp8) : _temp8(_temp7)); | ||
} catch (e) { | ||
@@ -1823,0 +1847,0 @@ return Promise.reject(e); |
{ | ||
"name": "did-jwt", | ||
"version": "5.9.0", | ||
"version": "5.10.0", | ||
"description": "Library for Signing and Verifying JWTs that use DIDs as issuers and JWEs that use DIDs as recipients", | ||
@@ -5,0 +5,0 @@ "source": "src/index.ts", |
@@ -14,2 +14,7 @@ import { x25519Decrypter, resolveX25519Encrypters } from '../xc20pEncryption' | ||
const did4 = 'did:test:4' | ||
const did5 = 'did:test:5' | ||
const did6 = 'did:test:6' | ||
const did7 = 'did:test:7' | ||
const did8 = 'did:test:8' | ||
const did9 = 'did:test:9' | ||
@@ -20,3 +25,11 @@ let resolver | ||
let didDocumentResult1, didDocumentResult2, didDocumentResult3, didDocumentResult4 | ||
let didDocumentResult1, | ||
didDocumentResult2, | ||
didDocumentResult3, | ||
didDocumentResult4, | ||
didDocumentResult5, | ||
didDocumentResult6, | ||
didDocumentResult7, | ||
didDocumentResult8, | ||
didDocumentResult9 | ||
@@ -68,2 +81,72 @@ beforeEach(() => { | ||
didDocumentResult5 = { | ||
didDocument: { | ||
controller: did1, | ||
verificationMethod: [ | ||
{ | ||
id: did5 + '#owner', | ||
type: 'BlockchainVerificationMethod2021', | ||
controller: did5, | ||
blockchainAccountId: '0xabc123', | ||
}, | ||
], | ||
}, | ||
} | ||
didDocumentResult6 = { | ||
didDocument: { | ||
controller: did5, | ||
verificationMethod: [ | ||
{ | ||
id: did6 + '#owner', | ||
type: 'BlockchainVerificationMethod2021', | ||
controller: did6, | ||
blockchainAccountId: '0xabc123', | ||
}, | ||
], | ||
}, | ||
} | ||
didDocumentResult7 = { | ||
didDocument: { | ||
controller: [did4], | ||
verificationMethod: [ | ||
{ | ||
id: did7 + '#owner', | ||
type: 'BlockchainVerificationMethod2021', | ||
controller: did7, | ||
blockchainAccountId: '0xabc123', | ||
}, | ||
], | ||
}, | ||
} | ||
didDocumentResult8 = { | ||
didDocument: { | ||
controller: [did2, did9], | ||
verificationMethod: [ | ||
{ | ||
id: did8 + '#owner', | ||
type: 'BlockchainVerificationMethod2021', | ||
controller: did8, | ||
blockchainAccountId: '0xabc123', | ||
}, | ||
], | ||
}, | ||
} | ||
didDocumentResult9 = { | ||
didDocument: { | ||
controller: [did8], | ||
verificationMethod: [ | ||
{ | ||
id: did9 + '#owner', | ||
type: 'BlockchainVerificationMethod2021', | ||
controller: did9, | ||
blockchainAccountId: '0xabc123', | ||
}, | ||
], | ||
}, | ||
} | ||
resolver = { | ||
@@ -80,2 +163,12 @@ resolve: jest.fn((did) => { | ||
return didDocumentResult4 | ||
case did5: | ||
return didDocumentResult5 | ||
case did6: | ||
return didDocumentResult6 | ||
case did7: | ||
return didDocumentResult7 | ||
case did8: | ||
return didDocumentResult8 | ||
case did9: | ||
return didDocumentResult9 | ||
} | ||
@@ -91,3 +184,2 @@ }), | ||
const jwe = await createJWE(cleartext, encrypters) | ||
expect(jwe.recipients[0].header.kid).toEqual(did1 + '#abc') | ||
@@ -102,3 +194,3 @@ expect(jwe.recipients[1].header.kid).toEqual(did2 + '#abc') | ||
it('throws error if key is not found', async () => { | ||
expect.assertions(2) | ||
expect.assertions(3) | ||
await expect(resolveX25519Encrypters([did3], resolver)).rejects.toThrowError( | ||
@@ -110,2 +202,5 @@ 'resolver_error: Could not resolve did:test:3' | ||
) | ||
await expect(resolveX25519Encrypters([did7], resolver)).rejects.toThrowError( | ||
'no_suitable_keys: Could not find x25519 key for did:test:7' | ||
) | ||
}) | ||
@@ -152,3 +247,34 @@ | ||
}) | ||
it('resolves encrypters for DIDs where only controllers have valid key exchange keys', async () => { | ||
expect.assertions(3) | ||
const encrypters = await resolveX25519Encrypters([did5], resolver) | ||
const cleartext = randomBytes(8) | ||
const jwe = await createJWE(cleartext, encrypters) | ||
expect(jwe.recipients[0].header.kid).toEqual(did1 + '#abc') | ||
expect(await decryptJWE(jwe, decrypter1)).toEqual(cleartext) | ||
expect(await decryptJWE(jwe, decrypter1remote)).toEqual(cleartext) | ||
}) | ||
it("resolved encrypters for DIDs where controller's controller has valid key exchange keys", async () => { | ||
expect.assertions(3) | ||
const encrypters = await resolveX25519Encrypters([did6], resolver) | ||
const cleartext = randomBytes(8) | ||
const jwe = await createJWE(cleartext, encrypters) | ||
expect(jwe.recipients[0].header.kid).toEqual(did1 + '#abc') | ||
expect(await decryptJWE(jwe, decrypter1)).toEqual(cleartext) | ||
expect(await decryptJWE(jwe, decrypter1remote)).toEqual(cleartext) | ||
}) | ||
it('does not enter an infinite loop when DIDs controllers refer each other', async () => { | ||
expect.assertions(4) | ||
const encrypters = await resolveX25519Encrypters([did9], resolver) | ||
const cleartext = randomBytes(8) | ||
const jwe = await createJWE(cleartext, encrypters) | ||
expect(jwe.recipients[0].header.kid).toEqual(did2 + '#abc') | ||
expect(jwe.recipients.length).toEqual(1) | ||
expect(await decryptJWE(jwe, decrypter2)).toEqual(cleartext) | ||
expect(await decryptJWE(jwe, decrypter2remote)).toEqual(cleartext) | ||
}) | ||
}) | ||
}) |
@@ -279,4 +279,5 @@ import { XChaCha20Poly1305 } from '@stablelib/xchacha20poly1305' | ||
export async function resolveX25519Encrypters(dids: string[], resolver: Resolvable): Promise<Encrypter[]> { | ||
const encryptersForDID = async (did: string): Promise<Encrypter[]> => { | ||
const encryptersForDID = async (did: string, resolved: string[] = []): Promise<Encrypter[]> => { | ||
const { didResolutionMetadata, didDocument } = await resolver.resolve(did) | ||
resolved.push(did) | ||
if (didResolutionMetadata?.error || didDocument == null) { | ||
@@ -287,3 +288,17 @@ throw new Error( | ||
} | ||
if (!didDocument.keyAgreement) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`) | ||
let controllerEncrypters: Encrypter[] = [] | ||
if (!didDocument.controller && !didDocument.keyAgreement) { | ||
throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`) | ||
} | ||
if (didDocument.controller) { | ||
let controllers = Array.isArray(didDocument.controller) ? didDocument.controller : [didDocument.controller] | ||
controllers = controllers.filter((c) => !resolved.includes(c)) | ||
const encrypterPromises = controllers.map((did) => | ||
encryptersForDID(did, resolved).catch(() => { | ||
return [] | ||
}) | ||
) | ||
const encrypterArrays = await Promise.all(encrypterPromises) | ||
controllerEncrypters = ([] as Encrypter[]).concat(...encrypterArrays) | ||
} | ||
const agreementKeys: VerificationMethod[] = didDocument.keyAgreement | ||
@@ -298,9 +313,13 @@ ?.map((key) => { | ||
}) | ||
.filter((key) => typeof key !== 'undefined') as VerificationMethod[] | ||
const pks = agreementKeys.filter((key) => { | ||
// TODO: should be able to use non base58 keys too | ||
return key.type === 'X25519KeyAgreementKey2019' && Boolean(key.publicKeyBase58) | ||
}) | ||
if (!pks.length) throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`) | ||
return pks.map((pk) => x25519Encrypter(base58ToBytes(<string>pk.publicKeyBase58), pk.id)) | ||
?.filter((key) => typeof key !== 'undefined') as VerificationMethod[] | ||
const pks = | ||
agreementKeys?.filter((key) => { | ||
// TODO: should be able to use non base58 keys too | ||
return key.type === 'X25519KeyAgreementKey2019' && Boolean(key.publicKeyBase58) | ||
}) ?? [] | ||
if (!pks.length && !controllerEncrypters.length) | ||
throw new Error(`no_suitable_keys: Could not find x25519 key for ${did}`) | ||
return pks | ||
.map((pk) => x25519Encrypter(base58ToBytes(<string>pk.publicKeyBase58), pk.id)) | ||
.concat(...controllerEncrypters) | ||
} | ||
@@ -307,0 +326,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1151500
10831