UNPKG

libas2

Version:

Implementation of the AS2 protocol as presented in RFC 4130 and related RFCs

122 lines (121 loc) 6.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AS2Composer = void 0; const AS2MimeNode_1 = require("../AS2MimeNode"); const Helpers_1 = require("../Helpers"); const Constants_1 = require("../Constants"); const { STANDARD_HEADER, AS2_VERSION } = Constants_1.AS2Constants; /** Options for composing an AS2 message. * @typedef {object} AS2ComposerOptions * @property {AS2MimeNodeOptions} message * @property {AgreementOptions} agreement */ /** Options for composing an AS2 message. * @typedef {object} AgreementOptions * @property {object} host - Options for the AS2 host. * @property {string} host.name - The name of the host. * @property {string} host.id - The id of the host; usually a company's DUNS id. * @property {string|URL} host.url - The URL of the host's AS2 endpoint. * @property {string|Buffer|PemFile} [host.certificate] - The certificate of the host in PEM format. Required for signing or decrypting. * @property {string|Buffer|PemFile} [host.privateKey] - The private key of the host in PEM format. Required for signing or decrypting. * @property {boolean} host.decrypt - Host requires partner to encrypt messages sent to the host. * @property {AS2Signing|boolean} host.sign - Host requires partner to verify messages sent from the host. * @property {object} [host.mdn] - Host requests a message disposition notification (MDN). * @property {boolean} host.mdn.async - Host requires MDN to be sent to a separate URL. * @property {AS2Signing|false} host.mdn.signing - Host requires MDN to be signed with algorithm if possible. * @property {object} partner - Options for the AS2 partner. * @property {string} partner.name - The name of the partner. * @property {string} partner.id - The id of the partner; usually a company's DUNS id. * @property {string|URL} partner.url - The URL of the partner's AS2 endpoint. * @property {'EDIX12'|'EDIFACT'|'XML'|string} partner.file - The file protocol for trading with the partner. * @property {string|Buffer|PemFile} [partner.certificate] - The certificate of the partner in PEM format. Required for signing or decrypting. * @property {AS2Encryption|boolean} partner.encrypt - Partner requires host to encrypt messages sent to the partner. * @property {boolean} partner.verify - Partner requires host to verify messages sent from the partner. * @property {object} [partner.mdn] - Partner may request a message disposition notification (MDN). * @property {boolean} partner.mdn.async - Partner requires MDN to be sent to a separate URL. * @property {AS2Signing|false} partner.mdn.signing - Partner requires MDN to be signed with algorithm if possible. */ /** Class for composing AS2 messages. * @param {AS2ComposerOptions} options - The options for composing AS2 messages. */ class AS2Composer { constructor(options) { this._message = Object.assign({}, options.message); this._headers = []; this.setAgreement(options.agreement); if (Array.isArray(options.additionalHeaders)) { this._headers.push(...options.additionalHeaders); } else { for (const [key, value] of Object.entries(options.additionalHeaders || {})) { this._headers.push({ key, value }); } } } /** Set the agreement for this composer instance. * @param {AgreementOptions} agreement */ setAgreement(agreement) { this._agreement = Helpers_1.getAgreementOptions(agreement); } /** Compile the composed message into an instance of AS2MimeNode. * @returns {Promise<AS2MimeNode>} This composer instance as an AS2MimeNode. */ async compile() { this.message = new AS2MimeNode_1.AS2MimeNode(Object.assign({}, this._message)); if (this._agreement.host.sign) { this.message.setSigning({ cert: this._agreement.host.certificate, key: this._agreement.host.privateKey, algorithm: this._agreement.host.sign }); this.message = await this.message.sign(); } if (this._agreement.partner.encrypt) { this.message.setEncryption({ cert: this._agreement.partner.certificate, encryption: this._agreement.partner.encrypt }); this.message = await this.message.encrypt(); } // Set AS2 headers. this.message.setHeader([ { key: STANDARD_HEADER.FROM, value: this._agreement.host.id }, { key: STANDARD_HEADER.TO, value: this._agreement.partner.id }, { key: STANDARD_HEADER.VERSION, value: AS2_VERSION } ]); this.message.messageId(true); // Set MDN headers. if (this._agreement.host.mdn) { const mdn = this._agreement.host.mdn; let options = 'signed-receipt-protocol=optional,pkcs7-signature; signed-receipt-micalg=optional,sha-256'; if (mdn.signing) { options = `signed-receipt-protocol=required,pkcs7-signature; signed-receipt-micalg=required,${mdn.signing.toLowerCase()}`; } this.message.setHeader(STANDARD_HEADER.MDN_TO, this._agreement.host.id); this.message.setHeader(STANDARD_HEADER.MDN_OPTIONS, options); if (mdn.async) { this.message.setHeader(STANDARD_HEADER.MDN_URL, this._agreement.host.url.toString()); } } this.message.setHeader(this._headers); return this.message; } /** Create a Node.js-compatible RequestOptions object from the composed message. * @param {string} [url] - Optional: The URL of the AS2 endpoint receiving this AS2 message; will use agreement partner url if not provided. * @returns {Promise<RequestOptions>} This composer instance as request options for Node.js. */ async toRequestOptions(url) { if (this.message === undefined) { await this.compile(); } const { headers, body } = await this.message.buildObject(); return { url: url || this._agreement.partner.url, headers, body, method: 'POST' }; } } exports.AS2Composer = AS2Composer;