Skip to content

Commit

Permalink
Use is-dom-node for DOM Node checking and narrowing
Browse files Browse the repository at this point in the history
  • Loading branch information
cjbarth committed Sep 18, 2023
1 parent b0f00d0 commit 3cf5e51
Show file tree
Hide file tree
Showing 17 changed files with 382 additions and 500 deletions.
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions src/c14n-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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(
Expand Down
7 changes: 4 additions & 3 deletions src/enveloped-signature.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as xpath from "xpath";
import * as isDomNode from "is-dom-node";

import type {
CanonicalizationOrTransformationAlgorithm,
Expand All @@ -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;
Expand All @@ -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(
Expand All @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions src/exclusive-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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(
Expand Down
21 changes: 11 additions & 10 deletions src/signed-xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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");
}
}
Expand Down Expand Up @@ -398,7 +399,7 @@ export class SignedXml {
}

// @ts-expect-error FIXME: xpath types are wrong
if (!xpath.isNodeLike(targetElem)) {
if (!isDomNode.isNodeLike(targetElem)) {
continue;
}

Expand Down Expand Up @@ -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`,
);
Expand Down Expand Up @@ -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;
}

Expand All @@ -509,7 +510,7 @@ export class SignedXml {
signatureNode,
);

if (xpath.isAttribute(signatureAlgorithm)) {
if (isDomNode.isAttributeNode(signatureAlgorithm)) {
this.signatureAlgorithm = signatureAlgorithm.value as SignatureAlgorithmType;
}

Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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}`,
);
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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)
) {
Expand Down Expand Up @@ -192,7 +193,7 @@ function collectAncestorNamespaces(
node: Element,
nsArray: NamespacePrefix[] = [],
): NamespacePrefix[] {
if (!xpath.isElement(node.parentNode)) {
if (!isDomNode.isElementNode(node.parentNode)) {
return nsArray;
}

Expand Down Expand Up @@ -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));
}

/**
Expand Down
17 changes: 8 additions & 9 deletions test/c14n-non-exclusive-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down
42 changes: 17 additions & 25 deletions test/c14nWithComments-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -354,19 +352,16 @@ describe("Exclusive canonicalization with comments", function () {
'<x xmlns:p="myns"><p:y><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"></ds:Signature></p:y></x>',
);
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('<p:y xmlns:p="myns"></p:y>');
} 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('<p:y xmlns:p="myns"></p:y>');
});

it("Enveloped-signature canonicalization respects current node", function () {
Expand All @@ -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("<y/>");
} else {
expect(xpath.isNodeLike(node)).to.be.true;
}
isDomNode.assertIsNodeLike(node);
const res = sig.getCanonXml(transforms, node);
expect(res).to.equal("<y/>");
});

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: \
Expand Down
Loading

0 comments on commit 3cf5e51

Please sign in to comment.