diff --git a/src/c14n-canonicalization.ts b/src/c14n-canonicalization.ts
index 91ee3009..76b5bec7 100644
--- a/src/c14n-canonicalization.ts
+++ b/src/c14n-canonicalization.ts
@@ -167,34 +167,38 @@ export class C14nCanonicalization implements CanonicalizationOrTransformationAlg
return { rendered: res.join(""), newDefaultNs };
}
- processInner(node, prefixesInScope, defaultNs, defaultNsForPrefix, ancestorNamespaces) {
+ processInner(node: Node, prefixesInScope, defaultNs, defaultNsForPrefix, ancestorNamespaces) {
if (xpath.isComment(node)) {
return this.renderComment(node);
}
- if (node.data) {
+ if (xpath.isComment(node)) {
return utils.encodeSpecialCharactersInText(node.data);
}
- let i;
- let pfxCopy;
- const ns = this.renderNs(
- node,
- prefixesInScope,
- defaultNs,
- defaultNsForPrefix,
- ancestorNamespaces,
- );
- const res = ["<", node.tagName, ns.rendered, this.renderAttrs(node), ">"];
-
- for (i = 0; i < node.childNodes.length; ++i) {
- pfxCopy = prefixesInScope.slice(0);
- res.push(
- this.processInner(node.childNodes[i], pfxCopy, ns.newDefaultNs, defaultNsForPrefix, []),
+ if (xpath.isElement(node)) {
+ let i;
+ let pfxCopy;
+ const ns = this.renderNs(
+ node,
+ prefixesInScope,
+ defaultNs,
+ defaultNsForPrefix,
+ ancestorNamespaces,
);
+ const res = ["<", node.tagName, ns.rendered, this.renderAttrs(node), ">"];
+
+ for (i = 0; i < node.childNodes.length; ++i) {
+ pfxCopy = prefixesInScope.slice(0);
+ res.push(
+ this.processInner(node.childNodes[i], pfxCopy, ns.newDefaultNs, defaultNsForPrefix, []),
+ );
+ }
+
+ res.push("", node.tagName, ">");
+ return res.join("");
}
- res.push("", node.tagName, ">");
- return res.join("");
+ return "";
}
// Thanks to deoxxa/xml-c14n for comment renderer
@@ -240,8 +244,7 @@ export class C14nCanonicalization implements CanonicalizationOrTransformationAlg
/**
* Perform canonicalization of the given node
*
- * @param {Node} node
- * @return {String}
+ * @param node
* @api public
*/
process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions) {
diff --git a/src/signed-xml.ts b/src/signed-xml.ts
index 2fd9fd3e..b5d7da13 100644
--- a/src/signed-xml.ts
+++ b/src/signed-xml.ts
@@ -311,7 +311,7 @@ export class SignedXml {
return this.getCanonXml([this.canonicalizationAlgorithm], signedInfo[0], c14nOptions);
}
- getCanonReferenceXml(doc, ref, node) {
+ getCanonReferenceXml(doc: Document, ref: Reference, node: Node) {
/**
* Search for ancestor namespaces before canonicalization.
*/
@@ -505,7 +505,6 @@ export class SignedXml {
const keyInfo = xpath.select1(".//*[local-name(.)='KeyInfo']", signatureNode);
- // TODO: should this just be a single return instead of an array that we always take the first entry of?
if (xpath.isNodeLike(keyInfo)) {
this.keyInfo = keyInfo;
}
@@ -515,10 +514,10 @@ export class SignedXml {
* Load the reference xml node to a model
*
*/
- loadReference(ref) {
- let nodes = utils.findChildren(ref, "DigestMethod");
+ loadReference(refNode: Node) {
+ let nodes = utils.findChildren(refNode, "DigestMethod");
if (nodes.length === 0) {
- throw new Error(`could not find DigestMethod in reference ${ref.toString()}`);
+ throw new Error(`could not find DigestMethod in reference ${refNode.toString()}`);
}
const digestAlgoNode = nodes[0];
@@ -528,9 +527,9 @@ export class SignedXml {
}
const digestAlgo = attr.value;
- nodes = utils.findChildren(ref, "DigestValue");
+ nodes = utils.findChildren(refNode, "DigestValue");
if (nodes.length === 0) {
- throw new Error(`could not find DigestValue node in reference ${ref.toString()}`);
+ throw new Error(`could not find DigestValue node in reference ${refNode.toString()}`);
}
const firstChild = nodes[0].firstChild;
if (!firstChild || !("data" in firstChild)) {
@@ -540,7 +539,7 @@ export class SignedXml {
const transforms: string[] = [];
let inclusiveNamespacesPrefixList: string[] = [];
- nodes = utils.findChildren(ref, "Transforms");
+ nodes = utils.findChildren(refNode, "Transforms");
if (nodes.length !== 0) {
const transformsNode = nodes[0];
const transformsAll = utils.findChildren(transformsNode, "Transform");
@@ -590,7 +589,7 @@ export class SignedXml {
this.addReference({
transforms,
digestAlgorithm: digestAlgo,
- uri: utils.findAttr(ref, "URI")?.value,
+ uri: xpath.isElement(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined,
digestValue,
inclusiveNamespacesPrefixList,
isEmptyUri: false,
@@ -908,19 +907,19 @@ export class SignedXml {
}
getCanonXml(
- transforms: CanonicalizationAlgorithmType[],
- node,
- options: CanonicalizationOrTransformationAlgorithmProcessOptions,
+ transforms: Reference["transforms"],
+ node: Node,
+ options: CanonicalizationOrTransformationAlgorithmProcessOptions = {},
) {
- options = options || {};
options.defaultNsForPrefix = options.defaultNsForPrefix ?? SignedXml.defaultNsForPrefix;
options.signatureNode = this.signatureNode;
- let canonXml = node.cloneNode(true); // Deep clone
+ const canonXml = node.cloneNode(true); // Deep clone
+ let transformedXml: string = canonXml.toString();
transforms.forEach((transformName) => {
const transform = this.findCanonicalizationAlgorithm(transformName);
- canonXml = transform.process(canonXml, options);
+ transformedXml = transform.process(canonXml, options).toString();
//TODO: currently transform.process may return either Node or String value (enveloped transformation returns Node, exclusive-canonicalization returns String).
//This either needs to be more explicit in the API, or all should return the same.
//exclusive-canonicalization returns String since it builds the Xml by hand. If it had used xmldom it would incorrectly minimize empty tags
@@ -930,7 +929,7 @@ export class SignedXml {
//if only y is the node to sign then a string would be without the definition of the p namespace. probably xmldom toString() should have added it.
});
- return canonXml.toString();
+ return transformedXml;
}
/**
diff --git a/src/utils.ts b/src/utils.ts
index dad31a85..f1226a26 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -76,7 +76,7 @@ export function encodeSpecialCharactersInAttribute(attributeValue) {
});
}
-export function encodeSpecialCharactersInText(text) {
+export function encodeSpecialCharactersInText(text: string): string {
return text.replace(/([&<>\r])/g, function (str, item) {
// Special character normalization. See:
// - https://www.w3.org/TR/xml-c14n#ProcessingModel (Text Nodes)
@@ -232,16 +232,20 @@ function isElementSubset(docSubset: Node[]): docSubset is Element[] {
* Extract ancestor namespaces in order to import it to root of document subset
* which is being canonicalized for non-exclusive c14n.
*
- * @param {object} doc - Usually a product from `new xmldom.DOMParser().parseFromString()`
- * @param {string} docSubsetXpath - xpath query to get document subset being canonicalized
- * @param {object} namespaceResolver - xpath namespace resolver
- * @returns {Array} i.e. [{prefix: "saml", namespaceURI: "urn:oasis:names:tc:SAML:2.0:assertion"}]
+ * @param doc - Usually a product from `new xmldom.DOMParser().parseFromString()`
+ * @param docSubsetXpath - xpath query to get document subset being canonicalized
+ * @param namespaceResolver - xpath namespace resolver
+ * @returns i.e. [{prefix: "saml", namespaceURI: "urn:oasis:names:tc:SAML:2.0:assertion"}]
*/
export function findAncestorNs(
- doc: Node,
- docSubsetXpath: string,
+ doc: Document,
+ docSubsetXpath?: string,
namespaceResolver?: XPathNSResolver,
-) {
+): NamespacePrefix[] {
+ if (docSubsetXpath == null) {
+ return [];
+ }
+
const docSubset = xpath.selectWithResolver(docSubsetXpath, doc, namespaceResolver);
if (!isArrayHasLength(docSubset)) {
@@ -289,7 +293,6 @@ export function validateDigestValue(digest, expectedDigest) {
return buffer.equals(expectedBuffer);
}
- // Compatibility with Node < 0.11.13
if (buffer.length !== expectedBuffer.length) {
return false;
}
diff --git a/test/c14nWithComments-unit-tests.spec.ts b/test/c14nWithComments-unit-tests.spec.ts
index 4b4f033d..3b196a94 100644
--- a/test/c14nWithComments-unit-tests.spec.ts
+++ b/test/c14nWithComments-unit-tests.spec.ts
@@ -350,16 +350,19 @@ describe("Exclusive canonicalization with comments", function () {
//var doc = new Dom().parseFromString("")
const doc = new xmldom.DOMParser().parseFromString('');
const node = xpath.select1("//*[local-name(.)='y']", doc);
- const sig = new SignedXml();
- // @ts-expect-error FIXME
- 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('');
+ 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;
+ }
});
it("Enveloped-signature canonicalization respects currentnode", function () {
@@ -372,9 +375,12 @@ 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"];
- // @ts-expect-error FIXME
- const res = sig.getCanonXml(transforms, node);
- expect(res).to.equal("");
+ if (xpath.isNodeLike(node)) {
+ const res = sig.getCanonXml(transforms, node);
+ expect(res).to.equal("");
+ } else {
+ expect(xpath.isNodeLike(node)).to.be.true;
+ }
});
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 85b6a12f..f91193c8 100644
--- a/test/canonicalization-unit-tests.spec.ts
+++ b/test/canonicalization-unit-tests.spec.ts
@@ -399,16 +399,19 @@ describe("Canonicalization unit tests", function () {
//var doc = new Dom().parseFromString("")
const doc = new xmldom.DOMParser().parseFromString('');
const node = xpath.select1("//*[local-name(.)='y']", doc);
- const sig = new SignedXml();
- // @ts-expect-error FIXME
- 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('');
+ 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;
+ }
});
it("Enveloped-signature canonicalization respects currentnode", function () {
@@ -419,11 +422,14 @@ describe("Canonicalization unit tests", function () {
'';
const doc = new xmldom.DOMParser().parseFromString(xml);
const node = xpath.select1("//*[local-name(.)='y']", doc);
- const sig = new SignedXml();
- const transforms = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature"];
- // @ts-expect-error FIXME
- const res = sig.getCanonXml(transforms, node);
- expect(res).to.equal("");
+ 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;
+ }
});
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/key-info-tests.spec.ts b/test/key-info-tests.spec.ts
index e46b2577..c1977064 100644
--- a/test/key-info-tests.spec.ts
+++ b/test/key-info-tests.spec.ts
@@ -15,7 +15,11 @@ describe("KeyInfo tests", function () {
const doc = new xmldom.DOMParser().parseFromString(signedXml);
const x509 = xpath.select("//*[local-name(.)='X509Certificate']", doc.documentElement);
// @ts-expect-error FIXME
- expect(x509.length, "X509Certificate element should exist").to.equal(1);
+ if (xpath.isArrayOfNodes(x509)) {
+ expect(x509.length, "X509Certificate element should exist").to.equal(1);
+ } else {
+ expect(xpath.isArrayOfNodes(x509)).to.be.true;
+ }
});
it("make sure private hmac key is not leaked due to key confusion", function () {
diff --git a/test/signature-unit-tests.spec.ts b/test/signature-unit-tests.spec.ts
index 9dcb0d29..f7e558db 100644
--- a/test/signature-unit-tests.spec.ts
+++ b/test/signature-unit-tests.spec.ts
@@ -1,103 +1,124 @@
import * as xpath from "xpath";
import * as xmldom from "@xmldom/xmldom";
-import { SignedXml } from "../src/index";
+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";
describe("Signature unit tests", function () {
- function verifySignature(xml, mode) {
+ function verifySignature(xml: string, idMode?: "wssecurity") {
const doc = new xmldom.DOMParser().parseFromString(xml);
const node = xpath.select1(
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
doc,
);
-
- const sig = new SignedXml({ idMode: mode });
- sig.publicCert = fs.readFileSync("./test/static/client_public.pem");
- // @ts-expect-error FIXME
- sig.loadSignature(node);
- try {
- const res = sig.checkSignature(xml);
-
- return res;
- } catch (e) {
- return false;
+ 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;
}
}
- function passValidSignature(file, mode) {
+ function passValidSignature(file: string, mode?: "wssecurity") {
const xml = fs.readFileSync(file, "utf8");
const res = verifySignature(xml, mode);
expect(res, "expected signature to be valid, but it was reported invalid").to.equal(true);
}
- function passLoadSignature(file, toString) {
+ function passLoadSignature(file: string, toString?: boolean) {
const xml = fs.readFileSync(file, "utf8");
const doc = new xmldom.DOMParser().parseFromString(xml);
- const node = xpath.select1(
+ const signature = xpath.select1(
"/*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
doc,
);
- const sig = new SignedXml();
- // @ts-expect-error FIXME
- sig.loadSignature(toString ? node.toString() : node);
+ if (xpath.isElement(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",
+ );
- // @ts-expect-error FIXME
- expect(sig.signatureValue, "wrong signature value").to.equal(
- "PI2xGt3XrVcxYZ34Kw7nFdq75c7Mmo7J0q7yeDhBprHuJal/KV9KyKG+Zy3bmQIxNwkPh0KMP5r1YMTKlyifwbWK0JitRCSa0Fa6z6+TgJi193yiR5S1MQ+esoQT0RzyIOBl9/GuJmXx/1rXnqrTxmL7UxtqKuM29/eHwF0QDUI=",
- );
+ 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");
+ };
- const keyInfo = xpath.select1(
- "//*[local-name(.)='KeyInfo']/*[local-name(.)='dummyKey']",
- // @ts-expect-error FIXME
- sig.keyInfo,
- );
- // @ts-expect-error FIXME
- expect(keyInfo.firstChild.data, "keyInfo clause not correctly loaded").to.equal("1234");
+ const checkedSignature = sig.checkSignature(xml);
+ expect(checkedSignature).to.be.true;
- // @ts-expect-error FIXME
- expect(sig.references.length).to.equal(3);
+ // @ts-expect-error FIXME
+ expect(sig.references.length).to.equal(3);
- const digests = [
- "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=",
- "K4dI497ZCxzweDIrbndUSmtoezY=",
- "sH1gxKve8wlU8LlFVa2l6w3HMJ0=",
- ];
+ const digests = [
+ "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=",
+ "K4dI497ZCxzweDIrbndUSmtoezY=",
+ "sH1gxKve8wlU8LlFVa2l6w3HMJ0=",
+ ];
- // @ts-expect-error FIXME
- for (let i = 0; i < sig.references.length; i++) {
// @ts-expect-error FIXME
- 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");
+ for (let i = 0; i < sig.references.length; i++) {
+ // @ts-expect-error FIXME
+ 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;
}
}
- function failInvalidSignature(file, mode) {
+ function failInvalidSignature(file: string, idMode?: "wssecurity") {
const xml = fs.readFileSync(file).toString();
- const res = verifySignature(xml, mode);
+ const res = verifySignature(xml, idMode);
expect(res, "expected signature to be invalid, but it was reported valid").to.equal(false);
}
- function verifyDoesNotDuplicateIdAttributes(mode, prefix) {
+ function verifyDoesNotDuplicateIdAttributes(prefix: string, idMode?: "wssecurity") {
const xml = ``;
- const sig = new SignedXml({ idMode: mode });
+ const sig = new SignedXml({ idMode });
sig.privateKey = fs.readFileSync("./test/static/client.pem");
sig.addReference({ xpath: "//*[local-name(.)='x']" });
sig.computeSignature(xml);
@@ -105,7 +126,11 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(signedXml);
const attrs = xpath.select("//@*", doc);
// @ts-expect-error FIXME
- expect(attrs.length, "wrong number of attributes").to.equal(2);
+ if (xpath.isArrayOfNodes(attrs)) {
+ expect(attrs.length, "wrong number of attributes").to.equal(2);
+ } else {
+ expect(xpath.isArrayOfNodes(attrs)).to.be.true;
+ }
}
function nodeExists(doc, xpathArg) {
@@ -196,7 +221,11 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(signedXml);
const references = xpath.select("//*[local-name(.)='Reference']", doc);
// @ts-expect-error FIXME
- expect(references.length).to.equal(2);
+ if (xpath.isArrayOfNodes(references)) {
+ expect(references.length).to.equal(2);
+ } else {
+ expect(xpath.isArrayOfNodes(references)).to.be.true;
+ }
}
it("signer adds increasing id attributes to elements", function () {
@@ -209,8 +238,8 @@ describe("Signature unit tests", function () {
});
it("signer does not duplicate existing id attributes", function () {
- verifyDoesNotDuplicateIdAttributes(null, "");
- verifyDoesNotDuplicateIdAttributes("wssecurity", "wsu:");
+ verifyDoesNotDuplicateIdAttributes("");
+ verifyDoesNotDuplicateIdAttributes("wsu:", "wssecurity");
});
it("signer adds custom attributes to the signature root node", function () {
@@ -227,11 +256,15 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
- expect(
- // @ts-expect-error FIXME
- doc.documentElement.lastChild.localName,
- "the signature must be appended to the root node by default",
- ).to.equal("Signature");
+ 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;
+ }
});
it("signer appends signature to a reference node", function () {
@@ -251,11 +284,19 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
const referenceNode = xpath.select1("/root/name", doc);
- expect(
- // @ts-expect-error FIXME
- referenceNode.lastChild.localName,
- "the signature should be appended to root/name",
- ).to.equal("Signature");
+ 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;
+ }
});
it("signer prepends signature to a reference node", function () {
@@ -274,12 +315,19 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
const referenceNode = xpath.select1("/root/name", doc);
-
- expect(
- // @ts-expect-error FIXME
- referenceNode.firstChild.localName,
- "the signature should be prepended to root/name",
- ).to.equal("Signature");
+ 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;
+ }
});
it("signer inserts signature before a reference node", function () {
@@ -298,12 +346,20 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
const referenceNode = xpath.select1("/root/name", doc);
-
- expect(
- // @ts-expect-error FIXME
- referenceNode.previousSibling.localName,
- "the signature should be inserted before to root/name",
- ).to.equal("Signature");
+ 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;
+ }
});
it("signer inserts signature after a reference node", function () {
@@ -323,11 +379,20 @@ describe("Signature unit tests", function () {
const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
const referenceNode = xpath.select1("/root/name", doc);
- expect(
- // @ts-expect-error FIXME
- referenceNode.nextSibling.localName,
- "the signature should be inserted after to root/name",
- ).to.equal("Signature");
+ 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;
+ }
});
it("signer creates signature with correct structure", function () {
@@ -342,6 +407,10 @@ describe("Signature unit tests", function () {
}
class DummySignatureAlgorithm {
+ verifySignature = function () {
+ return true;
+ };
+
getSignature = function () {
return "dummy signature";
};
@@ -352,6 +421,7 @@ describe("Signature unit tests", function () {
}
class DummyTransformation {
+ includeComments = false;
process = function () {
return "< x/>";
};
@@ -362,6 +432,7 @@ describe("Signature unit tests", function () {
}
class DummyCanonicalization {
+ includeComments = false;
process = function () {
return "< x/>";
};
@@ -374,12 +445,9 @@ describe("Signature unit tests", function () {
const xml = '';
const sig = new SignedXml();
- // @ts-expect-error FIXME
sig.CanonicalizationAlgorithms["http://DummyTransformation"] = DummyTransformation;
- // @ts-expect-error FIXME
sig.CanonicalizationAlgorithms["http://DummyCanonicalization"] = DummyCanonicalization;
sig.HashAlgorithms["http://dummyDigest"] = DummyDigest;
- // @ts-expect-error FIXME
sig.SignatureAlgorithms["http://dummySignatureAlgorithm"] = DummySignatureAlgorithm;
sig.signatureAlgorithm = "http://dummySignatureAlgorithm";
@@ -500,6 +568,10 @@ describe("Signature unit tests", function () {
}
class DummySignatureAlgorithm {
+ verifySignature = function () {
+ return true;
+ };
+
getSignature = function () {
return "dummy signature";
};
@@ -510,6 +582,7 @@ describe("Signature unit tests", function () {
}
class DummyTransformation {
+ includeComments = false;
process = function () {
return "< x/>";
};
@@ -520,6 +593,7 @@ describe("Signature unit tests", function () {
}
class DummyCanonicalization {
+ includeComments = false;
process = function () {
return "< x/>";
};
@@ -532,12 +606,9 @@ describe("Signature unit tests", function () {
const xml = '';
const sig = new SignedXml();
- // @ts-expect-error FIXME
sig.CanonicalizationAlgorithms["http://DummyTransformation"] = DummyTransformation;
- // @ts-expect-error FIXME
sig.CanonicalizationAlgorithms["http://DummyCanonicalization"] = DummyCanonicalization;
sig.HashAlgorithms["http://dummyDigest"] = DummyDigest;
- // @ts-expect-error FIXME
sig.SignatureAlgorithms["http://dummySignatureAlgorithm"] = DummySignatureAlgorithm;
sig.signatureAlgorithm = "http://dummySignatureAlgorithm";
@@ -650,8 +721,6 @@ describe("Signature unit tests", function () {
'';
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({ xpath: "//*[local-name(.)='x']" });
sig.addReference({ xpath: "//*[local-name(.)='y']" });
@@ -695,13 +764,19 @@ describe("Signature unit tests", function () {
it("signer creates correct signature values using async callback", function () {
class DummySignatureAlgorithm {
- getSignature = function (signedInfo, privateKey, callback) {
- const signer = crypto.createSign("RSA-SHA1");
- signer.update(signedInfo);
- const res = signer.sign(privateKey, "base64");
- //Do some asynchronous things here
- callback(null, res);
+ verifySignature = function () {
+ return true;
};
+
+ getSignature = createOptionalCallbackFunction(
+ (signedInfo: crypto.BinaryLike, privateKey: crypto.KeyLike) => {
+ const signer = crypto.createSign("RSA-SHA1");
+ signer.update(signedInfo);
+ const res = signer.sign(privateKey, "base64");
+ return res;
+ },
+ );
+
getAlgorithmName = function () {
return "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
};
@@ -710,12 +785,9 @@ describe("Signature unit tests", function () {
const xml =
'';
const sig = new SignedXml();
- // @ts-expect-error FIXME
sig.SignatureAlgorithms["http://dummySignatureAlgorithmAsync"] = DummySignatureAlgorithm;
sig.signatureAlgorithm = "http://dummySignatureAlgorithmAsync";
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({ xpath: "//*[local-name(.)='x']" });
sig.addReference({ xpath: "//*[local-name(.)='y']" });
@@ -759,7 +831,6 @@ describe("Signature unit tests", function () {
});
it("correctly loads signature", function () {
- // @ts-expect-error FIXME
passLoadSignature("./test/static/valid_signature.xml");
});
@@ -768,17 +839,14 @@ describe("Signature unit tests", function () {
});
it("correctly loads signature with root level sig namespace", function () {
- // @ts-expect-error FIXME
passLoadSignature("./test/static/valid_signature_with_root_level_sig_namespace.xml");
});
it("verifies valid signature", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature.xml");
});
it("verifies valid signature with lowercase id attribute", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature_with_lowercase_id_attribute.xml");
});
@@ -787,42 +855,34 @@ describe("Signature unit tests", function () {
});
it("verifies valid signature with reference keyInfo", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature_with_reference_keyInfo.xml");
});
it("verifies valid signature with whitespace in digestvalue", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature_with_whitespace_in_digestvalue.xml");
});
it("verifies valid utf8 signature", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature_utf8.xml");
});
it("verifies valid signature with unused prefixes", function () {
- // @ts-expect-error FIXME
passValidSignature("./test/static/valid_signature_with_unused_prefixes.xml");
});
it("fails invalid signature - signature value", function () {
- // @ts-expect-error FIXME
failInvalidSignature("./test/static/invalid_signature - signature value.xml");
});
it("fails invalid signature - hash", function () {
- // @ts-expect-error FIXME
failInvalidSignature("./test/static/invalid_signature - hash.xml");
});
it("fails invalid signature - non existing reference", function () {
- // @ts-expect-error FIXME
failInvalidSignature("./test/static/invalid_signature - non existing reference.xml");
});
it("fails invalid signature - changed content", function () {
- // @ts-expect-error FIXME
failInvalidSignature("./test/static/invalid_signature - changed content.xml");
});
@@ -855,8 +915,6 @@ describe("Signature unit tests", function () {
const xml = "";
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({
xpath: "//*[local-name(.)='root']",
@@ -872,8 +930,11 @@ 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);
- // @ts-expect-error FIXME
- expect(URI.value, `uri should be empty but instead was ${URI.value}`).to.equal("");
+ 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;
+ }
});
it("signer appends signature to a non-existing reference node", function () {
@@ -942,8 +1003,6 @@ describe("Signature unit tests", function () {
const xml = "";
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({
xpath: "//*[local-name(.)='root']",
@@ -962,8 +1021,10 @@ describe("Signature unit tests", function () {
"//*[local-name(.)='Reference']/*[local-name(.)='Transforms']/*[local-name(.)='Transform']/*[local-name(.)='InclusiveNamespaces']",
doc.documentElement,
);
- // @ts-expect-error FIXME
- expect(inclusiveNamespaces.length, "InclusiveNamespaces element should exist").to.equal(1);
+ expect(
+ utils.isArrayHasLength(inclusiveNamespaces) && inclusiveNamespaces.length,
+ "InclusiveNamespaces element should exist",
+ ).to.equal(1);
// @ts-expect-error FIXME
const prefixListAttribute = inclusiveNamespaces[0].getAttribute("PrefixList");
@@ -977,8 +1038,6 @@ describe("Signature unit tests", function () {
const xml = "";
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({
xpath: "//*[local-name(.)='root']",
@@ -993,21 +1052,18 @@ describe("Signature unit tests", function () {
const signedXml = sig.getSignedXml();
const doc = new xmldom.DOMParser().parseFromString(signedXml);
- const inclusiveNamespaces = xpath.select(
+ const inclusiveNamespaces = xpath.select1(
"//*[local-name(.)='Reference']/*[local-name(.)='Transforms']/*[local-name(.)='Transform']/*[local-name(.)='InclusiveNamespaces']",
doc.documentElement,
);
- // @ts-expect-error FIXME
- expect(inclusiveNamespaces.length, "InclusiveNamespaces element should not exist").to.equal(0);
+ expect(inclusiveNamespaces, "InclusiveNamespaces element should not exist").to.be.undefined;
});
it("creates InclusiveNamespaces element inside CanonicalizationMethod when inclusiveNamespacesPrefixList is set on SignedXml options", function () {
const xml = "";
const sig = new SignedXml({ inclusiveNamespacesPrefixList: "prefix1 prefix2" });
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({
xpath: "//*[local-name(.)='root']",
@@ -1025,8 +1081,7 @@ describe("Signature unit tests", function () {
);
expect(
- // @ts-expect-error FIXME
- inclusiveNamespaces.length,
+ utils.isArrayHasLength(inclusiveNamespaces) && inclusiveNamespaces.length,
"InclusiveNamespaces element should exist inside CanonicalizationMethod",
).to.equal(1);
@@ -1042,8 +1097,6 @@ describe("Signature unit tests", function () {
const xml = "";
const sig = new SignedXml(); // Omit inclusiveNamespacesPrefixList property
sig.privateKey = fs.readFileSync("./test/static/client.pem");
- // @ts-expect-error FIXME
- sig.publicCert = null;
sig.addReference({
xpath: "//*[local-name(.)='root']",
@@ -1055,16 +1108,15 @@ describe("Signature unit tests", function () {
const signedXml = sig.getSignedXml();
const doc = new xmldom.DOMParser().parseFromString(signedXml);
- const inclusiveNamespaces = xpath.select(
+ const inclusiveNamespaces = xpath.select1(
"//*[local-name(.)='CanonicalizationMethod']/*[local-name(.)='InclusiveNamespaces']",
doc.documentElement,
);
expect(
- // @ts-expect-error FIXME
- inclusiveNamespaces.length,
+ inclusiveNamespaces,
"InclusiveNamespaces element should not exist inside CanonicalizationMethod",
- ).to.equal(0);
+ ).to.be.undefined;
});
it("adds attributes to KeyInfo element when attrs are present in keyInfoProvider", function () {
@@ -1081,23 +1133,33 @@ describe("Signature unit tests", function () {
const signedXml = sig.getSignedXml();
const doc = new xmldom.DOMParser().parseFromString(signedXml);
- const keyInfoElement = xpath.select("//*[local-name(.)='KeyInfo']", doc.documentElement);
- // @ts-expect-error FIXME
- expect(keyInfoElement.length, "KeyInfo element should exist").to.equal(1);
+ const keyInfoElements = xpath.select("//*[local-name(.)='KeyInfo']", doc.documentElement);
// @ts-expect-error FIXME
- const algorithmAttribute = keyInfoElement[0].getAttribute("CustomUri");
- expect(
- algorithmAttribute,
- "KeyInfo element should have the correct CustomUri attribute value",
- ).to.equal("http://www.example.com/keyinfo");
-
- // @ts-expect-error FIXME
- const customAttribute = keyInfoElement[0].getAttribute("CustomAttribute");
- expect(
- customAttribute,
- "KeyInfo element should have the correct CustomAttribute attribute value",
- ).to.equal("custom-value");
+ 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;
+ }
});
it("adds all certificates and does not add private keys to KeyInfo element", function () {
@@ -1116,25 +1178,30 @@ describe("Signature unit tests", function () {
doc.documentElement,
);
// @ts-expect-error FIXME
- expect(x509certificates.length, "There should be exactly two certificates").to.equal(2);
+ if (xpath.isArrayOfNodes(x509certificates)) {
+ expect(x509certificates.length, "There should be exactly two certificates").to.equal(2);
- // @ts-expect-error FIXME
- const cert1 = x509certificates[0];
- // @ts-expect-error FIXME
- 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",
- );
+ 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;
+ }
});
});
diff --git a/test/static/valid_signature_with_root_level_sig_namespace.xml b/test/static/valid_signature_with_root_level_sig_namespace.xml
index 58c698ce..fc3fad07 100644
--- a/test/static/valid_signature_with_root_level_sig_namespace.xml
+++ b/test/static/valid_signature_with_root_level_sig_namespace.xml
@@ -1 +1 @@
-b5GCZ2xpP5T7tbLWBTkOl4CYupQ=K4dI497ZCxzweDIrbndUSmtoezY=sH1gxKve8wlU8LlFVa2l6w3HMJ0=PI2xGt3XrVcxYZ34Kw7nFdq75c7Mmo7J0q7yeDhBprHuJal/KV9KyKG+Zy3bmQIxNwkPh0KMP5r1YMTKlyifwbWK0JitRCSa0Fa6z6+TgJi193yiR5S1MQ+esoQT0RzyIOBl9/GuJmXx/1rXnqrTxmL7UxtqKuM29/eHwF0QDUI=1234
+b5GCZ2xpP5T7tbLWBTkOl4CYupQ=K4dI497ZCxzweDIrbndUSmtoezY=sH1gxKve8wlU8LlFVa2l6w3HMJ0=rR8+4xHiI8GQJ9Wty2TUbNI7Dd4uc89/BsAygYfeobEjmt4awzg6bQNA0nuQ+VggiPCYdKuKL8cPI7FUhk8osbVKdLPdy+rdJnibsyNpV87R7W5GZlFBEu/NqG6EYOMTHjpD4hq+H8ZeHC5YZDHPknPzJV8+A1UKN/BL2oWMQcg=1234
diff --git a/tsconfig.json b/tsconfig.json
index 03136e85..05f5ff27 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,9 +4,9 @@
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
- "target": "es2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+ "target": "es2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
- "lib": ["es2018"] /* Specify library files to be included in the compilation. */,
+ "lib": ["es2020"] /* Specify library files to be included in the compilation. */,
"allowJs": true /* Allow javascript files to be compiled. */,
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */