beeline-cli
Version:
A terminal wallet for the Hive blockchain - type, sign, rule the chain
229 lines โข 12.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const neon_js_1 = require("../utils/neon.js");
const crypto_js_1 = require("../utils/crypto.js");
const hive_js_1 = require("../utils/hive.js");
const inquirer_1 = __importDefault(require("inquirer"));
class Login extends core_1.Command {
async run() {
const { args, flags } = await this.parse(Login);
let account = args.account;
// Clean @ prefix if provided
if (account.startsWith('@')) {
account = account.substring(1);
}
const keyManager = new crypto_js_1.KeyManager();
await keyManager.initialize();
// Check if this is the first time using beeline
const existingAccounts = await keyManager.listAccounts();
const isFirstTime = existingAccounts.length === 0;
if (isFirstTime) {
await this.showWelcomeSequence();
}
console.log(neon_js_1.neonChalk.glow(`${neon_js_1.neonSymbols.diamond} Initiating secure login for ${neon_js_1.neonChalk.highlight('@' + account)}...`));
console.log('');
// Check if account already exists
const hasAccount = await keyManager.hasAccount(account);
if (hasAccount && !flags.force) {
const confirmPrompt = await inquirer_1.default.prompt([{
type: 'confirm',
name: 'confirm',
message: neon_js_1.neonChalk.warning(`Account @${account} already exists in vault. Overwrite keys?`),
default: false
}]);
if (!confirmPrompt.confirm) {
console.log(neon_js_1.neonChalk.info('Login cancelled'));
return;
}
}
// Parse roles
const requestedRoles = flags.roles.split(',').map(r => r.trim());
const validRoles = ['owner', 'active', 'posting', 'memo'];
const roles = requestedRoles.filter(role => validRoles.includes(role));
if (roles.length === 0) {
console.log(neon_js_1.neonChalk.error(`${neon_js_1.neonSymbols.cross} Invalid roles specified. Valid roles: owner, active, posting, memo`));
return;
}
// Verify account exists on blockchain
if (flags.verify) {
const verifySpinner = (0, neon_js_1.neonSpinner)('Verifying account on Hive blockchain');
try {
const hiveClient = new hive_js_1.HiveClient(keyManager);
const accountData = await hiveClient.getAccount(account);
clearInterval(verifySpinner);
process.stdout.write('\r' + ' '.repeat(80) + '\r');
if (!accountData) {
console.log(neon_js_1.neonChalk.error(`${neon_js_1.neonSymbols.cross} Account @${account} not found on Hive blockchain`));
console.log(neon_js_1.neonChalk.info('Use --no-verify to skip this check'));
return;
}
console.log(neon_js_1.neonChalk.success(`${neon_js_1.neonSymbols.check} Account verified on blockchain`));
console.log('');
}
catch (error) {
clearInterval(verifySpinner);
process.stdout.write('\r' + ' '.repeat(80) + '\r');
console.log(neon_js_1.neonChalk.warning(`${neon_js_1.neonSymbols.warning} Could not verify account: ${error instanceof Error ? error.message : 'Unknown error'}`));
console.log(neon_js_1.neonChalk.info('Proceeding anyway...'));
console.log('');
}
}
// Get master password
const passwordPrompt = await inquirer_1.default.prompt([{
type: 'password',
name: 'password',
message: neon_js_1.neonChalk.cyan('Master password:'),
validate: (input) => input.length > 0 || 'Password required'
}]);
// Get PIN if enabled
let pin;
if (flags.pin) {
const pinPrompt = await inquirer_1.default.prompt([{
type: 'password',
name: 'pin',
message: neon_js_1.neonChalk.cyan('Set encryption PIN (4+ characters):'),
validate: (input) => input.length >= 4 || 'PIN must be at least 4 characters'
}]);
pin = pinPrompt.pin;
}
// Display login details
const loginDetails = [
`${neon_js_1.neonChalk.cyan('ACCOUNT')} ${neon_js_1.neonSymbols.arrow} ${neon_js_1.neonChalk.highlight('@' + account)}`,
`${neon_js_1.neonChalk.magenta('ROLES')} ${neon_js_1.neonSymbols.arrow} ${neon_js_1.neonChalk.white(roles.join(', '))}`,
`${neon_js_1.neonChalk.electric('SECURITY')} ${neon_js_1.neonSymbols.arrow} ${flags.pin ? neon_js_1.neonChalk.success('PIN protected') : neon_js_1.neonChalk.warning('OS keychain only')}`,
``,
`${neon_js_1.neonChalk.darkCyan('Keys will be derived from your master password')}`
].join('\n');
console.log((0, neon_js_1.createNeonBox)(loginDetails, `${neon_js_1.neonSymbols.star} LOGIN CONFIGURATION ${neon_js_1.neonSymbols.star}`));
console.log('');
const loginSpinner = (0, neon_js_1.neonSpinner)('Deriving keys from master password');
try {
// Perform login with password derivation
await keyManager.loginWithPassword(account, passwordPrompt.password, pin, roles);
clearInterval(loginSpinner);
process.stdout.write('\r' + ' '.repeat(80) + '\r');
console.log(neon_js_1.neonChalk.success(`${neon_js_1.neonSymbols.check} Login successful!`));
console.log('');
// Get account summary
const summary = await keyManager.getAccountSummary(account);
const successMessage = [
`${neon_js_1.neonChalk.glow('Welcome to the neon grid, runner')}`,
``,
`${neon_js_1.neonChalk.cyan('Account:')} @${account}`,
`${neon_js_1.neonChalk.magenta('Keys imported:')} ${summary?.roles.join(', ')}`,
`${neon_js_1.neonChalk.electric('Security level:')} ${flags.pin ? 'Maximum (PIN + OS keychain)' : 'Standard (OS keychain)'}`,
summary?.isDefault ? `${neon_js_1.neonChalk.success('Set as default account')}` : '',
``,
`${neon_js_1.neonChalk.info('Your wallet is ready for blockchain operations')}`
].filter(Boolean).join('\n');
console.log((0, neon_js_1.createNeonBox)(successMessage, `${neon_js_1.neonSymbols.star} LOGIN COMPLETE ${neon_js_1.neonSymbols.star}`));
console.log('');
// Next steps
if (isFirstTime) {
console.log(neon_js_1.neonChalk.pulse('๐ Your wallet is now ready! Next steps:'));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Check balance: ${neon_js_1.neonChalk.highlight('beeline balance')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Test safely: ${neon_js_1.neonChalk.highlight('beeline balance --mock')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Send transfer: ${neon_js_1.neonChalk.highlight('beeline transfer @recipient 1 HIVE')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Add more accounts: ${neon_js_1.neonChalk.highlight('beeline login <account>')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} View help: ${neon_js_1.neonChalk.highlight('beeline --help')}`));
}
else {
console.log(neon_js_1.neonChalk.pulse('Next steps:'));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Check balance: ${neon_js_1.neonChalk.highlight('beeline balance')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Send transfer: ${neon_js_1.neonChalk.highlight('beeline transfer @recipient 1 HIVE')}`));
console.log(neon_js_1.neonChalk.darkCyan(`${neon_js_1.neonSymbols.bullet} Manage accounts: ${neon_js_1.neonChalk.highlight('beeline accounts list')}`));
}
// Memory scrubbing
keyManager.scrubMemory(passwordPrompt.password);
if (pin)
keyManager.scrubMemory(pin);
}
catch (error) {
clearInterval(loginSpinner);
process.stdout.write('\r' + ' '.repeat(80) + '\r');
console.log(neon_js_1.neonChalk.error(`${neon_js_1.neonSymbols.cross} Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
console.log('');
console.log(neon_js_1.neonChalk.info('Possible causes:'));
console.log(neon_js_1.neonChalk.darkCyan('โข Incorrect master password'));
console.log(neon_js_1.neonChalk.darkCyan('โข Invalid account name'));
console.log(neon_js_1.neonChalk.darkCyan('โข Network connectivity issues'));
// Memory scrubbing on error
keyManager.scrubMemory(passwordPrompt.password);
if (pin)
keyManager.scrubMemory(pin);
}
}
async showWelcomeSequence() {
console.clear();
// Display cyberpunk grid
console.log((0, neon_js_1.createNeonGrid)(80));
// Main banner
const banner = await (0, neon_js_1.createNeonBanner)('BEELINE');
console.log(banner);
// Tagline
console.log(neon_js_1.neonChalk.accent(' โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'));
console.log(neon_js_1.neonChalk.accent(' โ ') + neon_js_1.neonChalk.glow('H I V E T E R M I N A L W A L L E T') + neon_js_1.neonChalk.accent(' ยท ') + neon_js_1.neonChalk.pulse('N E O N G R I D') + neon_js_1.neonChalk.accent(' โ'));
console.log(neon_js_1.neonChalk.accent(' โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'));
console.log('');
// Welcome message
const welcomeMessage = [
`${neon_js_1.neonChalk.glow('Welcome to the neon grid, runner.')}`,
``,
`${neon_js_1.neonChalk.cyan('Your cyberpunk terminal wallet is initializing...')}`,
``,
`${neon_js_1.neonChalk.info('Security features:')}`,
`${neon_js_1.neonChalk.darkCyan('โโ')} ${neon_js_1.neonChalk.success('PIN encryption')} for maximum security`,
`${neon_js_1.neonChalk.darkCyan('โโ')} ${neon_js_1.neonChalk.success('OS keychain')} integration`,
`${neon_js_1.neonChalk.darkCyan('โโ')} ${neon_js_1.neonChalk.success('Memory scrubbing')} prevents key recovery`,
`${neon_js_1.neonChalk.darkCyan('โโ')} ${neon_js_1.neonChalk.success('Mock mode')} for safe testing`,
``,
`${neon_js_1.neonChalk.pulse('Type, sign, rule the chain.')}`
].join('\n');
console.log((0, neon_js_1.createNeonBox)(welcomeMessage, `${neon_js_1.neonSymbols.star} WALLET INITIALIZATION ${neon_js_1.neonSymbols.star}`));
console.log('');
// Brief pause for effect
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
Login.description = 'Login to your Hive account with master password';
Login.examples = [
`$ beeline login alice`,
`$ beeline login alice --roles posting,active`,
`$ beeline login alice --no-pin`
];
Login.flags = {
roles: core_1.Flags.string({
char: 'r',
description: 'key roles to import (comma-separated)',
default: 'posting,active,memo'
}),
pin: core_1.Flags.boolean({
char: 'p',
description: 'use PIN encryption for key storage',
default: true,
allowNo: true
}),
verify: core_1.Flags.boolean({
char: 'v',
description: 'verify account exists on blockchain',
default: true,
allowNo: true
}),
force: core_1.Flags.boolean({
char: 'f',
description: 'overwrite existing keys without confirmation',
default: false
})
};
Login.args = {
account: core_1.Args.string({
description: 'Hive account name',
required: true
})
};
exports.default = Login;
//# sourceMappingURL=login.js.map