Skip to content
Snippets Groups Projects

Nostr

2 unresolved threads
Open poka requested to merge nostr into master
2 unresolved threads
1 file
+ 104
20
Compare changes
  • Side-by-side
  • Inline
+ 104
20
@@ -4,6 +4,7 @@ use crate::commands::cesium::compute_g1v1_public_key;
use crate::entities::vault_account;
use crate::entities::vault_account::{AccountTreeNode, ActiveModel, DbAccountId};
use crate::*;
use crate::keys::seed_from_cesium;
use age::secrecy::Secret;
use sea_orm::ActiveValue::Set;
use sea_orm::{ConnectionTrait, TransactionTrait};
@@ -45,6 +46,30 @@ pub enum Subcommand {
/// Crypto scheme to use (sr25519, ed25519)
#[clap(short = 'c', long, required = false, default_value = CryptoScheme::Ed25519)]
crypto_scheme: CryptoScheme,
/// Substrate URI to import (non-interactive mode)
#[clap(short = 'u', long, required = false)]
uri: Option<String>,
/// G1v1 ID (non-interactive mode for g1v1 format)
#[clap(long, required = false)]
g1v1_id: Option<String>,
/// G1v1 password (non-interactive mode for g1v1 format)
#[clap(long, required = false)]
g1v1_password: Option<String>,
/// Password for encrypting the key (non-interactive mode)
#[clap(short = 'p', long, required = false)]
password: Option<String>,
/// Use empty password (non-interactive mode)
#[clap(long, required = false)]
no_password: bool,
/// Name for the wallet entry (non-interactive mode)
#[clap(short = 'n', long, required = false)]
name: Option<String>,
},
/// Add a derivation to an existing SS58 Address
#[clap(long_about = "Add a derivation to an existing SS58 Address.\n\
@@ -250,9 +275,49 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
let mnemonic = bip39::Mnemonic::generate(12).unwrap();
println!("{mnemonic}");
}
Subcommand::Import { secret_format, crypto_scheme } => {
let vault_data_for_import =
prompt_secret_and_compute_vault_data_to_import(secret_format, crypto_scheme)?;
Subcommand::Import { secret_format, crypto_scheme, uri, g1v1_id, g1v1_password, password, no_password, name } => {
let vault_data_for_import = if let Some(uri_str) = uri {
// Non-interactive mode with provided URI
if secret_format != SecretFormat::Substrate {
return Err(GcliError::Input(format!(
"URI can only be provided directly with secret_format=substrate, got: {:?}",
secret_format
)));
}
// Create keypair from provided URI
let key_pair = compute_keypair(crypto_scheme, &uri_str)?;
VaultDataToImport {
secret_format,
secret_suri: uri_str,
key_pair,
}
} else if let (Some(id), Some(pwd)) = (&g1v1_id, &g1v1_password) {
// Non-interactive mode with provided G1v1 ID and password
if secret_format != SecretFormat::G1v1 {
return Err(GcliError::Input(format!(
"G1v1 ID and password can only be provided directly with secret_format=g1v1, got: {:?}",
secret_format
)));
}
// Create keypair from provided G1v1 ID and password
let seed = seed_from_cesium(id, pwd);
let secret_suri = format!("0x{}", hex::encode(seed));
// G1v1 always uses Ed25519
let key_pair = compute_keypair(CryptoScheme::Ed25519, &secret_suri)?;
VaultDataToImport {
secret_format,
secret_suri,
key_pair,
}
} else {
// Interactive mode
prompt_secret_and_compute_vault_data_to_import(secret_format, crypto_scheme)?
};
//Extra check for SecretFormat::G1v1 (old cesium) - showing the G1v1 cesium public key for confirmation
if secret_format == SecretFormat::G1v1 {
@@ -260,17 +325,28 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
"The G1v1 public key for the provided secret is: '{}'",
compute_g1v1_public_key(&vault_data_for_import.key_pair)?
);
let confirmed = inputs::confirm_action("Is it the correct one (if not, you should try again to input G1v1 id/password) ?".to_string())?;
if !confirmed {
return Ok(());
// Skip confirmation in non-interactive mode
let is_non_interactive_g1v1 = g1v1_id.is_some() && g1v1_password.is_some();
if !is_non_interactive_g1v1 {
let confirmed = inputs::confirm_action("Is it the correct one (if not, you should try again to input G1v1 id/password) ?".to_string())?;
if !confirmed {
return Ok(());
}
}
}
let txn = db.begin().await?;
println!();
// Handle password in non-interactive mode
let provided_password = if no_password {
Some(String::new()) // Empty password
} else {
password
};
let _account =
create_base_account_for_vault_data_to_import(&txn, &vault_data_for_import, None, Some(crypto_scheme))
create_base_account_for_vault_data_to_import(&txn, &vault_data_for_import, provided_password.as_ref(), Some(crypto_scheme), name)
.await?;
txn.commit().await?;
@@ -489,6 +565,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
&vault_data_to_import,
Some(&vault_data_from_file.password),
Some(CryptoScheme::Ed25519),
None,
)
.await;
@@ -757,6 +834,7 @@ pub async fn create_base_account_for_vault_data_to_import<C>(
vault_data: &VaultDataToImport,
password_opt: Option<&String>,
crypto_scheme: Option<CryptoScheme>,
name_opt: Option<String>,
) -> Result<vault_account::Model, GcliError>
where
C: ConnectionTrait,
@@ -780,14 +858,16 @@ where
existing_vault_account
))? {
true => {
println!(
"(Optional) Enter a name for the vault entry (leave empty to remove the name)"
);
let name = inputs::prompt_vault_name_and_check_availability(
db_tx,
existing_vault_account.name.as_ref(),
)
.await?;
let name = if let Some(name) = name_opt {
Some(name)
} else {
println!("(Optional) Enter a name for the vault entry (leave empty to remove the name)");
inputs::prompt_vault_name_and_check_availability(
db_tx,
existing_vault_account.name.as_ref(),
)
.await?
};
// Since links are made based on address / parent(address) we can just edit the existing entry and it should be fine
let mut vault_account: ActiveModel = existing_vault_account.into();
@@ -797,7 +877,7 @@ where
map_secret_format_to_crypto_scheme(vault_data.secret_format, crypto_scheme).into(),
));
vault_account.encrypted_suri = Set(Some(encrypted_suri));
vault_account.name = Set(name.clone());
vault_account.name = Set(name);
vault_account.secret_format = Set(Some(vault_data.secret_format.into()));
let updated_vault_account =
vault_account::update_account(db_tx, vault_account).await?;
@@ -815,8 +895,12 @@ where
let encrypted_suri = compute_encrypted_suri(password, vault_data.secret_suri.clone())?;
println!("(Optional) Enter a name for the vault entry");
let name = inputs::prompt_vault_name_and_check_availability(db_tx, None).await?;
let name = if let Some(name) = name_opt {
Some(name)
} else {
println!("(Optional) Enter a name for the vault entry");
inputs::prompt_vault_name_and_check_availability(db_tx, None).await?
};
let crypto_scheme = map_secret_format_to_crypto_scheme(secret_format, crypto_scheme);
Loading