UNPKG

ec-sri-invoice-signer

Version:
96 lines (95 loc) 4.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateXmlFeatures = exports.validateDocumentType = exports.parseXml = exports.buildXml = void 0; const fast_xml_parser_1 = require("fast-xml-parser"); const errors_1 = require("./errors"); const utils_1 = require("../canonicalization/utils"); const constants_1 = require("./constants"); const parseXml = (xml) => { const parserOptions = { commentPropName: '#comment', // need to include comments to keep the possible whitespace that is left when removing them. Otherwhise the library gets rid of it ignoreAttributes: false, ignoreDeclaration: true, parseTagValue: false, preserveOrder: true, trimValues: false, processEntities: false, ignorePiTags: true, attributeValueProcessor: (name, value) => { return (0, utils_1.processAttributeValue)(value); }, tagValueProcessor: (name, value) => { return (0, utils_1.processTagValue)(value); } }; try { const parser = new fast_xml_parser_1.XMLParser(parserOptions); return parser.parse(xml); } catch (err) { throw new errors_1.XmlFormatError(); } }; exports.parseXml = parseXml; const buildXml = (data) => { const builderOptions = { ignoreAttributes: false, preserveOrder: true, processEntities: false, suppressEmptyNode: false }; const builder = new fast_xml_parser_1.XMLBuilder(builderOptions); return builder.build(data); }; exports.buildXml = buildXml; const validateDocumentType = (xml) => { const parsed = parseXml(xml); if (!parsed || parsed.length === 0) { throw new errors_1.XmlFormatError(); } // Find the root element const rootElement = Object.keys(parsed[0]).find(key => key !== ':@' && key !== '#text' && !key.startsWith('#')); if (!rootElement) { throw new errors_1.XmlFormatError(); } if (!constants_1.SupportedDocumentTypes.has(rootElement)) { throw new errors_1.UnsupportedDocumentTypeError(rootElement); } }; exports.validateDocumentType = validateDocumentType; const validateXmlFeatures = (xml) => { // Check for DOCTYPE declarations if (xml.includes('<!DOCTYPE')) { throw new errors_1.UnsupportedXmlFeatureError('DOCTYPE declarations', 'DOCTYPE declarations are not supported. Remove any <!DOCTYPE> declarations from your XML.'); } // Check for xml-prefixed attributes const xmlAttributePattern = /\w+:\w+\s*=/g; const xmlAttributeMatches = xml.match(xmlAttributePattern); if (xmlAttributeMatches) { for (const match of xmlAttributeMatches) { if (match.startsWith('xml:')) { throw new errors_1.UnsupportedXmlFeatureError('xml-prefixed attributes', `Found attribute "${match}". Remove any xml: prefixed attributes from your XML.`); } } } // Check for namespace declarations (xmlns) if (xml.includes('xmlns:')) { throw new errors_1.UnsupportedXmlFeatureError('namespace declarations', 'Namespace declarations (xmlns:) are not supported in the document root. This library adds the necessary namespaces automatically during signing.'); } // Check for default xmlns declarations const defaultXmlnsPattern = /<\w+[^>]*\s+xmlns\s*=/; if (defaultXmlnsPattern.test(xml)) { throw new errors_1.UnsupportedXmlFeatureError('default namespace declarations', 'Default xmlns declarations are not supported. This library adds the necessary namespaces automatically during signing.'); } // Check for processing instructions other than XML declaration const processingInstructionPattern = /<\?[^?]*\?>/g; const matches = xml.match(processingInstructionPattern); if (matches) { for (const match of matches) { if (!match.startsWith('<?xml')) { throw new errors_1.UnsupportedXmlFeatureError('processing instructions', `Found processing instruction "${match}". Only XML declarations (<?xml ... ?>) are supported.`); } } } }; exports.validateXmlFeatures = validateXmlFeatures;