UNPKG

resedit-cli

Version:

Command-line tool for editing Windows Resource data in executable binaries

289 lines (288 loc) 11.1 kB
#!/usr/bin/env node import { createRequire } from 'module'; import run from './run.js'; import thisVersion from './version.js'; import { certificateSelectModeValues } from './definitions/DefinitionData.js'; import { getValidDigestAlgorithm } from './definitions/parser/sign.js'; const require = createRequire(import.meta.url); const loglevel = require('loglevel'); const yargsFactory = require('yargs'); const { hideBin } = require('yargs/helpers'); const thisName = 'resedit'; class CommandLineError extends Error { } async function main() { var _a; loglevel.setDefaultLevel('WARN'); try { const yargs = yargsFactory(hideBin(process.argv)); const argv = yargs .scriptName(thisName) .version(false) .locale('en') .usage(`Usage: ${thisName} [[--in] <in> | --new] [--out] <out> [<options...>]`) .option('allow-shrink', { description: 'Allow shrinking resource section size (if the data size is less than original)', type: 'boolean', nargs: 0, }) .option('as-32bit', { type: 'boolean', description: 'Creates the executable binary as a 32-bit version (default: as 64-bit).\nRequires --new option.', nargs: 0, }) .option('as-exe-file', { type: 'boolean', description: 'Creates the executable binary as an EXE file (default: as a DLL).\nRequires --new option.', nargs: 0, }) .option('certificate', { alias: ['cert'], description: 'Certificate file for signing.\n(DER format file (.cer) or PEM format file (.pem) is supported)\nRequires --sign option.', type: 'string', nargs: 1, }) .option('company-name', { description: 'Company name for version resource', type: 'string', nargs: 1, }) .option('debug', { type: 'boolean', description: 'Output more logs than verbose mode while processing.', nargs: 0, }) .option('definition', { description: 'Resource definition file which contains resource data to write (see document for details)', type: 'string', nargs: 1, }) .option('digest', { description: "Digest algorithm for signing. (default: 'sha256')\nRequires --sign option.", type: 'string', choices: getValidDigestAlgorithm(), nargs: 1, }) .option('file-description', { description: 'File description for version resource', type: 'string', nargs: 1, }) .option('file-version', { description: "File version for version resource.\nMust be 'n.n.n.n' format (n is an integer)", type: 'string', nargs: 1, }) .option('grow', { type: 'boolean', hidden: true, }) .option('help', { alias: ['h', '?'], type: 'boolean', description: 'Show help', }) .option('icon', { description: 'One or more icon files to add to executable.\nIcon ID can be specified with following format: <ID>,<file-name>', type: 'array', nargs: 1, }) .option('ignore-signed', { description: 'Force read input file even if it is a signed executable', type: 'boolean', }) .option('in', { alias: 'i', description: 'Input executable file name.\nCannot specify --new if an input file is specified.', type: 'string', nargs: 1, }) .option('internal-name', { description: 'Internal name for version resource', type: 'string', nargs: 1, }) .option('lang', { description: 'Resource language id (default: 1033)', type: 'number', nargs: 1, }) .option('new', { alias: ['n'], type: 'boolean', description: 'Create an empty (data-only) executable binary.\nCannot specify an input file if this option is used.', nargs: 0, }) .option('no-grow', { alias: ['N'], description: 'Disallow growing resource section size (throw errors if data exceeds)', type: 'boolean', nargs: 0, }) .option('original-filename', { description: 'Original file name for version resource', type: 'string', nargs: 1, }) .option('out', { alias: 'o', description: 'Output executable file name', type: 'string', nargs: 1, }) .option('p12', { alias: ['pfx'], description: 'PKCS 12 file (.p12 or .pfx file), which contains private key and certificates, for signing.\nRequires --sign option.', type: 'string', nargs: 1, }) .option('password', { description: 'Password/passphrase for private key. If an empty string password is required, specify \'\' (sh) or "" (cmd.exe).\nRequires --sign option.', type: 'string', nargs: 1, }) .option('private-key', { alias: ['key'], description: 'Private key file for signing. (only PEM format file (.pem) is supported)\nRequires --sign option.', type: 'string', nargs: 1, }) .option('product-name', { description: 'Product name for version resource', type: 'string', nargs: 1, }) .option('product-version', { description: "Product version for version resource.\nMust be 'n.n.n.n' format (n is an integer)", type: 'string', nargs: 1, }) .option('raw', { description: 'One or more resources to add to executable.\nThe value must be one of following format:\n* <type>,<ID>,<string-value>\n* <type>,<ID>,@<file-name>\n(<string-value> will be stored as UTF-8 string)', type: 'array', nargs: 1, }) .option('select', { type: 'string', description: 'Certificate selection mode whether to pick certificates from the specified file (default: leaf)\n' + "* leaf : only pick 'leaf' certificate\n" + '* no-root : pick certificates except for root certificate (i.e. issuer is equal to subject)\n' + '* all : no filter certificates (includes all certificates)', choices: certificateSelectModeValues, }) .option('sign', { alias: 's', type: 'boolean', description: 'Sign output executables', }) .option('timestamp', { description: 'Timestamp server to set timestamp for signed data.\nRequires --sign option.', type: 'string', nargs: 1, }) .option('verbose', { alias: 'v', type: 'boolean', description: 'Output logs while processing.', nargs: 0, }) .option('version', { alias: 'V', type: 'boolean', description: 'Show version number of this tool', nargs: 0, }) .command('$0', 'default command', (yargs) => { yargs.positional('in', {}).positional('out', {}); }) .check((argv, _opts) => { if (argv.version) { return true; } const restArgs = argv._; if (!argv.new && (argv.in == null || argv.in === '')) { const val = restArgs.splice(0, 1).shift(); const inVal = val !== undefined ? `${val}` : ''; if (inVal !== '') { argv.in = inVal; } } if (argv.out == null || argv.out === '') { const val = restArgs.splice(0, 1).shift(); argv.out = val !== undefined ? `${val}` : ''; } if (argv.in == null || argv.in === '') { if (!argv.new) { throw new CommandLineError('input file is missing.'); } argv.in = undefined; } else if (argv.new) { throw new CommandLineError('cannot specify both input file and --new.'); } if (argv.out === '') { throw new CommandLineError('output file is missing.'); } if (argv.new && argv.grow === false) { throw new CommandLineError('--no-grow cannot be used with --new'); } if (restArgs.length > 0) { throw new CommandLineError('Unknown arguments: ' + restArgs.join(', ')); } return true; }) .fail((msg, err, yargs) => { if (err !== null && err !== undefined) { if (err instanceof CommandLineError) { msg = err.message; } else if (typeof err === 'string') { msg = err; } else { throw err; } } msg = yargs.help().toString() + '\n\nERROR: ' + msg; throw new CommandLineError(msg); }).argv; if (argv.version) { console.log(`${thisName} version ${thisVersion}`); return 0; } if ('debug' in argv && argv.debug !== false) { loglevel.setLevel('DEBUG'); } else if ('verbose' in argv && argv.verbose !== false) { loglevel.setLevel('INFO'); } if (argv.noGrow === undefined && argv.grow !== undefined) { argv.noGrow = !argv.grow; } await run(argv); } catch (s) { if (s instanceof CommandLineError) { console.error(s.message); } else if (s instanceof Error) { console.error(`${thisName}:`, (_a = s.stack) !== null && _a !== void 0 ? _a : s.message); } else { let msg; if (typeof s !== 'string') { msg = String(s); } else { msg = s; } if (msg !== undefined) { console.error(msg); } } return 1; } return 0; } process.exit(await main());