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
JavaScript
;
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;