myinvois-sdk
Version:
TypeScript SDK for interacting with the Malaysia e-invoicing system (MyInvois) API
147 lines (146 loc) • 6.22 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DocumentSigner = void 0;
const crypto = __importStar(require("crypto"));
const signed_invoice_1 = require("../models/signed-invoice");
const signature_info_1 = require("../models/signature-info");
const signed_properties_1 = require("../models/signed-properties");
/**
* Handles document signing operations
*/
class DocumentSigner {
/**
* Creates a new document signer
* @param certificateHandler The certificate handler to use
*/
constructor(certificateHandler) {
this.certificateHandler = certificateHandler;
}
/**
* Signs an invoice
* @param invoice The invoice to sign
* @returns A signed invoice
*/
async signInvoice(invoice) {
// Make sure the certificate handler is initialized
await this.certificateHandler.initialize();
// Get the invoice JSON
const invoiceJson = invoice.toJSON();
// Transform the JSON for signing
const transformedJson = this.transformForSigning(invoiceJson);
// Generate the document hash
const documentHash = this.generateDocumentHash(transformedJson);
// Generate the signature
const signature = this.certificateHandler.signData(transformedJson);
// Create signed properties
const signedProperties = this.createSignedProperties();
// Generate the signed properties hash
const signedPropertiesHash = this.generateSignedPropertiesHash(signedProperties);
// Create the signature information
const signatureInfo = this.createSignatureInfo(signature, documentHash, signedProperties, signedPropertiesHash);
// Create and return the signed invoice
return new signed_invoice_1.SignedInvoice(invoice, signatureInfo);
}
/**
* Transforms the document for signing
* @param document The document to transform
* @returns The transformed document as a string
*/
transformForSigning(document) {
const transformedDoc = JSON.parse(JSON.stringify(document));
// Remove UBLExtensions and Signature from the invoice
if (transformedDoc.Invoice && transformedDoc.Invoice[0]) {
delete transformedDoc.Invoice[0].UBLExtensions;
delete transformedDoc.Invoice[0].Signature;
}
// Convert to string for hashing
return JSON.stringify(transformedDoc);
}
/**
* Generates a document hash
* @param document The document to hash
* @returns The document hash
*/
generateDocumentHash(document) {
return crypto.createHash('sha256').update(document).digest('base64');
}
/**
* Creates signed properties
* @returns The signed properties
*/
createSignedProperties() {
const certificateHash = this.certificateHandler.generateCertificateHash();
const signingCert = this.certificateHandler.getSigningCertificate();
const formattedIssuerName = this.certificateHandler.formatDistinguishedName(signingCert.issuer);
const formattedSerialNumber = this.certificateHandler.formatSerialNumber(signingCert.serialNumber);
const signedProperties = new signed_properties_1.SignedProperties();
signedProperties.certificateHash = certificateHash;
signedProperties.issuerName = formattedIssuerName;
signedProperties.serialNumber = formattedSerialNumber;
return signedProperties;
}
/**
* Generates a hash for the signed properties
* @param signedProperties The signed properties
* @returns The signed properties hash
*/
generateSignedPropertiesHash(signedProperties) {
const signedPropertiesString = JSON.stringify({
"Target": "signature",
"SignedProperties": signedProperties.toJSON()
});
return crypto.createHash('sha256').update(signedPropertiesString, 'utf8').digest('base64');
}
/**
* Creates signature information
* @param signature The signature
* @param documentHash The document hash
* @param signedProperties The signed properties
* @param signedPropertiesHash The signed properties hash
* @returns The signature information
*/
createSignatureInfo(signature, documentHash, signedProperties, signedPropertiesHash) {
const certInfo = this.certificateHandler.generateCertificateInfo();
const signatureInfo = new signature_info_1.SignatureInfo();
signatureInfo.signatureValue = signature;
signatureInfo.documentHash = documentHash;
signatureInfo.signedProperties = signedProperties;
signatureInfo.signedPropertiesHash = signedPropertiesHash;
signatureInfo.certificateInfo = certInfo;
return signatureInfo;
}
}
exports.DocumentSigner = DocumentSigner;