Skip to content

Commit

Permalink
Merge pull request #10018 from Halimao/feat/discreetly
Browse files Browse the repository at this point in the history
feat: support display private key discreetly
  • Loading branch information
d0cd authored Jan 16, 2024
2 parents 87b101a + f354221 commit 195df65
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 11 deletions.
57 changes: 57 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ features = [ "fmt" ]
[dependencies.zip]
version = "^0.6"

[dependencies.crossterm]
version = "0.27.0"

[target."cfg(windows)".dependencies.ansi_term]
version = "0.12.1"

Expand Down
59 changes: 48 additions & 11 deletions leo/cli/commands/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ use super::*;
use leo_package::root::Env;
use snarkvm::prelude::{Address, PrivateKey, ViewKey};

use crossterm::ExecutableCommand;
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use std::io::{self, Read, Write};

/// Commands to manage Aleo accounts.
#[derive(Parser, Debug)]
Expand All @@ -32,6 +34,9 @@ pub enum Account {
/// Write the private key to the .env file.
#[clap(short = 'w', long)]
write: bool,
/// Print sensitive information (such as private key) discreetly to an alternate screen
#[clap(long)]
discreet: bool,
},
/// Derive an Aleo account from a private key.
Import {
Expand All @@ -40,6 +45,9 @@ pub enum Account {
/// Write the private key to the .env file.
#[clap(short = 'w', long)]
write: bool,
/// Print sensitive information (such as private key) discreetly to an alternate screen
#[clap(long)]
discreet: bool,
},
}

Expand All @@ -59,7 +67,7 @@ impl Command for Account {
Self: Sized,
{
match self {
Account::New { seed, write } => {
Account::New { seed, write, discreet } => {
// Sample a new Aleo account.
let private_key = match seed {
// Recover the field element deterministically.
Expand All @@ -70,16 +78,16 @@ impl Command for Account {
.map_err(CliError::failed_to_parse_seed)?;

// Derive the view key and address and print to stdout.
print_keys(private_key)?;
print_keys(private_key, discreet)?;

// Save key data to .env file.
if write {
write_to_env_file(private_key, &ctx)?;
}
}
Account::Import { private_key, write } => {
Account::Import { private_key, write, discreet } => {
// Derive the view key and address and print to stdout.
print_keys(private_key)?;
print_keys(private_key, discreet)?;

// Save key data to .env file.
if write {
Expand All @@ -94,16 +102,24 @@ impl Command for Account {
// Helper functions

// Print keys as a formatted string without log level.
fn print_keys(private_key: PrivateKey<CurrentNetwork>) -> Result<()> {
fn print_keys(private_key: PrivateKey<CurrentNetwork>, discreet: bool) -> Result<()> {
let view_key = ViewKey::try_from(&private_key)?;
let address = Address::<CurrentNetwork>::try_from(&view_key)?;

println!(
"\n {:>12} {private_key}\n {:>12} {view_key}\n {:>12} {address}\n",
"Private Key".cyan().bold(),
"View Key".cyan().bold(),
"Address".cyan().bold(),
);
if !discreet {
println!(
"\n {:>12} {private_key}\n {:>12} {view_key}\n {:>12} {address}\n",
"Private Key".cyan().bold(),
"View Key".cyan().bold(),
"Address".cyan().bold(),
);
return Ok(());
}
display_string_discreetly(
&private_key.to_string(),
"### Do not share or lose this private key! Press any key to complete. ###",
)?;
println!("\n {:>12} {view_key}\n {:>12} {address}\n", "View Key".cyan().bold(), "Address".cyan().bold(),);
Ok(())
}

Expand All @@ -115,3 +131,24 @@ fn write_to_env_file(private_key: PrivateKey<CurrentNetwork>, ctx: &Context) ->
tracing::info!("✅ Private Key written to {}", program_dir.join(".env").display());
Ok(())
}

/// Print the string to an alternate screen, so that the string won't been printed to the terminal.
fn display_string_discreetly(discreet_string: &str, continue_message: &str) -> Result<()> {
use crossterm::{
style::Print,
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
};
let mut stdout = io::stdout();
stdout.execute(EnterAlternateScreen).unwrap();
// print msg on the alternate screen
stdout.execute(Print(format!("{discreet_string}\n{continue_message}"))).unwrap();
stdout.flush().unwrap();
wait_for_keypress();
stdout.execute(LeaveAlternateScreen).unwrap();
Ok(())
}

fn wait_for_keypress() {
let mut single_key = [0u8];
std::io::stdin().read_exact(&mut single_key).unwrap();
}

0 comments on commit 195df65

Please sign in to comment.