diff --git a/tools/keygen.mjs b/tools/keygen.mjs index 43481d3..4089fc0 100644 --- a/tools/keygen.mjs +++ b/tools/keygen.mjs @@ -1,5 +1,6 @@ // Mint PRO unlock keys for RecipesCam. Dev-side only — never bundled. // node tools/keygen.mjs 5 mint 5 keys +// node tools/keygen.mjs --from MYCHOSEN12 key for a payload you pick // node tools/keygen.mjs --check mint 3 keys and verify them (parity guard) // The key is 12 payload chars + 4 checksum chars, so any 12-char payload works. // Keep KEY_ALPHABET / KEY_SECRET / checksum identical to @@ -30,14 +31,27 @@ const keyIsValid = (raw) => { return true; }; -const mint = () => { - let payload = ''; - for (let i = 0; i < 12; i++) payload += KEY_ALPHABET[randomInt(KEY_ALPHABET.length)]; +const format = (s) => s.replace(/(.{4})/g, '$1-').slice(0, -1); + +const checkOf = (payload) => { const bits = checksum(payload); let check = ''; for (let i = 0; i < 4; i++) check += KEY_ALPHABET[(bits >>> (i * 5)) & 31]; - const s = payload + check; - return s.replace(/(.{4})/g, '$1-').slice(0, -1); + return check; +}; + +const mint = () => { + let payload = ''; + for (let i = 0; i < 12; i++) payload += KEY_ALPHABET[randomInt(KEY_ALPHABET.length)]; + return format(payload + checkOf(payload)); +}; + +// Mint the key for a payload you picked yourself — must be 12 chars, alphabet only. +const from = (payload) => { + const p = (payload || '').toUpperCase().replace(/[^A-Z0-9]/g, ''); + if (p.length !== 12) throw new Error(`payload must be 12 chars, got ${p.length}: ${p}`); + for (const ch of p) if (KEY_ALPHABET.indexOf(ch) < 0) throw new Error(`'${ch}' is not in ${KEY_ALPHABET}`); + return format(p + checkOf(p)); }; const args = process.argv.slice(2); @@ -50,6 +64,8 @@ if (args[0] === '--check') { } } console.log('ok', keys.join(' ')); +} else if (args[0] === '--from') { + console.log(from(args[1])); } else { const n = Number(args[0]) || 1; for (let i = 0; i < n; i++) console.log(mint());