UNPKG

@ianacaburian/generate-key-file

Version:

Ports juce_KeyGeneration::generateKeyFile() to node.

287 lines (280 loc) 8.82 kB
// src/juce/JuceKeyFileUtils.ts import { XMLBuilder } from "fast-xml-parser"; // src/juce/JuceBigInteger.ts import { BigInteger as JSBN } from "jsbn"; var JuceBigInteger = class _JuceBigInteger { constructor(value = 0n) { this.value = value; } static fromJSBN(b) { return _JuceBigInteger.fromHex(b.toString(16)); } toJSBN() { return new JSBN(this.toHex(), 16); } static fromHex(hex) { const h = hex.trim(); return new _JuceBigInteger(h ? BigInt(`0x${h}`) : 0n); } toHex() { return this.value.toString(16); } static fromUTF8MemoryBlock(input) { const u = Buffer.from(input, "utf8"); const b = new _JuceBigInteger(); for (let i = u.length - 1; i >= 0; i--) { b.value = b.value << 8n | BigInt(u[i]); } return b; } isZero() { return this.value === 0n; } divideBy(divisor, remainder) { if (divisor.isZero()) { this.value = 0n; return; } const b = this.toJSBN(); const d = divisor.toJSBN(); const [q, r] = b.divideAndRemainder(d); this.value = _JuceBigInteger.fromJSBN(q).value; remainder.value = _JuceBigInteger.fromJSBN(r).value; } exponentModulo(exponent, modulus) { const b = this.toJSBN(); const e = exponent.toJSBN(); const m = modulus.toJSBN(); const em = b.modPow(e, m); this.value = _JuceBigInteger.fromJSBN(em).value; } }; // src/juce/JuceKeyFileUtils.ts var XML_DECLARATION = '<?xml version="1.0" encoding="UTF-8"?>'; var legalXmlCharRegex = ( // Ports juce::XmlOutputFunctions::LegalCharLookupTable /^[a-zA-Z0-9 .,;:\-()_+=?!$#@[\]/|*%~{}'\\]$/ ); var xmlAttributeCharProcessor = (char) => ( // Ports juce::XmlOutputFunctions::escapeIllegalXMLChars() char.length !== 1 ? "" : legalXmlCharRegex.test(char) ? char : char === "&" ? "&amp;" : char === '"' ? "&quot;" : char === ">" ? "&gt;" : char === "<" ? "&lt;" : `&#${char.charCodeAt(0)};` ); var xmlAttributeValueProcessor = (value) => ( // Ports juce::XmlOutputFunctions::escapeIllegalXMLChars() typeof value !== "string" ? "" : value.split("").map(xmlAttributeCharProcessor).join("") ); var xmlBuilder = new XMLBuilder({ ignoreAttributes: false, suppressEmptyNode: true, // processEntities is disabled since it doesn't port to juce as is processEntities: false, attributeValueProcessor: (_, value) => xmlAttributeValueProcessor(value) }); var JuceKeyFileUtils = class { static toString(date) { const months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; const day = date.getDate().toString(); const month = months[date.getMonth()]; const year = date.getFullYear(); let hours = date.getHours(); const minutes = date.getMinutes().toString().padStart(2, "0"); const seconds = date.getSeconds().toString().padStart(2, "0"); const ampm = hours >= 12 ? "pm" : "am"; hours = hours % 12; hours = hours ? hours : 12; return `${day} ${month} ${year} ${hours}:${minutes}:${seconds}${ampm}`; } static toHexStringMilliseconds(date) { return date.getTime().toString(16); } static createKeyFileContentLine({ appName, userEmail, userName, machineNumbers, machineNumbersAttributeName }, date, expiryTime) { const xml = { key: { "@_user": userName, "@_email": userEmail, [`@_${machineNumbersAttributeName}`]: machineNumbers, "@_app": appName, "@_date": date, ...expiryTime ? { "@_expiryTime": expiryTime } : {} } }; return [XML_DECLARATION, xmlBuilder.build(xml).trim()].join(" "); } static createKeyFileComment({ appName, userEmail, userName, machineNumbers }, created, expiryTime) { return `Keyfile for ${appName}\r ${userName ? `User: ${userName}\r ` : ""}Email: ${userEmail}\r Machine numbers: ${machineNumbers}\r Created: ${created}` + (expiryTime ? `\r Expires: ${expiryTime}` : ""); } static encryptXMLLine(xmlLine, privateKey) { const val = JuceBigInteger.fromUTF8MemoryBlock(xmlLine); privateKey.applyToValue(val); return val.toHex(); } static createKeyFile(comment, xmlLine, rsaPrivateKey) { let asHex = "#" + this.encryptXMLLine(xmlLine, rsaPrivateKey); const lines = []; lines.push(comment); lines.push(""); const charsPerLine = 70; while (asHex.length > 0) { lines.push(asHex.substring(0, charsPerLine)); asHex = asHex.substring(charsPerLine); } lines.push(""); return lines.join("\r\n"); } }; // src/juce/JuceRSAKey.ts var JuceRSAKey = class { constructor(s) { this.s = s; if (s.includes(",")) { const [p1, p2] = s.split(",").map((p) => JuceBigInteger.fromHex(p)); this.part1 = p1; this.part2 = p2; } else { this.part1 = new JuceBigInteger(); this.part2 = new JuceBigInteger(); } } applyToValue(val) { if (this.part1.isZero() || this.part2.isZero() || val.value <= 0n) { return; } const result = new JuceBigInteger(); while (!val.isZero()) { result.value *= this.part2.value; const remainder = new JuceBigInteger(); val.divideBy(this.part2, remainder); remainder.exponentModulo(this.part1, this.part2); result.value += remainder.value; } val.value = result.value; } }; // src/juce/JuceKeyGeneration.ts var JuceKeyGeneration = class { static generateKeyFile(params, date = /* @__PURE__ */ new Date()) { const xml = JuceKeyFileUtils.createKeyFileContentLine( { appName: params.appName, userEmail: params.userEmail, userName: params.userName, machineNumbers: params.machineNumbers, machineNumbersAttributeName: "mach" }, JuceKeyFileUtils.toHexStringMilliseconds(date) ); const comment = JuceKeyFileUtils.createKeyFileComment( { appName: params.appName, userEmail: params.userEmail, userName: params.userName, machineNumbers: params.machineNumbers }, JuceKeyFileUtils.toString(date) ); return JuceKeyFileUtils.createKeyFile( comment, xml, new JuceRSAKey(params.privateKey) ); } static generateExpiringKeyFile(params, date = /* @__PURE__ */ new Date()) { const xml = JuceKeyFileUtils.createKeyFileContentLine( { appName: params.appName, userEmail: params.userEmail, userName: params.userName, machineNumbers: params.machineNumbers, machineNumbersAttributeName: "expiring_mach" }, JuceKeyFileUtils.toHexStringMilliseconds(date), JuceKeyFileUtils.toHexStringMilliseconds(params.expiryTime) ); const comment = JuceKeyFileUtils.createKeyFileComment( { appName: params.appName, userEmail: params.userEmail, userName: params.userName, machineNumbers: params.machineNumbers }, JuceKeyFileUtils.toString(date), JuceKeyFileUtils.toString(params.expiryTime) ); return JuceKeyFileUtils.createKeyFile( comment, xml, new JuceRSAKey(params.privateKey) ); } }; // src/types.ts import { z } from "zod"; var createKeyFileCommentParamsValidator = z.object({ appName: z.string().min(1), userEmail: z.string().min(1).email(), userName: z.string().min(1), machineNumbers: z.string().min(1) }); var machineNumbersAttributeNameValidator = z.enum([ "mach", "expiring_mach" ]); var createKeyFileContentLineParamsValidator = createKeyFileCommentParamsValidator.extend({ machineNumbersAttributeName: machineNumbersAttributeNameValidator }); var rsaKeyComponentsValidator = z.string().refine( // Ports juce::RSAKey::RSAKey() and juce::RSAKey::applyToValue() (x) => x.includes(",") && x.split(",").every((p) => !JuceBigInteger.fromHex(p).isZero()) ); var generateKeyFileParamsValidator = createKeyFileCommentParamsValidator.extend({ privateKey: rsaKeyComponentsValidator }); var generateExpiringKeyFileParamsValidator = generateKeyFileParamsValidator.extend({ expiryTime: z.date().min(/* @__PURE__ */ new Date("1970-01-01T00:00:00.001Z"), { message: "Expiry time must be after 1970-01-01T00:00:00.000Z" }) }); // src/generateKeyFile.ts var generateKeyFile = (params, date = /* @__PURE__ */ new Date()) => { const paramsParse = generateKeyFileParamsValidator.parse(params); return JuceKeyGeneration.generateKeyFile(paramsParse, date); }; // src/generateExpiringKeyFile.ts var generateExpiringKeyFile = (params, date = /* @__PURE__ */ new Date()) => { const paramsParse = generateExpiringKeyFileParamsValidator.parse(params); return JuceKeyGeneration.generateExpiringKeyFile(paramsParse, date); }; export { generateExpiringKeyFile, generateKeyFile }; //# sourceMappingURL=index.js.map