From 0750cd95cc2f2ce948797f248ab6cb6c92d23813 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Fri, 29 Dec 2023 20:17:01 -0500 Subject: [PATCH] Remove expansionMap (deprecated). --- lib/ProofSet.js | 41 +++++++--------------- lib/jsonld-signatures.js | 20 +++-------- lib/purposes/AuthenticationProofPurpose.js | 8 ++--- lib/purposes/ControllerProofPurpose.js | 7 ++-- lib/purposes/ProofPurpose.js | 6 ++-- lib/suites/LinkedDataProof.js | 8 ++--- lib/suites/LinkedDataSignature.js | 38 ++++++++------------ 7 files changed, 42 insertions(+), 86 deletions(-) diff --git a/lib/ProofSet.js b/lib/ProofSet.js index 1fe241c6..f0607dfc 100644 --- a/lib/ProofSet.js +++ b/lib/ProofSet.js @@ -7,7 +7,6 @@ const constants = require('./constants'); const jsonld = require('jsonld'); const {extendContextLoader, strictDocumentLoader} = require('./documentLoader'); const {serializeError} = require('serialize-error'); -const strictExpansionMap = require('./expansionMap'); module.exports = class ProofSet { /** @@ -35,16 +34,11 @@ module.exports = class ProofSet { * * @param [documentLoader] {function} a custom document loader, * `Promise documentLoader(url)`. - * @param [expansionMap] {function} A custom expansion map that is - * passed to the JSON-LD processor; by default a function that will throw - * an error when unmapped properties are detected in the input, use `false` - * to turn this off and allow unmapped properties to be dropped or use a - * custom function. * * @return {Promise} resolves with the signed document, with * the signature in the top-level `proof` property. */ - async add(document, {suite, purpose, documentLoader, expansionMap} = {}) { + async add(document, {suite, purpose, documentLoader} = {}) { if(!suite) { throw new TypeError('"options.suite" is required.'); } @@ -57,9 +51,6 @@ module.exports = class ProofSet { } else { documentLoader = strictDocumentLoader; } - if(expansionMap !== false) { - expansionMap = strictExpansionMap; - } // preprocess document to prepare to remove existing proofs // let input; @@ -71,7 +62,7 @@ module.exports = class ProofSet { // create the new proof (suites MUST output a proof using the security-v2 // `@context`) const proof = await suite.createProof({ - document: input, purpose, documentLoader, expansionMap + document: input, purpose, documentLoader }); jsonld.addValue(document, 'proof', proof); @@ -101,11 +92,6 @@ module.exports = class ProofSet { * * @param {function} [documentLoader] a custom document loader, * `Promise documentLoader(url)`. - * @param {function} [expansionMap] - A custom expansion map that is - * passed to the JSON-LD processor; by default a function that will throw - * an error when unmapped properties are detected in the input, use `false` - * to turn this off and allow unmapped properties to be dropped or use a - * custom function. * * @return {Promise<{verified: boolean, results: Array, error: *}>} resolves * with an object with a `verified`boolean property that is `true` if at @@ -113,7 +99,7 @@ module.exports = class ProofSet { * otherwise; a `results` property with an array of detailed results; * if `false` an `error` property will be present. */ - async verify(document, {suite, purpose, documentLoader, expansionMap} = {}) { + async verify(document, {suite, purpose, documentLoader} = {}) { if(!suite) { throw new TypeError('"options.suite" is required.'); } @@ -130,9 +116,6 @@ module.exports = class ProofSet { } else { documentLoader = strictDocumentLoader; } - if(expansionMap !== false) { - expansionMap = strictExpansionMap; - } try { // shallow copy to allow for removal of proof set prior to canonize @@ -140,13 +123,13 @@ module.exports = class ProofSet { // get proofs from document const {proofSet, document: doc} = await _getProofs({ - document, documentLoader, expansionMap + document, documentLoader }); document = doc; // verify proofs const results = await _verify({ - document, suites, proofSet, purpose, documentLoader, expansionMap + document, suites, proofSet, purpose, documentLoader }); if(results.length === 0) { const error = new Error( @@ -197,7 +180,7 @@ async function _getProofs({document}) { } async function _verify({ - document, suites, proofSet, purpose, documentLoader, expansionMap + document, suites, proofSet, purpose, documentLoader }) { // map each purpose to at least one proof to verify const purposes = Array.isArray(purpose) ? purpose : [purpose]; @@ -206,7 +189,7 @@ async function _verify({ const suiteMatchQueue = new Map(); await Promise.all(purposes.map(purpose => _matchProofSet({ purposeToProofs, proofToSuite, purpose, proofSet, suites, - suiteMatchQueue, document, documentLoader, expansionMap + suiteMatchQueue, document, documentLoader }))); // every purpose must have at least one matching proof or verify will fail @@ -230,7 +213,7 @@ async function _verify({ } }; const {verified, verificationMethod, error} = await suite.verifyProof({ - proof, document, purpose, documentLoader, expansionMap + proof, document, purpose, documentLoader }); if(!vm) { vm = verificationMethod; @@ -264,7 +247,7 @@ async function _verify({ let purposeResult; try { purposeResult = await purpose.validate(proof, { - document, suite, verificationMethod, documentLoader, expansionMap + document, suite, verificationMethod, documentLoader }); } catch(error) { purposeResult = {valid: false, error}; @@ -312,11 +295,11 @@ function _makeSerializable(error) { async function _matchProofSet({ purposeToProofs, proofToSuite, purpose, proofSet, suites, - suiteMatchQueue, document, documentLoader, expansionMap + suiteMatchQueue, document, documentLoader }) { for(const proof of proofSet) { // first check if the proof matches the purpose; if it doesn't continue - if(!await purpose.match(proof, {document, documentLoader, expansionMap})) { + if(!await purpose.match(proof, {document, documentLoader})) { continue; } @@ -335,7 +318,7 @@ async function _matchProofSet({ } let promise = matchingProofs.get(proof); if(!promise) { - promise = s.matchProof({proof, document, documentLoader, expansionMap}); + promise = s.matchProof({proof, document, documentLoader}); matchingProofs.set(proof, promise); } if(await promise) { diff --git a/lib/jsonld-signatures.js b/lib/jsonld-signatures.js index 428e6200..366ed672 100644 --- a/lib/jsonld-signatures.js +++ b/lib/jsonld-signatures.js @@ -36,12 +36,6 @@ const VerificationError = require('./VerificationError'); * and other relevant URLs needed for the proof. * * Advanced optional parameters and overrides: - * - * @param {function} [options.expansionMap] - A custom expansion map that is - * passed to the JSON-LD processor; by default a function that will throw - * an error when unmapped properties are detected in the input, use `false` - * to turn this off and allow unmapped properties to be dropped or use a - * custom function. * @param {boolean} [options.addSuiteContext=true] - Toggles the default * behavior of each signature suite enforcing the presence of its own * `@context` (if it is not present, it's added to the context list). @@ -49,7 +43,7 @@ const VerificationError = require('./VerificationError'); * @returns {Promise} Resolves with signed document. */ api.sign = async function sign(document, { - suite, purpose, documentLoader, expansionMap, addSuiteContext = true + suite, purpose, documentLoader, addSuiteContext = true } = {}) { if(typeof document !== 'object') { throw new TypeError('The "document" parameter must be an object.'); @@ -61,7 +55,7 @@ api.sign = async function sign(document, { try { return await new ProofSet().add( - document, {suite, purpose, documentLoader, expansionMap}); + document, {suite, purpose, documentLoader}); } catch(e) { if(!documentLoader && e.name === 'jsonld.InvalidUrl') { const {details: {url}} = e; @@ -92,11 +86,6 @@ api.sign = async function sign(document, { * * @param {function} [documentLoader] - A custom document loader, * `Promise documentLoader(url)`. - * @param {function} [expansionMap] - A custom expansion map that is - * passed to the JSON-LD processor; by default a function that will throw - * an error when unmapped properties are detected in the input, use `false` - * to turn this off and allow unmapped properties to be dropped or use a - * custom function. * * @return {Promise<{verified: boolean, results: Array, * error: VerificationError}>} @@ -107,12 +96,12 @@ api.sign = async function sign(document, { * containing all of the errors that occurred during the verification process. */ api.verify = async function verify(document, { - suite, purpose, documentLoader, expansionMap} = {}) { + suite, purpose, documentLoader} = {}) { if(typeof document !== 'object') { throw new TypeError('The "document" parameter must be an object.'); } const result = await new ProofSet().verify( - document, {suite, purpose, documentLoader, expansionMap}); + document, {suite, purpose, documentLoader}); const {error} = result; if(error) { if(!documentLoader && error.name === 'jsonld.InvalidUrl') { @@ -136,4 +125,3 @@ api.purposes = require('./purposes').purposes; // expose document loader helpers Object.assign(api, require('./documentLoader')); - diff --git a/lib/purposes/AuthenticationProofPurpose.js b/lib/purposes/AuthenticationProofPurpose.js index 3947a998..c87c749a 100644 --- a/lib/purposes/AuthenticationProofPurpose.js +++ b/lib/purposes/AuthenticationProofPurpose.js @@ -21,7 +21,7 @@ module.exports = class AuthenticationProofPurpose extends this.domain = domain; } - async validate(proof, {verificationMethod, documentLoader, expansionMap}) { + async validate(proof, {verificationMethod, documentLoader}) { try { // check challenge if(proof.challenge !== this.challenge) { @@ -36,15 +36,15 @@ module.exports = class AuthenticationProofPurpose extends } return super.validate( - proof, {verificationMethod, documentLoader, expansionMap}); + proof, {verificationMethod, documentLoader}); } catch(error) { return {valid: false, error}; } } - async update(proof, {document, suite, documentLoader, expansionMap}) { + async update(proof, {document, suite, documentLoader}) { proof = await super.update( - proof, {document, suite, documentLoader, expansionMap}); + proof, {document, suite, documentLoader}); proof.challenge = this.challenge; if(this.domain !== undefined) { proof.domain = this.domain; diff --git a/lib/purposes/ControllerProofPurpose.js b/lib/purposes/ControllerProofPurpose.js index e72f68a9..3b7bc196 100644 --- a/lib/purposes/ControllerProofPurpose.js +++ b/lib/purposes/ControllerProofPurpose.js @@ -54,17 +54,16 @@ module.exports = class ControllerProofPurpose extends ProofPurpose { * @param proof * @param verificationMethod * @param documentLoader - * @param expansionMap * * @throws {Error} If verification method not authorized by controller * @throws {Error} If proof's created timestamp is out of range * * @returns {Promise<{valid: boolean, error: Error}>} */ - async validate(proof, {verificationMethod, documentLoader, expansionMap}) { + async validate(proof, {verificationMethod, documentLoader}) { try { const result = await super.validate( - proof, {verificationMethod, documentLoader, expansionMap}); + proof, {verificationMethod, documentLoader}); if(!result.valid) { throw result.error; } @@ -97,8 +96,6 @@ module.exports = class ControllerProofPurpose extends ProofPurpose { (Array.isArray(document['@context']) && document['@context'][0] === DID_CONTEXT_V1)); if(mustFrame) { - // Note: `expansionMap` is intentionally not passed; we can safely - // drop properties here and must allow for it document = await jsonld.frame(document, { '@context': constants.SECURITY_CONTEXT_URL, id: controllerId, diff --git a/lib/purposes/ProofPurpose.js b/lib/purposes/ProofPurpose.js index 7b8b1de8..d8c331fb 100644 --- a/lib/purposes/ProofPurpose.js +++ b/lib/purposes/ProofPurpose.js @@ -43,7 +43,7 @@ module.exports = class ProofPurpose { */ async validate( proof, {/*document, suite, verificationMethod, - documentLoader, expansionMap*/}) { + documentLoader*/}) { try { // check expiration if(this.maxTimestampDelta !== Infinity) { @@ -73,7 +73,7 @@ module.exports = class ProofPurpose { * @return {Promise} resolves to the proof instance (in the * `constants.SECURITY_CONTEXT_URL`. */ - async update(proof, {/*document, suite, documentLoader, expansionMap */}) { + async update(proof, {/*document, suite, documentLoader*/}) { proof.proofPurpose = this.term; return proof; } @@ -87,7 +87,7 @@ module.exports = class ProofPurpose { * * @return {Promise} `true` if there's a match, `false` if not. */ - async match(proof, {/* document, documentLoader, expansionMap */}) { + async match(proof, {/* document, documentLoader */}) { return proof.proofPurpose === this.term; } }; diff --git a/lib/suites/LinkedDataProof.js b/lib/suites/LinkedDataProof.js index 8fbe797f..916fe3ae 100644 --- a/lib/suites/LinkedDataProof.js +++ b/lib/suites/LinkedDataProof.js @@ -15,12 +15,11 @@ module.exports = class LinkedDataProof { * @param document {object} to be signed. * @param purpose {ProofPurpose} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise} Resolves with the created proof object. */ async createProof({ - /* document, purpose, documentLoader, expansionMap */ + /* document, purpose, documentLoader */ }) { throw new Error('"createProof" must be implemented in a derived class.'); } @@ -30,12 +29,11 @@ module.exports = class LinkedDataProof { * @param document {object} the document the proof applies to. * @param purpose {ProofPurpose} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise<{object}>} Resolves with the verification result. */ async verifyProof({ - /* proof, document, purpose, documentLoader, expansionMap */ + /* proof, document, purpose, documentLoader */ }) { throw new Error('"verifyProof" must be implemented in a derived class.'); } @@ -49,7 +47,7 @@ module.exports = class LinkedDataProof { * @returns {Promise} Whether a match for the proof was found. */ async matchProof({ - proof /*, document, purpose, documentLoader, expansionMap */ + proof /*, document, purpose, documentLoader */ }) { return proof.type === this.type; } diff --git a/lib/suites/LinkedDataSignature.js b/lib/suites/LinkedDataSignature.js index e01c661f..19860429 100644 --- a/lib/suites/LinkedDataSignature.js +++ b/lib/suites/LinkedDataSignature.js @@ -86,11 +86,10 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param document {object} to be signed. * @param purpose {ProofPurpose} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise} Resolves with the created proof object. */ - async createProof({document, purpose, documentLoader, expansionMap}) { + async createProof({document, purpose, documentLoader}) { // build proof (currently known as `signature options` in spec) let proof; if(this.proof) { @@ -124,23 +123,23 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { // add any extensions to proof (mostly for legacy support) proof = await this.updateProof({ - document, proof, purpose, documentLoader, expansionMap + document, proof, purpose, documentLoader }); // allow purpose to update the proof; the `proof` is in the // SECURITY_CONTEXT_URL `@context` -- therefore the `purpose` must // ensure any added fields are also represented in that same `@context` proof = await purpose.update( - proof, {document, suite: this, documentLoader, expansionMap}); + proof, {document, suite: this, documentLoader}); // create data to sign const verifyData = await this.createVerifyData({ - document, proof, documentLoader, expansionMap + document, proof, documentLoader }); // sign data proof = await this.sign( - {verifyData, document, proof, documentLoader, expansionMap}); + {verifyData, document, proof, documentLoader}); return proof; } @@ -149,7 +148,6 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param document {object} to be signed. * @param purpose {ProofPurpose} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise} Resolves with the created proof object. */ @@ -162,24 +160,23 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param proof {object} the proof to be verified. * @param document {object} the document the proof applies to. * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise<{object}>} Resolves with the verification result. */ - async verifyProof({proof, document, documentLoader, expansionMap}) { + async verifyProof({proof, document, documentLoader}) { try { // create data to verify const verifyData = await this.createVerifyData( - {document, proof, documentLoader, expansionMap}); + {document, proof, documentLoader}); // fetch verification method const verificationMethod = await this.getVerificationMethod( - {proof, document, documentLoader, expansionMap}); + {proof, document, documentLoader}); // verify signature on data const verified = await this.verifySignature({ verifyData, verificationMethod, document, proof, - documentLoader, expansionMap}); + documentLoader}); if(!verified) { throw new Error('Invalid signature.'); } @@ -190,18 +187,17 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { } } - async canonize(input, {documentLoader, expansionMap, skipExpansion}) { + async canonize(input, {documentLoader, skipExpansion}) { return jsonld.canonize(input, { algorithm: 'URDNA2015', format: 'application/n-quads', documentLoader, - expansionMap, skipExpansion, useNative: this.useNativeCanonize }); } - async canonizeProof(proof, {document, documentLoader, expansionMap}) { + async canonizeProof(proof, {document, documentLoader}) { // `jws`,`signatureValue`,`proofValue` must not be included in the proof // options proof = { @@ -213,7 +209,6 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { delete proof.proofValue; return this.canonize(proof, { documentLoader, - expansionMap, skipExpansion: false }); } @@ -222,11 +217,10 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param document {object} to be signed/verified. * @param proof {object} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise<{Uint8Array}>}. */ - async createVerifyData({document, proof, documentLoader, expansionMap}) { + async createVerifyData({document, proof, documentLoader}) { // get cached document hash let cachedDocHash; const {_hashCache} = this; @@ -237,7 +231,7 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { document, // canonize and hash document hash: cachedDocHash = - this.canonize(document, {documentLoader, expansionMap}) + this.canonize(document, {documentLoader}) .then(c14nDocument => sha256digest({string: c14nDocument})) }; } @@ -246,7 +240,7 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { const [proofHash, docHash] = await Promise.all([ // canonize and hash proof this.canonizeProof( - proof, {document, documentLoader, expansionMap}) + proof, {document, documentLoader}) .then(c14nProofOptions => sha256digest({string: c14nProofOptions})), cachedDocHash ]); @@ -271,8 +265,6 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { throw new Error('No "verificationMethod" found in proof.'); } - // Note: `expansionMap` is intentionally not passed; we can safely drop - // properties here and must allow for it const framed = await jsonld.frame(verificationMethod, { '@context': constants.SECURITY_CONTEXT_URL, '@embed': '@always', @@ -295,7 +287,6 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param document {object} to be signed. * @param proof {object} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise<{object}>} the proof containing the signature value. */ @@ -309,7 +300,6 @@ module.exports = class LinkedDataSignature extends LinkedDataProof { * @param document {object} to be signed. * @param proof {object} * @param documentLoader {function} - * @param expansionMap {function} * * @returns {Promise} */