UNPKG

ura-prn

Version:

A TypeScript package to generate a PRN, generate access token, check PRN status and check TIN validity.

108 lines (107 loc) 3.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.URAPrn = exports.URAError = void 0; const tslib_1 = require("tslib"); const fs_1 = tslib_1.__importDefault(require("fs")); const path_1 = tslib_1.__importDefault(require("path")); const crypto_1 = tslib_1.__importDefault(require("crypto")); const node_forge_1 = tslib_1.__importDefault(require("node-forge")); /** * URA Error Codes and Descriptions */ exports.URAError = { CERTIFICATE_LOAD_ERROR: { code: 'ERROR001', message: 'Failed to load or parse the certificate file.', }, ENCRYPTION_FAILED: { code: 'ERROR002', message: 'Failed to encrypt the provided plaintext.', }, KEYSTORE_LOAD_ERROR: { code: 'ERROR003', message: 'Failed to load or parse the PFX keystore.', }, PRIVATE_KEY_NOT_FOUND: { code: 'ERROR004', message: 'Private key not found in keystore.', }, SIGNATURE_FAILED: { code: 'ERROR005', message: 'Failed to generate digital signature.', }, }; class URAPrnError extends Error { constructor(code, extra) { super(`${exports.URAError[code].message}${extra ? ' - ' + extra : ''}`); this.code = exports.URAError[code].code; this.name = 'URAPrnError'; } } /** * Main URAPrn utility class */ class URAPrn { constructor(config) { this.certPath = config.certPath; this.pfxPath = config.pfxPath; this.keystorePassword = config.keystorePassword; this.alias = config.alias; } encrypt(plainText) { try { const certPem = fs_1.default.readFileSync(path_1.default.resolve(this.certPath), 'utf8'); const cert = node_forge_1.default.pki.certificateFromPem(certPem); const publicKeyPem = node_forge_1.default.pki.publicKeyToPem(cert.publicKey); const encryptedBuffer = crypto_1.default.publicEncrypt({ key: publicKeyPem, padding: crypto_1.default.constants.RSA_PKCS1_PADDING, }, Buffer.from(plainText, 'utf8')); return encryptedBuffer.toString('base64'); } catch (err) { throw new URAPrnError('ENCRYPTION_FAILED', err.message); } } generateSignature(textToSign) { try { const pfxBuffer = fs_1.default.readFileSync(path_1.default.resolve(this.pfxPath)); let p12Asn1; try { p12Asn1 = node_forge_1.default.asn1.fromDer(pfxBuffer.toString('binary'), false); } catch (e) { throw new URAPrnError('KEYSTORE_LOAD_ERROR', e.message); } const p12 = node_forge_1.default.pkcs12.pkcs12FromAsn1(p12Asn1, this.keystorePassword); let privateKey = null; p12.safeContents.forEach((content) => { content.safeBags.forEach((bag) => { if (bag.type === node_forge_1.default.pki.oids.pkcs8ShroudedKeyBag && bag.key && (!this.alias || bag.attributes.friendlyName?.[0] === this.alias)) { privateKey = bag.key; } }); }); if (!privateKey) { throw new URAPrnError('PRIVATE_KEY_NOT_FOUND'); } const md = node_forge_1.default.md.sha1.create(); md.update(textToSign, 'utf8'); const signature = privateKey.sign(md); return Buffer.from(signature, 'binary').toString('base64'); } catch (err) { if (err instanceof URAPrnError) throw err; throw new URAPrnError('SIGNATURE_FAILED', err.message); } } encryptAndSign(plainText) { const encryption = this.encrypt(plainText); const signature = this.generateSignature(encryption); return { encryption, signature }; } } exports.URAPrn = URAPrn;