{"version":3,"file":"xml.js","sourceRoot":"","sources":["../../src/node-saml/xml.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,wCAAwC;AACxC,yCAAyC;AACzC,iCAAiC;AACjC,iCAAiC;AACjC,yCAAyC;AACzC,mCAAwE;AACxE,2CAA2C;AAI3C,MAAM,WAAW,GAAG,CAClB,KAAiD,EACjD,IAAU,EACV,KAAa,EACR,EAAE;IACP,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;KAC9C;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,MAAuB,EAAoB,EAAE;IAC7E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,IAAI,OAAO,KAAK,IAAI,QAAQ,EAAE;YAC5B,OAAO,KAAK,CAAC;SACd;QACD,OAAO,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,cAAc,CAAC;IACvF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,MAAuB,EAAuB,EAAE;IAC9E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,IAAI,OAAO,KAAK,IAAI,QAAQ,EAAE;YAC5B,OAAO,KAAK,CAAC;SACd;QACD,OAAO,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,YAAY,CAAC;IACrF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEW,QAAA,KAAK,GAAG;IACnB,gBAAgB,EAAE,CAAC,IAAU,EAAE,KAAa,EAAU,EAAE,CACtD,WAAW,CAAC,wBAAwB,EAAE,IAAI,EAAE,KAAK,CAAC;IACpD,cAAc,EAAE,CAAC,IAAU,EAAE,KAAa,EAAa,EAAE,CACvD,WAAW,CAAC,sBAAsB,EAAE,IAAI,EAAE,KAAK,CAAC;CACnD,CAAC;AAEK,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,aAA8B,EAAE,EAAE,CAC9E,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;AAD9D,QAAA,UAAU,cACoD;AAE3E,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,6DAA6D;IAC7D,oFAAoF;IACpF,+EAA+E;IAC/E,OAAO,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE;IAC3C,wDAAwD;IACxD,8HAA8H;IAC9H,OAAO,0BAAkB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5C,CAAC,CAAC;AAEF;;GAEG;AACI,MAAM,2BAA2B,GAAG,CACzC,SAAe,EACf,OAAe,EACf,OAAe,EACf,WAAoB,EACX,EAAE;IACX,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;IACtC,GAAG,CAAC,eAAe,GAAG;QACpB,IAAI,EAAE,EAAE;QACR,UAAU,EAAE,GAAG,EAAE,CAAC,uBAAuB;QACzC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;KACnC,CAAC;IACF,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7D,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAChC,2FAA2F;IAC3F,wDAAwD;IACxD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAI,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/D,0DAA0D;IAC1D,MAAM,WAAW,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACjE,IAAI,WAAW,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACjE,2FAA2F;IAC3F,+CAA+C;IAC/C,MAAM,oBAAoB,GAAG,aAAK,CAAC,cAAc,CAC/C,WAAW,CAAC,aAAa,EACzB,OAAO,GAAG,WAAW,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAC5C,CAAC;IAEF,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE;QACnC,OAAO,KAAK,CAAC;KACd;IACD,qFAAqF;IACrF,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC;AApCW,QAAA,2BAA2B,+BAoCtC;AAOK,MAAM,OAAO,GAAG,CACrB,GAAW,EACX,KAAa,EACb,QAA8B,EAC9B,OAA2B,EACnB,EAAE;;IACV,MAAM,iBAAiB,GAAG;QACxB,uDAAuD;QACvD,yCAAyC;KAC1C,CAAC;IAEF,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrD,IAAI,CAAC,iCAAyB,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAE3F,MAAM,UAAU,GAAG,MAAA,OAAO,CAAC,sBAAsB,mCAAI,iBAAiB,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE;QACtC,GAAG,CAAC,kBAAkB,GAAG,UAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACrF;IACD,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5F,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACpC,GAAG,CAAC,gBAAgB,CAAC,GAAG,EAAE;QACxB,QAAQ;KACT,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC;AAC5B,CAAC,CAAC;AA5BW,QAAA,OAAO,WA4BlB;AAEK,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAY,EAAE;IAC1D,OAAO,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC;AAFW,QAAA,kBAAkB,sBAE7B;AAEK,MAAM,qBAAqB,GAAG,KAAK,EAAE,GAAoB,EAAgB,EAAE;IAChF,MAAM,YAAY,GAAG;QACnB,YAAY,EAAE,IAAI;QAClB,eAAe,EAAE,IAAI;QACrB,iBAAiB,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC;KACnD,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC,CAAC;AARW,QAAA,qBAAqB,yBAQhC;AAEK,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAE,GAAQ,EAAU,EAAE;IACtE,MAAM,WAAW,GAAG;QAClB,QAAQ;QACR,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC,CAAC;AANW,QAAA,iBAAiB,qBAM5B;AAEK,MAAM,qBAAqB,GAAG,CAAC,GAAwB,EAAE,MAAe,EAAU,EAAE;IACzF,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC7C,CAAC,CAAC;AAHW,QAAA,qBAAqB,yBAGhC","sourcesContent":["import * as util from \"util\";\nimport * as xmlCrypto from \"xml-crypto\";\nimport * as xmlenc from \"xml-encryption\";\nimport * as xmldom from \"xmldom\";\nimport * as xml2js from \"xml2js\";\nimport * as xmlbuilder from \"xmlbuilder\";\nimport { isValidSamlSigningOptions, SamlSigningOptions } from \"./types\";\nimport * as algorithms from \"./algorithms\";\n\ntype SelectedValue = string | number | boolean | Node;\n\nconst selectXPath = (\n guard: (values: SelectedValue[]) => values is T[],\n node: Node,\n xpath: string\n): T[] => {\n const result = xmlCrypto.xpath(node, xpath);\n if (!guard(result)) {\n throw new Error(\"invalid xpath return type\");\n }\n return result;\n};\n\nconst attributesXPathTypeGuard = (values: SelectedValue[]): values is Attr[] => {\n return values.every((value) => {\n if (typeof value != \"object\") {\n return false;\n }\n return typeof value.nodeType === \"number\" && value.nodeType === value.ATTRIBUTE_NODE;\n });\n};\n\nconst elementsXPathTypeGuard = (values: SelectedValue[]): values is Element[] => {\n return values.every((value) => {\n if (typeof value != \"object\") {\n return false;\n }\n return typeof value.nodeType === \"number\" && value.nodeType === value.ELEMENT_NODE;\n });\n};\n\nexport const xpath = {\n selectAttributes: (node: Node, xpath: string): Attr[] =>\n selectXPath(attributesXPathTypeGuard, node, xpath),\n selectElements: (node: Node, xpath: string): Element[] =>\n selectXPath(elementsXPathTypeGuard, node, xpath),\n};\n\nexport const decryptXml = async (xml: string, decryptionKey: string | Buffer) =>\n util.promisify(xmlenc.decrypt).bind(xmlenc)(xml, { key: decryptionKey });\n\nconst normalizeNewlines = (xml: string): string => {\n // we can use this utility before passing XML to `xml-crypto`\n // we are considered the XML processor and are responsible for newline normalization\n // https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752\n return xml.replace(/\\r\\n?/g, \"\\n\");\n};\n\nconst normalizeXml = (xml: string): string => {\n // we can use this utility to parse and re-stringify XML\n // `DOMParser` will take care of normalization tasks, like replacing XML-encoded carriage returns with actual carriage returns\n return parseDomFromString(xml).toString();\n};\n\n/**\n * This function checks that the |signature| is signed with a given |cert|.\n */\nexport const validateXmlSignatureForCert = (\n signature: Node,\n certPem: string,\n fullXml: string,\n currentNode: Element\n): boolean => {\n const sig = new xmlCrypto.SignedXml();\n sig.keyInfoProvider = {\n file: \"\",\n getKeyInfo: () => \"\",\n getKey: () => Buffer.from(certPem),\n };\n const signatureStr = normalizeNewlines(signature.toString());\n sig.loadSignature(signatureStr);\n // We expect each signature to contain exactly one reference to the top level of the xml we\n // are validating, so if we see anything else, reject.\n if (sig.references.length != 1) return false;\n const refUri = sig.references[0].uri!;\n const refId = refUri[0] === \"#\" ? refUri.substring(1) : refUri;\n // If we can't find the reference at the top level, reject\n const idAttribute = currentNode.getAttribute(\"ID\") ? \"ID\" : \"Id\";\n if (currentNode.getAttribute(idAttribute) != refId) return false;\n // If we find any extra referenced nodes, reject. (xml-crypto only verifies one digest, so\n // multiple candidate references is bad news)\n const totalReferencedNodes = xpath.selectElements(\n currentNode.ownerDocument,\n \"//*[@\" + idAttribute + \"='\" + refId + \"']\"\n );\n\n if (totalReferencedNodes.length > 1) {\n return false;\n }\n // normalize XML to replace XML-encoded carriage returns with actual carriage returns\n fullXml = normalizeXml(fullXml);\n fullXml = normalizeNewlines(fullXml);\n return sig.checkSignature(fullXml);\n};\n\ninterface XmlSignatureLocation {\n reference: string;\n action: \"append\" | \"prepend\" | \"before\" | \"after\";\n}\n\nexport const signXml = (\n xml: string,\n xpath: string,\n location: XmlSignatureLocation,\n options: SamlSigningOptions\n): string => {\n const defaultTransforms = [\n \"http://www.w3.org/2000/09/xmldsig#enveloped-signature\",\n \"http://www.w3.org/2001/10/xml-exc-c14n#\",\n ];\n\n if (!xml) throw new Error(\"samlMessage is required\");\n if (!location) throw new Error(\"location is required\");\n if (!options) throw new Error(\"options is required\");\n if (!isValidSamlSigningOptions(options)) throw new Error(\"options.privateKey is required\");\n\n const transforms = options.xmlSignatureTransforms ?? defaultTransforms;\n const sig = new xmlCrypto.SignedXml();\n if (options.signatureAlgorithm != null) {\n sig.signatureAlgorithm = algorithms.getSigningAlgorithm(options.signatureAlgorithm);\n }\n sig.addReference(xpath, transforms, algorithms.getDigestAlgorithm(options.digestAlgorithm));\n sig.signingKey = options.privateKey;\n sig.computeSignature(xml, {\n location,\n });\n\n return sig.getSignedXml();\n};\n\nexport const parseDomFromString = (xml: string): Document => {\n return new xmldom.DOMParser().parseFromString(xml);\n};\n\nexport const parseXml2JsFromString = async (xml: string | Buffer): Promise => {\n const parserConfig = {\n explicitRoot: true,\n explicitCharkey: true,\n tagNameProcessors: [xml2js.processors.stripPrefix],\n };\n const parser = new xml2js.Parser(parserConfig);\n return parser.parseStringPromise(xml);\n};\n\nexport const buildXml2JsObject = (rootName: string, xml: any): string => {\n const builderOpts = {\n rootName,\n headless: true,\n };\n return new xml2js.Builder(builderOpts).buildObject(xml);\n};\n\nexport const buildXmlBuilderObject = (xml: Record, pretty: boolean): string => {\n const options = pretty ? { pretty: true, indent: \" \", newline: \"\\n\" } : {};\n return xmlbuilder.create(xml).end(options);\n};\n"]}