"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WSSecurityCert = void 0;
const uuid_1 = require("uuid");
const xml_crypto_1 = require("xml-crypto");
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes * 60000);
}
function dateStringForSOAP(date) {
return date.getUTCFullYear() + '-' + ('0' + (date.getUTCMonth() + 1)).slice(-2) + '-' +
('0' + date.getUTCDate()).slice(-2) + 'T' + ('0' + date.getUTCHours()).slice(-2) + ':' +
('0' + date.getUTCMinutes()).slice(-2) + ':' + ('0' + date.getUTCSeconds()).slice(-2) + 'Z';
}
function generateCreated() {
return dateStringForSOAP(new Date());
}
function generateExpires() {
return dateStringForSOAP(addMinutes(new Date(), 10));
}
function insertStr(src, dst, pos) {
return [dst.slice(0, pos), src, dst.slice(pos)].join('');
}
function generateId() {
return (0, uuid_1.v4)().replace(/-/gm, '');
}
function resolvePlaceholderInReferences(references, bodyXpath) {
for (const ref of references) {
if (ref.xpath === bodyXpathPlaceholder) {
ref.xpath = bodyXpath;
}
}
}
const oasisBaseUri = 'http://docs.oasis-open.org/wss/2004/01';
const bodyXpathPlaceholder = '[[bodyXpath]]';
class WSSecurityCert {
constructor(privatePEM, publicP12PEM, password, options = {}) {
this.signerOptions = {};
this.additionalReferences = [];
this.publicP12PEM = publicP12PEM.toString()
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '')
.replace(/(\r\n|\n|\r)/gm, '');
this.signer = new xml_crypto_1.SignedXml(options?.signerOptions?.idMode);
if (options.signatureAlgorithm === 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') {
this.signer.signatureAlgorithm = options.signatureAlgorithm;
this.signer.addReference(bodyXpathPlaceholder, ['http://www.w3.org/2001/10/xml-exc-c14n#'], 'http://www.w3.org/2001/04/xmlenc#sha256');
}
if (options.additionalReferences && options.additionalReferences.length > 0) {
this.additionalReferences = options.additionalReferences;
}
if (options.signerOptions) {
const { signerOptions } = options;
this.signerOptions = signerOptions;
if (!this.signerOptions.existingPrefixes) {
this.signerOptions.existingPrefixes = {};
}
if (this.signerOptions.existingPrefixes && !this.signerOptions.existingPrefixes.wsse) {
this.signerOptions.existingPrefixes.wsse = `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd`;
}
}
else {
this.signerOptions = { existingPrefixes: { wsse: `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd` } };
}
this.signer.signingKey = {
key: privatePEM,
passphrase: password,
};
this.x509Id = `x509-${generateId()}`;
this.hasTimeStamp = typeof options.hasTimeStamp === 'undefined' ? true : !!options.hasTimeStamp;
this.signatureTransformations = Array.isArray(options.signatureTransformations) ? options.signatureTransformations
: ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'];
this.signer.keyInfoProvider = {};
this.signer.keyInfoProvider.getKeyInfo = (key) => {
return `` +
`` +
``;
};
}
postProcess(xml, envelopeKey) {
this.created = generateCreated();
this.expires = generateExpires();
let timestampStr = '';
if (this.hasTimeStamp) {
timestampStr =
`` +
`${this.created}` +
`${this.expires}` +
``;
}
const binarySecurityToken = `${this.publicP12PEM}` +
timestampStr;
let xmlWithSec;
const secExt = `xmlns:wsse="${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd"`;
const secUtility = `xmlns:wsu="${oasisBaseUri}/oasis-200401-wss-wssecurity-utility-1.0.xsd"`;
const endOfSecurityHeader = xml.indexOf('');
if (endOfSecurityHeader > -1) {
const securityHeaderRegexp = /]*)?>/;
const match = xml.match(securityHeaderRegexp);
let insertHeaderAttributes = '';
if (!match[0].includes(` ${envelopeKey}:mustUnderstand="`)) {
insertHeaderAttributes += `${envelopeKey}:mustUnderstand="1" `;
}
if (!match[0].includes(secExt.substring(0, secExt.indexOf('=')))) {
insertHeaderAttributes += `${secExt} `;
}
if (!match[0].includes(secUtility.substring(0, secExt.indexOf('=')))) {
insertHeaderAttributes += `${secUtility} `;
}
const headerMarker = '` +
binarySecurityToken +
``;
xmlWithSec = insertStr(secHeader, xml, xml.indexOf(`${envelopeKey}:Header>`));
}
const references = this.signatureTransformations;
const bodyXpath = `//*[name(.)='${envelopeKey}:Body']`;
resolvePlaceholderInReferences(this.signer.references, bodyXpath);
if (!(this.signer.references.filter((ref) => (ref.xpath === bodyXpath)).length > 0)) {
this.signer.addReference(bodyXpath, references);
}
for (const name of this.additionalReferences) {
const xpath = `//*[name(.)='${name}']`;
if (!(this.signer.references.filter((ref) => (ref.xpath === xpath)).length > 0)) {
this.signer.addReference(xpath, references);
}
}
const timestampXpath = `//*[name(.)='wsse:Security']/*[local-name(.)='Timestamp']`;
if (this.hasTimeStamp && !(this.signer.references.filter((ref) => (ref.xpath === timestampXpath)).length > 0)) {
this.signer.addReference(timestampXpath, references);
}
this.signer.computeSignature(xmlWithSec, this.signerOptions);
const originalXmlWithIds = this.signer.getOriginalXmlWithIds();
const signatureXml = this.signer.getSignatureXml();
return insertStr(signatureXml, originalXmlWithIds, originalXmlWithIds.indexOf(''));
}
}
exports.WSSecurityCert = WSSecurityCert;
//# sourceMappingURL=WSSecurityCert.js.map