app.js

#!/usr/bin/env node
'use strict';

/**
 * @fileoverview CLI tool for managing Bitcoin Mini private keys.
 * 
 * This tool provides the following functionalities:
 * - **Validation**: Check if a given MiniKey is valid.
 * - **Generation**: Generate new 30-character MiniKeys.
 * - **Conversion**:
 *   - MiniKey → HEX private key.
 *   - HEX private key → Wallet Import Format (WIF).
 * - **Verification**: Confirm that a WIF key matches its original MiniKey.
 * - **Full Workflow**: Validate MiniKeys, convert to HEX, and generate WIF keys.
 * 
 * @module app
 * @requires commander
 * @requires @core/logger
 * @requires @classes/MiniKeyConverter
 * @requires @core/output
 * @requires config/config.json
 */

// Try to register module aliases dynamically
try {
  require('../core/setupAliases');
} catch (error) {
  console.warn('Module aliases are not registered. Ensure the runtime supports _moduleAliases.');
}

const { program } = require('commander'); // CLI framework for argument parsing
const logger = require('@core/logger'); // Custom logger for logging output
const MiniKeyConverter = require('@classes/MiniKeyConverter'); // Main converter class
const { printResult } = require('@core/output'); // Helper for user-facing results

// Read configuration
const config = require('../config/config.json');

/**
 * Set default log level from configuration file or fallback to 'info'.
 * @constant {string} LOG_LEVEL - The default logging level.
 */
process.env.LOG_LEVEL = config.logLevel || 'info';

/**
 * Instance of the MiniKeyConverter class.
 * @type {MiniKeyConverter}
 */
const Converter = new MiniKeyConverter();

/**
 * Adjust logging levels dynamically based on CLI options.
 * @name LoggingLevelOptions
 * @function
 */
program
  .option('-v, --verbose', 'Enable verbose debug logging')
  .option('-q, --quiet', 'Suppress all non-critical logs')
  .hook('preAction', (thisCommand) => {
    const opts = thisCommand.opts();

    // Set global LOG_LEVEL based on options
    if (opts.verbose) {
      process.env.LOG_LEVEL = 'debug';
    } else if (opts.quiet) {
      process.env.LOG_LEVEL = 'error';
    }

    // Update Winston logger level dynamically
    logger.transports[0].level = process.env.LOG_LEVEL;
  });

/**
 * Define the CLI program.
 */
program
  .name('minikey-converter')
  .description('A tool to manage and convert Bitcoin Mini private keys')
  .version('1.0.0');

/**
 * Command: Generate a new MiniKey and convert it to HEX and WIF formats.
 * @name generate
 * @function
 */
program
  .command('generate')
  .description('Generate a new 30-character MiniKey and convert it to HEX and WIF formats')
  .action(() => {
    try {
      const minikey = Converter.generateMiniKey();
      printResult(`🆕 Generated MiniKey: ${minikey}`);

      const hexKey = Converter.miniToHex(minikey);
      printResult(`🔑 HEX Private Key: ${hexKey}`);

      const mainnetWifUncompressed = Converter.hexToWif(hexKey, false, false);
      const mainnetWifCompressed = Converter.hexToWif(hexKey, false, true);
      const testnetWifUncompressed = Converter.hexToWif(hexKey, true, false);
      const testnetWifCompressed = Converter.hexToWif(hexKey, true, true);

      printResult('✅ WIF Keys Generated:');
      printResult(`  Mainnet (Uncompressed): ${mainnetWifUncompressed}`);
      printResult(`  Mainnet (Compressed):   ${mainnetWifCompressed}`);
      printResult(`  Testnet (Uncompressed): ${testnetWifUncompressed}`);
      printResult(`  Testnet (Compressed):   ${testnetWifCompressed}`);
    } catch (error) {
      logger.error(`❌ Error generating MiniKey: ${error.message}`);
    }
  });

/**
 * Command: Process a MiniKey through the full workflow.
 * @name process
 * @function
 * @param {string} minikey - The Mini private key to process.
 */
