Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/os keychain followup #1770

Open
wants to merge 7 commits into
base: feat/os_keychain
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@ Add a new identity (keypair, ledger, OS specific secure store)

* `--secret-key` — Add using `secret_key` Can provide with `SOROBAN_SECRET_KEY`
* `--seed-phrase` — Add using 12 word seed phrase to generate `secret_key`
* `--secure-store` — Add using secure store entry
* `--entry-name <ENTRY_NAME>` — Name of the secure store entry
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."

Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/keys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl Cmd {
Cmd::Fund(cmd) => cmd.run().await?,
Cmd::Generate(cmd) => cmd.run(global_args).await?,
Cmd::Ls(cmd) => cmd.run()?,
Cmd::Rm(cmd) => cmd.run()?,
Cmd::Rm(cmd) => cmd.run(global_args)?,
Cmd::Show(cmd) => cmd.run()?,
Cmd::Default(cmd) => cmd.run(global_args)?,
};
Expand Down
6 changes: 4 additions & 2 deletions cmd/soroban-cli/src/commands/keys/rm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use clap::command;

use crate::commands::global;

use super::super::config::locator;

#[derive(thiserror::Error, Debug)]
Expand All @@ -19,7 +21,7 @@ pub struct Cmd {
}

impl Cmd {
pub fn run(&self) -> Result<(), Error> {
Ok(self.config.remove_identity(&self.name)?)
pub fn run(&self, global_args: &global::Args) -> Result<(), Error> {
Ok(self.config.remove_identity(&self.name, global_args)?)
}
}
29 changes: 27 additions & 2 deletions cmd/soroban-cli/src/config/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ use std::{
};
use stellar_strkey::{Contract, DecodeError};

use crate::{commands::HEADING_GLOBAL, utils::find_config_dir, Pwd};
use crate::{
commands::{global, HEADING_GLOBAL},
print::Print,
signer::{self, keyring::StellarEntry},
utils::find_config_dir,
Pwd,
};

use super::{
alias,
Expand Down Expand Up @@ -83,6 +89,8 @@ pub enum Error {
UpgradeCheckReadFailed { path: PathBuf, error: io::Error },
#[error("Failed to write upgrade check file: {path}: {error}")]
UpgradeCheckWriteFailed { path: PathBuf, error: io::Error },
#[error(transparent)]
Keyring(#[from] signer::keyring::Error),
}

#[derive(Debug, clap::Args, Default, Clone)]
Expand Down Expand Up @@ -253,7 +261,24 @@ impl Args {
res
}

pub fn remove_identity(&self, name: &str) -> Result<(), Error> {
pub fn remove_identity(&self, name: &str, global_args: &global::Args) -> Result<(), Error> {
let print = Print::new(global_args.quiet);
let identity = self.read_identity(name)?;
if let Secret::SecureStore { entry_name } = identity {
let entry = StellarEntry::new(&entry_name)?;
match entry.delete_password() {
Ok(()) => {}
Err(e) => match e {
signer::keyring::Error::Keyring(keyring::Error::NoEntry) => {
print.infoln("This key was already removed from the secure store. Removing the cli config file.");
}
_ => {
return Err(Error::Keyring(e));
}
},
}
}

KeyType::Identity.remove(name, &self.config_dir()?)
}

Expand Down
29 changes: 27 additions & 2 deletions cmd/soroban-cli/src/config/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,25 @@ pub enum Error {
pub struct Args {
/// Add using `secret_key`
/// Can provide with `SOROBAN_SECRET_KEY`
#[arg(long, conflicts_with = "seed_phrase")]
#[arg(long, conflicts_with = "seed_phrase", conflicts_with = "secure_store")]
pub secret_key: bool,

/// Add using 12 word seed phrase to generate `secret_key`
#[arg(long, conflicts_with = "secret_key")]
#[arg(long, conflicts_with = "secret_key", conflicts_with = "secure_store")]
pub seed_phrase: bool,

/// Add using secure store entry
#[arg(
long,
requires = "entry_name",
conflicts_with = "seed_phrase",
conflicts_with = "secret_key"
)]
pub secure_store: bool,

/// Name of the secure store entry
#[arg(long, requires = "secure_store")]
pub entry_name: Option<String>,
}

impl Args {
Expand Down Expand Up @@ -71,6 +85,17 @@ impl Args {
.collect::<Vec<_>>()
.join(" "),
})
} else if self.secure_store {
let entry_name_with_prefix = format!(
"{}{}-{}",
keyring::SECURE_STORE_ENTRY_PREFIX,
keyring::SECURE_STORE_ENTRY_SERVICE,
self.entry_name.as_ref().unwrap()
);

Ok(Secret::SecureStore {
entry_name: entry_name_with_prefix,
})
} else {
Err(Error::PasswordRead {})
}
Expand Down
31 changes: 30 additions & 1 deletion cmd/soroban-cli/src/signer/keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ impl StellarEntry {
Ok(base64.decode(self.keyring.get_password()?)?)
}

pub fn delete_password(&self) -> Result<(), Error> {
Ok(self.keyring.delete_credential()?)
}

fn use_key<T>(
&self,
f: impl FnOnce(ed25519_dalek::SigningKey) -> Result<T, Error>,
Expand Down Expand Up @@ -116,7 +120,7 @@ mod test {
fn test_sign_data() {
set_default_credential_builder(mock::default_credential_builder());

//create a secret
// create a secret
let secret = crate::config::secret::Secret::from_seed(None).unwrap();
let key_pair = secret.key_pair(None).unwrap();

Expand All @@ -129,4 +133,29 @@ mod test {
let sign_tx_env_result = entry.sign_data(tx_xdr.as_bytes());
assert!(sign_tx_env_result.is_ok());
}

#[test]
fn test_delete_password() {
set_default_credential_builder(mock::default_credential_builder());

// add a keyring entry
let entry = StellarEntry::new("test").unwrap();
entry.set_password("test password".as_bytes()).unwrap();

// assert it is there
let get_password_result = entry.get_password();
assert!(get_password_result.is_ok());

// delete the password
let delete_password_result = entry.delete_password();
assert!(delete_password_result.is_ok());

// confirm the entry is gone
let get_password_result = entry.get_password();
assert!(get_password_result.is_err());
assert!(matches!(
get_password_result.unwrap_err(),
Error::Keyring(_)
));
}
}
Loading