From 3cf5e512c9f8e5637aab119919250ea201834958 Mon Sep 17 00:00:00 2001 From: Chris Barth Date: Mon, 18 Sep 2023 14:11:32 -0500 Subject: [PATCH] Use is-dom-node for DOM Node checking and narrowing --- package-lock.json | 15 +- package.json | 3 +- src/c14n-canonicalization.ts | 8 +- src/enveloped-signature.ts | 7 +- src/exclusive-canonicalization.ts | 8 +- src/signed-xml.ts | 21 +- src/utils.ts | 7 +- test/c14n-non-exclusive-unit-tests.spec.ts | 17 +- test/c14nWithComments-unit-tests.spec.ts | 42 +-- test/canonicalization-unit-tests.spec.ts | 93 +++--- test/document-tests.spec.ts | 29 +- test/hmac-tests.spec.ts | 55 ++-- test/key-info-tests.spec.ts | 11 +- test/saml-response-tests.spec.ts | 118 +++---- test/signature-integration-tests.spec.ts | 69 ++-- test/signature-unit-tests.spec.ts | 363 ++++++++------------- test/wsfed-metadata-tests.spec.ts | 16 +- 17 files changed, 382 insertions(+), 500 deletions(-) diff --git a/package-lock.json b/package-lock.json index f327492f..0af92eb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.10", - "xpath": "0.0.33" + "is-dom-node": "github:xmldom/is-dom-node#v1.0.0", + "xpath": "^0.0.33" }, "devDependencies": { "@cjbarth/github-release-notes": "^4.1.0", @@ -5539,6 +5540,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-dom-node": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/xmldom/is-dom-node.git#5c92a5123142c74c1550f7287b04ed6a39d294b6", + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -16615,6 +16624,10 @@ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true }, + "is-dom-node": { + "version": "git+ssh://git@github.com/xmldom/is-dom-node.git#5c92a5123142c74c1550f7287b04ed6a39d294b6", + "from": "is-dom-node@github:xmldom/is-dom-node#v1.0.0" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", diff --git a/package.json b/package.json index a80900c1..64026bfc 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ }, "dependencies": { "@xmldom/xmldom": "^0.8.10", - "xpath": "0.0.33" + "is-dom-node": "github:xmldom/is-dom-node#v1.0.0", + "xpath": "^0.0.33" }, "devDependencies": { "@cjbarth/github-release-notes": "^4.1.0", diff --git a/src/c14n-canonicalization.ts b/src/c14n-canonicalization.ts index 6589352c..4d3bbb70 100644 --- a/src/c14n-canonicalization.ts +++ b/src/c14n-canonicalization.ts @@ -5,7 +5,7 @@ import type { RenderedNamespace, } from "./types"; import * as utils from "./utils"; -import * as xpath from "xpath"; +import * as isDomNode from "is-dom-node"; export class C14nCanonicalization implements CanonicalizationOrTransformationAlgorithm { includeComments = false; @@ -44,7 +44,7 @@ export class C14nCanonicalization implements CanonicalizationOrTransformationAlg let attr; const attrListToRender: Attr[] = []; - if (xpath.isComment(node)) { + if (isDomNode.isCommentNode(node)) { return this.renderComment(node); } @@ -171,14 +171,14 @@ export class C14nCanonicalization implements CanonicalizationOrTransformationAlg * @param node Node */ processInner(node, prefixesInScope, defaultNs, defaultNsForPrefix, ancestorNamespaces) { - if (xpath.isComment(node)) { + if (isDomNode.isCommentNode(node)) { return this.renderComment(node); } if (node.data) { return utils.encodeSpecialCharactersInText(node.data); } - if (xpath.isElement(node)) { + if (isDomNode.isElementNode(node)) { let i; let pfxCopy; const ns = this.renderNs( diff --git a/src/enveloped-signature.ts b/src/enveloped-signature.ts index d303d002..4adcaf82 100644 --- a/src/enveloped-signature.ts +++ b/src/enveloped-signature.ts @@ -1,4 +1,5 @@ import * as xpath from "xpath"; +import * as isDomNode from "is-dom-node"; import type { CanonicalizationOrTransformationAlgorithm, @@ -14,7 +15,7 @@ export class EnvelopedSignature implements CanonicalizationOrTransformationAlgor "./*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", node, ); - if (xpath.isNodeLike(signature) && signature.parentNode) { + if (isDomNode.isNodeLike(signature) && signature.parentNode) { signature.parentNode.removeChild(signature); } return node; @@ -24,7 +25,7 @@ export class EnvelopedSignature implements CanonicalizationOrTransformationAlgor ".//*[local-name(.)='SignatureValue']/text()", signatureNode, ); - if (xpath.isTextNode(expectedSignatureValue)) { + if (isDomNode.isTextNode(expectedSignatureValue)) { const expectedSignatureValueData = expectedSignatureValue.data; const signatures = xpath.select( @@ -36,7 +37,7 @@ export class EnvelopedSignature implements CanonicalizationOrTransformationAlgor ".//*[local-name(.)='SignatureValue']/text()", nodeSignature, ); - if (xpath.isTextNode(signatureValue)) { + if (isDomNode.isTextNode(signatureValue)) { const signatureValueData = signatureValue.data; if (expectedSignatureValueData === signatureValueData) { if (nodeSignature.parentNode) { diff --git a/src/exclusive-canonicalization.ts b/src/exclusive-canonicalization.ts index 6f61f3dd..18b21d06 100644 --- a/src/exclusive-canonicalization.ts +++ b/src/exclusive-canonicalization.ts @@ -4,7 +4,7 @@ import type { NamespacePrefix, } from "./types"; import * as utils from "./utils"; -import * as xpath from "xpath"; +import * as isDomNode from "is-dom-node"; function isPrefixInScope(prefixesInScope, prefix, namespaceURI) { let ret = false; @@ -55,7 +55,7 @@ export class ExclusiveCanonicalization implements CanonicalizationOrTransformati const res: string[] = []; const attrListToRender: Attr[] = []; - if (xpath.isComment(node)) { + if (isDomNode.isCommentNode(node)) { return this.renderComment(node); } @@ -177,14 +177,14 @@ export class ExclusiveCanonicalization implements CanonicalizationOrTransformati defaultNsForPrefix, inclusiveNamespacesPrefixList: string[], ) { - if (xpath.isComment(node)) { + if (isDomNode.isCommentNode(node)) { return this.renderComment(node); } if (node.data) { return utils.encodeSpecialCharactersInText(node.data); } - if (xpath.isElement(node)) { + if (isDomNode.isElementNode(node)) { let i; let pfxCopy; const ns = this.renderNs( diff --git a/src/signed-xml.ts b/src/signed-xml.ts index 38e91a21..95297b46 100644 --- a/src/signed-xml.ts +++ b/src/signed-xml.ts @@ -23,6 +23,7 @@ import * as envelopedSignatures from "./enveloped-signature"; import * as hashAlgorithms from "./hash-algorithms"; import * as signatureAlgorithms from "./signature-algorithms"; import * as crypto from "crypto"; +import * as isDomNode from "is-dom-node"; export class SignedXml { idMode?: "wssecurity"; @@ -215,7 +216,7 @@ export class SignedXml { static getCertFromKeyInfo(keyInfo?: Node | null): string | null { if (keyInfo != null) { const certs = xpath.select1(".//*[local-name(.)='X509Certificate']", keyInfo); - if (xpath.isNodeLike(certs)) { + if (isDomNode.isNodeLike(certs)) { return utils.derToPem(certs.textContent || "", "CERTIFICATE"); } } @@ -398,7 +399,7 @@ export class SignedXml { } // @ts-expect-error FIXME: xpath types are wrong - if (!xpath.isNodeLike(targetElem)) { + if (!isDomNode.isNodeLike(targetElem)) { continue; } @@ -446,7 +447,7 @@ export class SignedXml { } // @ts-expect-error FIXME: xpath types are wrong - if (!xpath.isNodeLike(elem)) { + if (!isDomNode.isNodeLike(elem)) { const validationError = new Error( `invalid signature: the signature references an element with uri ${ref.uri} but could not find such element in the xml`, ); @@ -500,7 +501,7 @@ export class SignedXml { throw new Error("could not find CanonicalizationMethod/@Algorithm element"); } - if (xpath.isAttribute(nodes[0])) { + if (isDomNode.isAttributeNode(nodes[0])) { this.canonicalizationAlgorithm = nodes[0].value as CanonicalizationAlgorithmType; } @@ -509,7 +510,7 @@ export class SignedXml { signatureNode, ); - if (xpath.isAttribute(signatureAlgorithm)) { + if (isDomNode.isAttributeNode(signatureAlgorithm)) { this.signatureAlgorithm = signatureAlgorithm.value as SignatureAlgorithmType; } @@ -531,13 +532,13 @@ export class SignedXml { signatureNode, ); - if (xpath.isTextNode(signatureValue)) { + if (isDomNode.isTextNode(signatureValue)) { this.signatureValue = signatureValue.data.replace(/\r?\n/g, ""); } const keyInfo = xpath.select1(".//*[local-name(.)='KeyInfo']", signatureNode); - if (xpath.isNodeLike(keyInfo)) { + if (isDomNode.isNodeLike(keyInfo)) { this.keyInfo = keyInfo; } } @@ -621,7 +622,7 @@ export class SignedXml { this.addReference({ transforms, digestAlgorithm: digestAlgo, - uri: xpath.isElement(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined, + uri: isDomNode.isElementNode(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined, digestValue, inclusiveNamespacesPrefixList, isEmptyUri: false, @@ -796,7 +797,7 @@ export class SignedXml { const referenceNode = xpath.select1(location.reference, doc); - if (!xpath.isNodeLike(referenceNode)) { + if (!isDomNode.isNodeLike(referenceNode)) { const err2 = new Error( `the following xpath cannot be used because it was not found: ${location.reference}`, ); @@ -949,7 +950,7 @@ export class SignedXml { let transformedXml: Node | string = canonXml; transforms.forEach((transformName) => { - if (xpath.isNodeLike(transformedXml)) { + if (isDomNode.isNodeLike(transformedXml)) { // If, after processing, `transformedNode` is a string, we can't do anymore transforms on it const transform = this.findCanonicalizationAlgorithm(transformName); transformedXml = transform.process(transformedXml, options); diff --git a/src/utils.ts b/src/utils.ts index 8896447c..fdf933f4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,6 @@ import * as xpath from "xpath"; import type { NamespacePrefix } from "./types"; +import * as isDomNode from "is-dom-node"; export function isArrayHasLength(array: unknown): array is unknown[] { return Array.isArray(array) && array.length > 0; @@ -36,7 +37,7 @@ export function findChildren(node: Node | Document, localName: string, namespace for (let i = 0; i < element.childNodes.length; i++) { const child = element.childNodes[i]; if ( - xpath.isElement(child) && + isDomNode.isElementNode(child) && child.localName === localName && (child.namespaceURI === namespace || namespace == null) ) { @@ -192,7 +193,7 @@ function collectAncestorNamespaces( node: Element, nsArray: NamespacePrefix[] = [], ): NamespacePrefix[] { - if (!xpath.isElement(node.parentNode)) { + if (!isDomNode.isElementNode(node.parentNode)) { return nsArray; } @@ -229,7 +230,7 @@ function findNSPrefix(subset) { } function isElementSubset(docSubset: Node[]): docSubset is Element[] { - return docSubset.every((node) => xpath.isElement(node)); + return docSubset.every((node) => isDomNode.isElementNode(node)); } /** diff --git a/test/c14n-non-exclusive-unit-tests.spec.ts b/test/c14n-non-exclusive-unit-tests.spec.ts index 44540cca..8107a431 100644 --- a/test/c14n-non-exclusive-unit-tests.spec.ts +++ b/test/c14n-non-exclusive-unit-tests.spec.ts @@ -4,20 +4,19 @@ import { C14nCanonicalization } from "../src/c14n-canonicalization"; import * as xmldom from "@xmldom/xmldom"; import * as xpath from "xpath"; import * as utils from "../src/utils"; +import * as isDomNode from "is-dom-node"; const test_C14nCanonicalization = function (xml, xpathArg, expected) { const doc = new xmldom.DOMParser().parseFromString(xml); const node = xpath.select1(xpathArg, doc); const can = new C14nCanonicalization(); - let result = ""; - - if (xpath.isNodeLike(node)) { - result = can - .process(node, { - ancestorNamespaces: utils.findAncestorNs(doc, xpathArg), - }) - .toString(); - } + + isDomNode.assertIsNodeLike(node); + const result = can + .process(node, { + ancestorNamespaces: utils.findAncestorNs(doc, xpathArg), + }) + .toString(); expect(result).to.equal(expected); }; diff --git a/test/c14nWithComments-unit-tests.spec.ts b/test/c14nWithComments-unit-tests.spec.ts index 77ab5850..78c162aa 100644 --- a/test/c14nWithComments-unit-tests.spec.ts +++ b/test/c14nWithComments-unit-tests.spec.ts @@ -4,17 +4,15 @@ import { ExclusiveCanonicalizationWithComments as c14nWithComments } from "../sr import * as xmldom from "@xmldom/xmldom"; import * as xpath from "xpath"; import { SignedXml } from "../src/index"; +import * as isDomNode from "is-dom-node"; const compare = function (xml, xpathArg, expected, inclusiveNamespacesPrefixList?: string[]) { const doc = new xmldom.DOMParser().parseFromString(xml); const elem = xpath.select1(xpathArg, doc); const can = new c14nWithComments(); - if (xpath.isElement(elem)) { - const result = can.process(elem, { inclusiveNamespacesPrefixList }).toString(); - expect(result).to.equal(expected); - } else { - throw new Error("Element not found."); - } + isDomNode.assertIsElementNode(elem); + const result = can.process(elem, { inclusiveNamespacesPrefixList }).toString(); + expect(result).to.equal(expected); }; describe("Exclusive canonicalization with comments", function () { @@ -354,19 +352,16 @@ describe("Exclusive canonicalization with comments", function () { '', ); const node = xpath.select1("//*[local-name(.)='y']", doc); - if (xpath.isNodeLike(node)) { - const sig = new SignedXml(); - const res = sig.getCanonXml( - [ - "http://www.w3.org/2000/09/xmldsig#enveloped-signature", - "http://www.w3.org/2001/10/xml-exc-c14n#", - ], - node, - ); - expect(res).to.equal(''); - } else { - expect(xpath.isNodeLike(node)).to.be.true; - } + isDomNode.assertIsNodeLike(node); + const sig = new SignedXml(); + const res = sig.getCanonXml( + [ + "http://www.w3.org/2000/09/xmldsig#enveloped-signature", + "http://www.w3.org/2001/10/xml-exc-c14n#", + ], + node, + ); + expect(res).to.equal(''); }); it("Enveloped-signature canonicalization respects current node", function () { @@ -379,12 +374,9 @@ describe("Exclusive canonicalization with comments", function () { const node = xpath.select1("//*[local-name(.)='y']", doc); const sig = new SignedXml(); const transforms = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature"]; - if (xpath.isNodeLike(node)) { - const res = sig.getCanonXml(transforms, node); - expect(res).to.equal(""); - } else { - expect(xpath.isNodeLike(node)).to.be.true; - } + isDomNode.assertIsNodeLike(node); + const res = sig.getCanonXml(transforms, node); + expect(res).to.equal(""); }); it("The XML canonicalization method processes a node-set by imposing the following additional document order rules on the namespace and attribute nodes of each element: \ diff --git a/test/canonicalization-unit-tests.spec.ts b/test/canonicalization-unit-tests.spec.ts index c073574c..808450ba 100644 --- a/test/canonicalization-unit-tests.spec.ts +++ b/test/canonicalization-unit-tests.spec.ts @@ -4,6 +4,7 @@ import { ExclusiveCanonicalization } from "../src/exclusive-canonicalization"; import * as xmldom from "@xmldom/xmldom"; import * as xpath from "xpath"; import { SignedXml } from "../src/index"; +import * as isDomNode from "is-dom-node"; const compare = function ( xml: string, @@ -15,18 +16,15 @@ const compare = function ( const doc = new xmldom.DOMParser().parseFromString(xml); const elem = xpath.select1(xpathArg, doc); const can = new ExclusiveCanonicalization(); - if (xpath.isElement(elem)) { - const result = can - .process(elem, { - inclusiveNamespacesPrefixList, - defaultNsForPrefix, - }) - .toString(); - - expect(expected).to.equal(result); - } else { - throw new Error("Invalid element"); - } + isDomNode.assertIsElementNode(elem); + const result = can + .process(elem, { + inclusiveNamespacesPrefixList, + defaultNsForPrefix, + }) + .toString(); + + expect(expected).to.equal(result); }; describe("Canonicalization unit tests", function () { @@ -404,19 +402,17 @@ describe("Canonicalization unit tests", function () { '', ); const node = xpath.select1("//*[local-name(.)='y']", doc); - if (xpath.isNodeLike(node)) { - const sig = new SignedXml(); - const res = sig.getCanonXml( - [ - "http://www.w3.org/2000/09/xmldsig#enveloped-signature", - "http://www.w3.org/2001/10/xml-exc-c14n#", - ], - node, - ); - expect(res).to.equal(''); - } else { - expect(xpath.isNodeLike(node)).to.be.true; - } + isDomNode.assertIsNodeLike(node); + + const sig = new SignedXml(); + const res = sig.getCanonXml( + [ + "http://www.w3.org/2000/09/xmldsig#enveloped-signature", + "http://www.w3.org/2001/10/xml-exc-c14n#", + ], + node, + ); + expect(res).to.equal(''); }); it("Shouldn't continue processing transforms if we end up with a string as a result of a transform", function () { @@ -425,25 +421,22 @@ describe("Canonicalization unit tests", function () { ); const node1 = xpath.select1("//*[local-name(.)='y']", doc); const node2 = xpath.select1("//*[local-name(.)='y']", doc); - if (xpath.isNodeLike(node1) && xpath.isNodeLike(node2)) { - const sig = new SignedXml(); - const res1 = sig.getCanonXml( - [ - "http://www.w3.org/2001/10/xml-exc-c14n#", - "http://www.w3.org/2000/09/xmldsig#enveloped-signature", - ], - node1, + isDomNode.assertIsNodeLike(node1); + isDomNode.assertIsNodeLike(node2); + const sig = new SignedXml(); + const res1 = sig.getCanonXml( + [ + "http://www.w3.org/2001/10/xml-exc-c14n#", + "http://www.w3.org/2000/09/xmldsig#enveloped-signature", + ], + node1, + ); + const res2 = sig.getCanonXml(["http://www.w3.org/2001/10/xml-exc-c14n#"], node2); + expect(res1) + .to.equal(res2) + .to.equal( + '', ); - const res2 = sig.getCanonXml(["http://www.w3.org/2001/10/xml-exc-c14n#"], node2); - expect(res1) - .to.equal(res2) - .to.equal( - '', - ); - } else { - expect(xpath.isNodeLike(node1)).to.be.true; - expect(xpath.isNodeLike(node2)).to.be.true; - } }); it("Enveloped-signature canonicalization respects current node", function () { @@ -454,14 +447,12 @@ describe("Canonicalization unit tests", function () { ''; const doc = new xmldom.DOMParser().parseFromString(xml); const node = xpath.select1("//*[local-name(.)='y']", doc); - if (xpath.isNodeLike(node)) { - const sig = new SignedXml(); - const transforms = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature"]; - const res = sig.getCanonXml(transforms, node); - expect(res).to.equal(""); - } else { - expect(xpath.isNodeLike(node)).to.be.true; - } + isDomNode.assertIsNodeLike(node); + + const sig = new SignedXml(); + const transforms = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature"]; + const res = sig.getCanonXml(transforms, node); + expect(res).to.equal(""); }); it("The XML canonicalization method processes a node-set by imposing the following additional document order rules on the namespace and attribute nodes of each element: \ diff --git a/test/document-tests.spec.ts b/test/document-tests.spec.ts index c7e7cde0..88d40b29 100644 --- a/test/document-tests.spec.ts +++ b/test/document-tests.spec.ts @@ -3,20 +3,19 @@ import * as xpath from "xpath"; import * as xmldom from "@xmldom/xmldom"; import * as fs from "fs"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("Document tests", function () { it("test with a document (using FileKeyInfo)", function () { const xml = fs.readFileSync("./test/static/valid_saml.xml", "utf-8"); const doc = new xmldom.DOMParser().parseFromString(xml); - const signature = new xmldom.DOMParser().parseFromString( - // @ts-expect-error FIXME - xpath - .select( - "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - doc, - )[0] - .toString(), + const node = xpath.select1( + "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + doc, ); + + isDomNode.assertIsNodeLike(node); + const signature = new xmldom.DOMParser().parseFromString(node.toString()); const sig = new SignedXml(); sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); sig.loadSignature(signature); @@ -28,15 +27,13 @@ describe("Document tests", function () { it("test with a document (using StringKeyInfo)", function () { const xml = fs.readFileSync("./test/static/valid_saml.xml", "utf-8"); const doc = new xmldom.DOMParser().parseFromString(xml); - const signature = new xmldom.DOMParser().parseFromString( - // @ts-expect-error FIXME - xpath - .select( - "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - doc, - )[0] - .toString(), + const node = xpath.select1( + "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + doc, ); + + isDomNode.assertIsNodeLike(node); + const signature = new xmldom.DOMParser().parseFromString(node.toString()); const sig = new SignedXml(); const feidePublicCert = fs.readFileSync("./test/static/feide_public.pem"); sig.publicCert = feidePublicCert; diff --git a/test/hmac-tests.spec.ts b/test/hmac-tests.spec.ts index 2087f62d..aac2649d 100644 --- a/test/hmac-tests.spec.ts +++ b/test/hmac-tests.spec.ts @@ -3,6 +3,7 @@ import * as xpath from "xpath"; import * as xmldom from "@xmldom/xmldom"; import * as fs from "fs"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("HMAC tests", function () { it("test validating HMAC signature", function () { @@ -12,17 +13,15 @@ describe("HMAC tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.enableHMAC(); - sig.publicCert = fs.readFileSync("./test/static/hmac.key"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); + isDomNode.assertIsNodeLike(signature); - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + const sig = new SignedXml(); + sig.enableHMAC(); + sig.publicCert = fs.readFileSync("./test/static/hmac.key"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); + + expect(result).to.be.true; }); it("test HMAC signature with incorrect key", function () { @@ -32,17 +31,15 @@ describe("HMAC tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.enableHMAC(); - sig.publicCert = fs.readFileSync("./test/static/hmac-foobar.key"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); + isDomNode.assertIsNodeLike(signature); - expect(result).to.be.false; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + const sig = new SignedXml(); + sig.enableHMAC(); + sig.publicCert = fs.readFileSync("./test/static/hmac-foobar.key"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); + + expect(result).to.be.false; }); it("test create and validate HMAC signature", function () { @@ -59,16 +56,14 @@ describe("HMAC tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const verify = new SignedXml(); - verify.enableHMAC(); - verify.publicCert = fs.readFileSync("./test/static/hmac.key"); - verify.loadSignature(signature); - const result = verify.checkSignature(sig.getSignedXml()); + isDomNode.assertIsNodeLike(signature); + + const verify = new SignedXml(); + verify.enableHMAC(); + verify.publicCert = fs.readFileSync("./test/static/hmac.key"); + verify.loadSignature(signature); + const result = verify.checkSignature(sig.getSignedXml()); - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + expect(result).to.be.true; }); }); diff --git a/test/key-info-tests.spec.ts b/test/key-info-tests.spec.ts index c1977064..43e1af34 100644 --- a/test/key-info-tests.spec.ts +++ b/test/key-info-tests.spec.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as xpath from "xpath"; import { SignedXml } from "../src/index"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("KeyInfo tests", function () { it("adds X509Certificate element during signature", function () { @@ -14,12 +15,9 @@ describe("KeyInfo tests", function () { const signedXml = sig.getSignedXml(); const doc = new xmldom.DOMParser().parseFromString(signedXml); const x509 = xpath.select("//*[local-name(.)='X509Certificate']", doc.documentElement); - // @ts-expect-error FIXME - if (xpath.isArrayOfNodes(x509)) { - expect(x509.length, "X509Certificate element should exist").to.equal(1); - } else { - expect(xpath.isArrayOfNodes(x509)).to.be.true; - } + isDomNode.assertIsArrayOfNodes(x509); + + expect(x509.length, "X509Certificate element should exist").to.equal(1); }); it("make sure private hmac key is not leaked due to key confusion", function () { @@ -33,7 +31,6 @@ describe("KeyInfo tests", function () { sig.computeSignature(xml); const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); - const keyInfo = xpath.select1("//*[local-name(.)='KeyInfo']", doc); expect(keyInfo).to.be.undefined; diff --git a/test/saml-response-tests.spec.ts b/test/saml-response-tests.spec.ts index 5960e366..f02f96fe 100644 --- a/test/saml-response-tests.spec.ts +++ b/test/saml-response-tests.spec.ts @@ -3,6 +3,7 @@ import * as xpath from "xpath"; import * as xmldom from "@xmldom/xmldom"; import * as fs from "fs"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("SAML response tests", function () { it("test validating SAML response", function () { @@ -12,45 +13,36 @@ describe("SAML response tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + expect(result).to.be.true; }); it("test validating wrapped assertion signature", function () { const xml = fs.readFileSync("./test/static/valid_saml_signature_wrapping.xml", "utf-8"); const doc = new xmldom.DOMParser().parseFromString(xml); const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc); - if (xpath.isNodeLike(assertion)) { - const signature = xpath.select1( - "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - assertion, - ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); - sig.loadSignature(signature); - expect( - function () { - sig.checkSignature(xml); - }, - "Should not validate a document which contains multiple elements with the " + - "same value for the ID / Id / Id attributes, in order to prevent " + - "signature wrapping attack.", - ).to.throw(); - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } - } else { - expect(xpath.isNodeLike(assertion)).to.be.true; - } + isDomNode.assertIsNodeLike(assertion); + const signature = xpath.select1( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + assertion, + ); + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); + sig.loadSignature(signature); + expect( + function () { + sig.checkSignature(xml); + }, + "Should not validate a document which contains multiple elements with the " + + "same value for the ID / Id / Id attributes, in order to prevent " + + "signature wrapping attack.", + ).to.throw(); }); it("test validating SAML response where a namespace is defined outside the signed element", function () { @@ -60,39 +52,30 @@ describe("SAML response tests", function () { "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); + expect(result).to.be.true; }); it("test reference id does not contain quotes", function () { const xml = fs.readFileSync("./test/static/id_with_quotes.xml", "utf-8"); const doc = new xmldom.DOMParser().parseFromString(xml); const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc); - if (xpath.isNodeLike(assertion)) { - const signature = xpath.select1( - "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - assertion, - ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); - sig.loadSignature(signature); - expect(function () { - sig.checkSignature(xml); - }, "id should not contain quotes").to.throw(); - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } - } else { - expect(xpath.isNodeLike(assertion)).to.be.true; - } + isDomNode.assertIsNodeLike(assertion); + const signature = xpath.select1( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + assertion, + ); + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); + sig.loadSignature(signature); + expect(function () { + sig.checkSignature(xml); + }, "id should not contain quotes").to.throw(); }); it("test validating SAML response WithComments", function () { @@ -102,15 +85,12 @@ describe("SAML response tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); - // This doesn't matter, just want to make sure that we don't fail due to unknown algorithm - expect(result).to.be.false; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); + // This doesn't matter, just want to make sure that we don't fail due to unknown algorithm + expect(result).to.be.false; }); }); diff --git a/test/signature-integration-tests.spec.ts b/test/signature-integration-tests.spec.ts index 995405dd..53008c61 100644 --- a/test/signature-integration-tests.spec.ts +++ b/test/signature-integration-tests.spec.ts @@ -3,6 +3,7 @@ import * as xmldom from "@xmldom/xmldom"; import { SignedXml } from "../src/index"; import * as fs from "fs"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("Signature integration tests", function () { function verifySignature(xml, expected, xpath) { @@ -92,16 +93,13 @@ describe("Signature integration tests", function () { "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/windows_store_certificate.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(childXml ?? ""); - - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/windows_store_certificate.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(childXml ?? ""); + + expect(result).to.be.true; }); it("signature with inclusive namespaces", function () { @@ -113,16 +111,13 @@ describe("Signature integration tests", function () { "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(childXml ?? ""); - - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(childXml ?? ""); + + expect(result).to.be.true; }); it("signature with inclusive namespaces with unix line separators", function () { @@ -137,16 +132,13 @@ describe("Signature integration tests", function () { "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(childXml ?? ""); - - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(childXml ?? ""); + + expect(result).to.be.true; }); it("signature with inclusive namespaces with windows line separators", function () { @@ -161,16 +153,13 @@ describe("Signature integration tests", function () { "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(childXml ?? ""); - - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/signature_with_inclusivenamespaces.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(childXml ?? ""); + + expect(result).to.be.true; }); it("should create single root xml document when signing inner node", function () { diff --git a/test/signature-unit-tests.spec.ts b/test/signature-unit-tests.spec.ts index 8a185f8d..ac4bea90 100644 --- a/test/signature-unit-tests.spec.ts +++ b/test/signature-unit-tests.spec.ts @@ -4,7 +4,7 @@ import { SignedXml, createOptionalCallbackFunction } from "../src/index"; import * as fs from "fs"; import * as crypto from "crypto"; import { expect } from "chai"; -import * as utils from "../src/utils"; +import * as isDomNode from "is-dom-node"; describe("Signature unit tests", function () { function verifySignature(xml: string, idMode?: "wssecurity") { @@ -13,19 +13,16 @@ describe("Signature unit tests", function () { "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(node)) { - const sig = new SignedXml({ idMode }); - sig.publicCert = fs.readFileSync("./test/static/client_public.pem"); - sig.loadSignature(node); - try { - const res = sig.checkSignature(xml); - - return res; - } catch (e) { - return false; - } - } else { - expect(xpath.isNodeLike(node)).to.be.true; + isDomNode.assertIsNodeLike(node); + const sig = new SignedXml({ idMode }); + sig.publicCert = fs.readFileSync("./test/static/client_public.pem"); + sig.loadSignature(node); + try { + const res = sig.checkSignature(xml); + + return res; + } catch (e) { + return false; } } @@ -42,78 +39,59 @@ describe("Signature unit tests", function () { "/*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isElement(signature)) { - const sig = new SignedXml(); - sig.loadSignature(toString ? signature.toString() : signature); + isDomNode.assertIsElementNode(signature); + const sig = new SignedXml(); + sig.loadSignature(toString ? signature.toString() : signature); - expect(sig.canonicalizationAlgorithm, "wrong canonicalization method").to.equal( - "http://www.w3.org/2001/10/xml-exc-c14n#", - ); + expect(sig.canonicalizationAlgorithm, "wrong canonicalization method").to.equal( + "http://www.w3.org/2001/10/xml-exc-c14n#", + ); - expect(sig.signatureAlgorithm, "wrong signature method").to.equal( - "http://www.w3.org/2000/09/xmldsig#rsa-sha1", + expect(sig.signatureAlgorithm, "wrong signature method").to.equal( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1", + ); + + sig.getCertFromKeyInfo = (keyInfo) => { + isDomNode.assertIsNodeLike(keyInfo); + const keyInfoContents = xpath.select1( + "//*[local-name(.)='KeyInfo']/*[local-name(.)='dummyKey']", + keyInfo, ); + isDomNode.assertIsNodeLike(keyInfoContents); + const firstChild = keyInfoContents.firstChild; + isDomNode.assertIsTextNode(firstChild); + expect(firstChild.data, "keyInfo clause not correctly loaded").to.equal("1234"); - sig.getCertFromKeyInfo = (keyInfo) => { - // @ts-expect-error FIXME - if (xpath.isNodeLike(keyInfo)) { - const keyInfoContents = xpath.select1( - "//*[local-name(.)='KeyInfo']/*[local-name(.)='dummyKey']", - keyInfo, - ); - if (xpath.isNodeLike(keyInfoContents)) { - const firstChild = keyInfoContents.firstChild; - if (xpath.isTextNode(firstChild)) { - expect(firstChild.data, "keyInfo clause not correctly loaded").to.equal("1234"); - } else { - expect(xpath.isTextNode(firstChild), "keyInfo has improper format").to.be.true; - } - } else { - expect(xpath.isNodeLike(keyInfoContents), "KeyInfo contents not found").to.be.true; - } - } else { - // @ts-expect-error FIXME - expect(xpath.isNodeLike(keyInfo), "KeyInfo not found").to.be.true; - } - - return fs.readFileSync("./test/static/client.pem", "latin1"); - }; + return fs.readFileSync("./test/static/client.pem", "latin1"); + }; + + const checkedSignature = sig.checkSignature(xml); + expect(checkedSignature).to.be.true; + + expect(sig.references.length).to.equal(3); - const checkedSignature = sig.checkSignature(xml); - expect(checkedSignature).to.be.true; - - expect(sig.references.length).to.equal(3); - - const digests = [ - "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=", - "K4dI497ZCxzweDIrbndUSmtoezY=", - "sH1gxKve8wlU8LlFVa2l6w3HMJ0=", - ]; - - const firstGrandchild = doc.firstChild?.firstChild; - - // @ts-expect-error FIXME - if (xpath.isElement(firstGrandchild)) { - expect(() => sig.validateElementAgainstReferences(firstGrandchild, doc)).to.not.throw; - } else { - // @ts-expect-error FIXME - expect(xpath.isElement(firstGrandchild)).to.be.true; - } - - for (let i = 0; i < sig.references.length; i++) { - const ref = sig.references[i]; - const expectedUri = `#_${i}`; - expect( - ref.uri, - `wrong uri for index ${i}. expected: ${expectedUri} actual: ${ref.uri}`, - ).to.equal(expectedUri); - expect(ref.transforms.length).to.equal(1); - expect(ref.transforms[0]).to.equal("http://www.w3.org/2001/10/xml-exc-c14n#"); - expect(ref.digestValue).to.equal(digests[i]); - expect(ref.digestAlgorithm).to.equal("http://www.w3.org/2000/09/xmldsig#sha1"); - } - } else { - expect(xpath.isNodeLike(signature)).to.be.true; + const digests = [ + "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=", + "K4dI497ZCxzweDIrbndUSmtoezY=", + "sH1gxKve8wlU8LlFVa2l6w3HMJ0=", + ]; + + const firstGrandchild = doc.firstChild?.firstChild; + isDomNode.assertIsElementNode(firstGrandchild); + const matchedReference = sig.validateElementAgainstReferences(firstGrandchild, doc); + expect(matchedReference).to.not.be.false; + + for (let i = 0; i < sig.references.length; i++) { + const ref = sig.references[i]; + const expectedUri = `#_${i}`; + expect( + ref.uri, + `wrong uri for index ${i}. expected: ${expectedUri} actual: ${ref.uri}`, + ).to.equal(expectedUri); + expect(ref.transforms.length).to.equal(1); + expect(ref.transforms[0]).to.equal("http://www.w3.org/2001/10/xml-exc-c14n#"); + expect(ref.digestValue).to.equal(digests[i]); + expect(ref.digestAlgorithm).to.equal("http://www.w3.org/2000/09/xmldsig#sha1"); } } @@ -132,12 +110,8 @@ describe("Signature unit tests", function () { const signedXml = sig.getOriginalXmlWithIds(); const doc = new xmldom.DOMParser().parseFromString(signedXml); const attrs = xpath.select("//@*", doc); - // @ts-expect-error FIXME - if (xpath.isArrayOfNodes(attrs)) { - expect(attrs.length, "wrong number of attributes").to.equal(2); - } else { - expect(xpath.isArrayOfNodes(attrs)).to.be.true; - } + isDomNode.assertIsArrayOfNodes(attrs); + expect(attrs.length, "wrong number of attributes").to.equal(2); } function nodeExists(doc, xpathArg) { @@ -145,7 +119,7 @@ describe("Signature unit tests", function () { return; } const node = xpath.select(xpathArg, doc); - // @ts-expect-error FIXME + isDomNode.assertIsArrayOfNodes(node); expect(node.length, `xpath ${xpathArg} not found`).to.equal(1); } @@ -227,12 +201,8 @@ describe("Signature unit tests", function () { const signedXml = sig.getSignatureXml(); const doc = new xmldom.DOMParser().parseFromString(signedXml); const references = xpath.select("//*[local-name(.)='Reference']", doc); - // @ts-expect-error FIXME - if (xpath.isArrayOfNodes(references)) { - expect(references.length).to.equal(2); - } else { - expect(xpath.isArrayOfNodes(references)).to.be.true; - } + isDomNode.assertIsArrayOfNodes(references); + expect(references.length).to.equal(2); } it("signer adds increasing id attributes to elements", function () { @@ -264,14 +234,11 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); const lastChild = doc.documentElement.lastChild; - if (xpath.isElement(lastChild)) { - expect( - lastChild.localName, - "the signature must be appended to the root node by default", - ).to.equal("Signature"); - } else { - expect(xpath.isElement(lastChild)).to.be.true; - } + isDomNode.assertIsElementNode(lastChild); + expect( + lastChild.localName, + "the signature must be appended to the root node by default", + ).to.equal("Signature"); }); it("signer appends signature to a reference node", function () { @@ -291,19 +258,13 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); const referenceNode = xpath.select1("/root/name", doc); - if (xpath.isNodeLike(referenceNode)) { - const lastChild = referenceNode.lastChild; - - if (xpath.isElement(lastChild)) { - expect(lastChild.localName, "the signature should be appended to root/name").to.equal( - "Signature", - ); - } else { - expect(xpath.isElement(lastChild)).to.be.true; - } - } else { - expect(xpath.isNodeLike(referenceNode)).to.be.true; - } + isDomNode.assertIsNodeLike(referenceNode); + const lastChild = referenceNode.lastChild; + + isDomNode.assertIsElementNode(lastChild); + expect(lastChild.localName, "the signature should be appended to root/name").to.equal( + "Signature", + ); }); it("signer prepends signature to a reference node", function () { @@ -322,19 +283,13 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); const referenceNode = xpath.select1("/root/name", doc); - if (xpath.isNodeLike(referenceNode)) { - const firstChild = referenceNode.firstChild; - - if (xpath.isElement(firstChild)) { - expect(firstChild.localName, "the signature should be prepended to root/name").to.equal( - "Signature", - ); - } else { - expect(xpath.isElement(firstChild)).to.be.true; - } - } else { - expect(xpath.isNodeLike(referenceNode)).to.be.true; - } + isDomNode.assertIsNodeLike(referenceNode); + const firstChild = referenceNode.firstChild; + + isDomNode.assertIsElementNode(firstChild); + expect(firstChild.localName, "the signature should be prepended to root/name").to.equal( + "Signature", + ); }); it("signer inserts signature before a reference node", function () { @@ -353,20 +308,14 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); const referenceNode = xpath.select1("/root/name", doc); - if (xpath.isNodeLike(referenceNode)) { - const previousSibling = referenceNode.previousSibling; - - if (xpath.isElement(previousSibling)) { - expect( - previousSibling.localName, - "the signature should be inserted before to root/name", - ).to.equal("Signature"); - } else { - expect(xpath.isElement(previousSibling)).to.be.true; - } - } else { - expect(xpath.isNodeLike(referenceNode)).to.be.true; - } + isDomNode.assertIsNodeLike(referenceNode); + const previousSibling = referenceNode.previousSibling; + + isDomNode.assertIsElementNode(previousSibling); + expect( + previousSibling.localName, + "the signature should be inserted before to root/name", + ).to.equal("Signature"); }); it("signer inserts signature after a reference node", function () { @@ -386,20 +335,13 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml()); const referenceNode = xpath.select1("/root/name", doc); - if (xpath.isNodeLike(referenceNode)) { - const nextSibling = referenceNode.nextSibling; - - if (xpath.isElement(nextSibling)) { - expect( - nextSibling.localName, - "the signature should be inserted after to root/name", - ).to.equal("Signature"); - } else { - expect(xpath.isElement(nextSibling)).to.be.true; - } - } else { - expect(xpath.isNodeLike(referenceNode)).to.be.true; - } + isDomNode.assertIsNodeLike(referenceNode); + const nextSibling = referenceNode.nextSibling; + + isDomNode.assertIsElementNode(nextSibling); + expect(nextSibling.localName, "the signature should be inserted after to root/name").to.equal( + "Signature", + ); }); it("signer creates signature with correct structure", function () { @@ -945,11 +887,8 @@ describe("Signature unit tests", function () { const signedXml = sig.getSignedXml(); const doc = new xmldom.DOMParser().parseFromString(signedXml); const URI = xpath.select1("//*[local-name(.)='Reference']/@URI", doc); - if (xpath.isAttribute(URI)) { - expect(URI.value, `uri should be empty but instead was ${URI.value}`).to.equal(""); - } else { - expect(xpath.isAttribute(URI)).to.be.true; - } + isDomNode.assertIsAttributeNode(URI); + expect(URI.value, `uri should be empty but instead was ${URI.value}`).to.equal(""); }); it("signer appends signature to a non-existing reference node", function () { @@ -1036,13 +975,13 @@ describe("Signature unit tests", function () { "//*[local-name(.)='Reference']/*[local-name(.)='Transforms']/*[local-name(.)='Transform']/*[local-name(.)='InclusiveNamespaces']", doc.documentElement, ); - expect( - utils.isArrayHasLength(inclusiveNamespaces) && inclusiveNamespaces.length, - "InclusiveNamespaces element should exist", - ).to.equal(1); + isDomNode.assertIsArrayOfNodes(inclusiveNamespaces); + expect(inclusiveNamespaces.length, "InclusiveNamespaces element should exist").to.equal(1); + + const firstNamespace = inclusiveNamespaces[0]; + isDomNode.assertIsElementNode(firstNamespace); - // @ts-expect-error FIXME - const prefixListAttribute = inclusiveNamespaces[0].getAttribute("PrefixList"); + const prefixListAttribute = firstNamespace.getAttribute("PrefixList"); expect( prefixListAttribute, "InclusiveNamespaces element should have the correct PrefixList attribute value", @@ -1095,13 +1034,17 @@ describe("Signature unit tests", function () { doc.documentElement, ); + isDomNode.assertIsArrayOfNodes(inclusiveNamespaces); + expect( - utils.isArrayHasLength(inclusiveNamespaces) && inclusiveNamespaces.length, + inclusiveNamespaces.length, "InclusiveNamespaces element should exist inside CanonicalizationMethod", ).to.equal(1); - // @ts-expect-error FIXME - const prefixListAttribute = inclusiveNamespaces[0].getAttribute("PrefixList"); + const firstNamespace = inclusiveNamespaces[0]; + isDomNode.assertIsElementNode(firstNamespace); + + const prefixListAttribute = firstNamespace.getAttribute("PrefixList"); expect( prefixListAttribute, "InclusiveNamespaces element inside CanonicalizationMethod should have the correct PrefixList attribute value", @@ -1150,31 +1093,22 @@ describe("Signature unit tests", function () { const doc = new xmldom.DOMParser().parseFromString(signedXml); const keyInfoElements = xpath.select("//*[local-name(.)='KeyInfo']", doc.documentElement); - // @ts-expect-error FIXME - if (xpath.isArrayOfNodes(keyInfoElements)) { - expect(keyInfoElements.length, "KeyInfo element should exist").to.equal(1); - const keyInfoElement = keyInfoElements[0]; - - if (xpath.isElement(keyInfoElement)) { - const algorithmAttribute = keyInfoElement.getAttribute("CustomUri"); - expect( - algorithmAttribute, - "KeyInfo element should have the correct CustomUri attribute value", - ).to.equal("http://www.example.com/keyinfo"); - - const customAttribute = keyInfoElement.getAttribute("CustomAttribute"); - expect( - customAttribute, - "KeyInfo element should have the correct CustomAttribute attribute value", - ).to.equal("custom-value"); - } else { - expect(xpath.isElement(keyInfoElement), "KeyInfo element should be an element node").to.be - .true; - } - } else { - expect(xpath.isArrayOfNodes(keyInfoElements), "KeyInfo should be an array of nodes").to.be - .true; - } + isDomNode.assertIsArrayOfNodes(keyInfoElements); + expect(keyInfoElements.length, "KeyInfo element should exist").to.equal(1); + const keyInfoElement = keyInfoElements[0]; + + isDomNode.assertIsElementNode(keyInfoElement); + const algorithmAttribute = keyInfoElement.getAttribute("CustomUri"); + expect( + algorithmAttribute, + "KeyInfo element should have the correct CustomUri attribute value", + ).to.equal("http://www.example.com/keyinfo"); + + const customAttribute = keyInfoElement.getAttribute("CustomAttribute"); + expect( + customAttribute, + "KeyInfo element should have the correct CustomAttribute attribute value", + ).to.equal("custom-value"); }); it("adds all certificates and does not add private keys to KeyInfo element", function () { @@ -1192,31 +1126,24 @@ describe("Signature unit tests", function () { "//*[local-name(.)='X509Certificate']", doc.documentElement, ); - // @ts-expect-error FIXME - if (xpath.isArrayOfNodes(x509certificates)) { - expect(x509certificates.length, "There should be exactly two certificates").to.equal(2); + isDomNode.assertIsArrayOfNodes(x509certificates); + expect(x509certificates.length, "There should be exactly two certificates").to.equal(2); - const cert1 = x509certificates[0]; - const cert2 = x509certificates[1]; - expect(cert1.textContent, "X509Certificate[0] TextContent does not exist").to.exist; - expect(cert2.textContent, "X509Certificate[1] TextContent does not exist").to.exist; + const cert1 = x509certificates[0]; + const cert2 = x509certificates[1]; + expect(cert1.textContent, "X509Certificate[0] TextContent does not exist").to.exist; + expect(cert2.textContent, "X509Certificate[1] TextContent does not exist").to.exist; - const trimmedTextContent1 = cert1.textContent?.trim(); - const trimmedTextContent2 = cert2.textContent?.trim(); - expect(trimmedTextContent1, "Empty certificate added [0]").to.not.be.empty; - expect(trimmedTextContent2, "Empty certificate added [1]").to.not.be.empty; + const trimmedTextContent1 = cert1.textContent?.trim(); + const trimmedTextContent2 = cert2.textContent?.trim(); + expect(trimmedTextContent1, "Empty certificate added [0]").to.not.be.empty; + expect(trimmedTextContent2, "Empty certificate added [1]").to.not.be.empty; - expect( - trimmedTextContent1?.substring(0, 5), - "Incorrect value for X509Certificate[0]", - ).to.equal("MIIDC"); - expect( - trimmedTextContent2?.substring(0, 5), - "Incorrect value for X509Certificate[1]", - ).to.equal("MIIDZ"); - } else { - expect(xpath.isArrayOfNodes(x509certificates), "X509Certificate should be an array of nodes") - .to.be.true; - } + expect(trimmedTextContent1?.substring(0, 5), "Incorrect value for X509Certificate[0]").to.equal( + "MIIDC", + ); + expect(trimmedTextContent2?.substring(0, 5), "Incorrect value for X509Certificate[1]").to.equal( + "MIIDZ", + ); }); }); diff --git a/test/wsfed-metadata-tests.spec.ts b/test/wsfed-metadata-tests.spec.ts index 7f742ea7..8458e785 100644 --- a/test/wsfed-metadata-tests.spec.ts +++ b/test/wsfed-metadata-tests.spec.ts @@ -3,6 +3,7 @@ import * as xpath from "xpath"; import * as xmldom from "@xmldom/xmldom"; import * as fs from "fs"; import { expect } from "chai"; +import * as isDomNode from "is-dom-node"; describe("WS-Fed Metadata tests", function () { it("test validating WS-Fed Metadata", function () { @@ -12,15 +13,12 @@ describe("WS-Fed Metadata tests", function () { "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", doc, ); - if (xpath.isNodeLike(signature)) { - const sig = new SignedXml(); - sig.publicCert = fs.readFileSync("./test/static/wsfederation_metadata.pem"); - sig.loadSignature(signature); - const result = sig.checkSignature(xml); + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/wsfederation_metadata.pem"); + sig.loadSignature(signature); + const result = sig.checkSignature(xml); - expect(result).to.be.true; - } else { - expect(xpath.isNodeLike(signature)).to.be.true; - } + expect(result).to.be.true; }); });