program
  .command('process <minikey>')
  .description('Validate a MiniKey and convert it to both HEX and WIF keys')
  .action((minikey) => {
    printResult('Starting the full MiniKey workflow...');

    // Step 1: Validate the MiniKey
    if (!Converter.check(minikey)) {
      logger.error('❌ Invalid MiniKey format. Exiting workflow.');
      return;
    }
    printResult(`✅ Valid MiniKey: ${minikey}`);

    // Step 2: Convert MiniKey to HEX
    const hexKey = Converter.miniToHex(minikey);
    printResult(`🔑 HEX Private Key: ${hexKey}`);

    // Step 3: Convert HEX to WIF (mainnet and testnet, compressed and uncompressed)
    const mainnetWifUncompressed = Converter.hexToWif(hexKey, false, false);
    const mainnetWifCompressed = Converter.hexToWif(hexKey, false, true);
    const testnetWifUncompressed = Converter.hexToWif(hexKey, true, false);
    const testnetWifCompressed = Converter.hexToWif(hexKey, true, true);

    printResult('✅ WIF Keys Generated:');
    printResult(`  Mainnet (Uncompressed): ${mainnetWifUncompressed}`);
    printResult(`  Mainnet (Compressed):   ${mainnetWifCompressed}`);
    printResult(`  Testnet (Uncompressed): ${testnetWifUncompressed}`);
    printResult(`  Testnet (Compressed):   ${testnetWifCompressed}`);
  });

/**
 * Command: Validate a MiniKey.
 * @name validate
 * @function
 * @param {string} minikey - The Mini private key to validate.
 */
program
  .command('validate <minikey>')
  .description('Validate a Bitcoin Mini private key')
  .action((minikey) => {
    if (Converter.check(minikey)) {
      printResult(`✅ Valid MiniKey: ${minikey}`);
    } else {
      logger.warn(`❌ Invalid MiniKey: ${minikey}`);
    }
  });

/**
 * Command: Convert a MiniKey to HEX.
 * @name to-hex
 * @function
 * @param {string} minikey - The Mini private key to convert.
 */
program
  .command('to-hex <minikey>')
  .description('Convert a MiniKey to a HEX private key')
  .action((minikey) => {
    if (Converter.check(minikey)) {
      const hexKey = Converter.miniToHex(minikey);
      printResult(`HEX Private Key: ${hexKey}`);
    } else {
      logger.error('Invalid MiniKey. Cannot convert.');
    }
  });

/**
 * Command: Convert HEX to WIF.
 * @name to-wif
 * @function
 * @param {string} hexkey - The HEX private key to convert.
 * @param {boolean} [testnet=false] - Generate a testnet WIF key.
 * @param {boolean} [compressed=false] - Generate a compressed WIF key.
 */
program
  .command('to-wif <hexkey>')
  .option('-t, --testnet', 'Generate a WIF key for testnet')
  .option('-c, --compressed', 'Generate a compressed WIF key')
  .description('Convert a HEX private key to WIF format')
  .action((hexkey, options) => {
    try {
      const wifKey = Converter.hexToWif(
        hexkey,
        options.testnet || false,
        options.compressed || false
      );
      printResult(`WIF Key: ${wifKey}`);
    } catch (error) {
      logger.error(`Error: ${error.message}`);
    }
  });

/**
 * Command: Verify if a WIF matches a MiniKey.
 * @name verify
 * @function
 * @param {string} minikey - The Mini private key.
 * @param {string} wifkey - The Wallet Import Format key.
 */
program
  .command('verify <minikey> <wifkey>')
  .description('Verify if the given WIF key matches the MiniKey')
  .action((miniKey, wifKey) => {
    try {
      const isValid = Converter.verifyWifAgainstMiniKey(miniKey, wifKey);
      if (isValid) {
        printResult('✅ The WIF key matches the MiniKey');
      } else {
        logger.error('❌ The WIF key does not match the MiniKey');
      }
    } catch (error) {
      logger.error(`❌ Error verifying WIF and MiniKey: ${error.message}`);
    }
  });

// Parse CLI arguments
program.parse(process.argv);