feat: Ability to enter password via stdin add
&edit
#15
11 changed files with 80 additions and 48 deletions
|
@ -26,18 +26,36 @@ use crate::{
|
||||||
pub struct Add {
|
pub struct Add {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
vault_info: Vault<Plain>,
|
vault_info: Vault<Plain>,
|
||||||
|
/// The password, if there is no value for it you will prompt it
|
||||||
|
#[arg(short, long)]
|
||||||
|
password: Option<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Add {
|
impl RunCommand for Add {
|
||||||
fn run(&self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(mut self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
if self.vault_info.username.is_none()
|
if self.vault_info.username.is_none()
|
||||||
&& self.vault_info.password.is_none()
|
&& self.password.is_none()
|
||||||
&& self.vault_info.service.is_none()
|
&& self.vault_info.service.is_none()
|
||||||
&& self.vault_info.note.is_none()
|
&& self.vault_info.note.is_none()
|
||||||
{
|
{
|
||||||
return Err(LprsError::Other("You can't add empty vault".to_owned()));
|
return Err(LprsError::Other("You can't add empty vault".to_owned()));
|
||||||
}
|
}
|
||||||
vault_manager.add_vault(self.vault_info.clone());
|
|
||||||
|
match self.password {
|
||||||
|
Some(Some(password)) => self.vault_info.password = Some(password),
|
||||||
|
Some(None) => {
|
||||||
|
self.vault_info.password = Some(
|
||||||
|
inquire::Password::new("Vault password:")
|
||||||
|
.without_confirmation()
|
||||||
|
.with_formatter(&|p| "*".repeat(p.chars().count()))
|
||||||
|
.with_display_mode(inquire::PasswordDisplayMode::Masked)
|
||||||
|
.prompt()?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
vault_manager.add_vault(self.vault_info);
|
||||||
vault_manager.try_export()
|
vault_manager.try_export()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::{
|
||||||
pub struct Clean {}
|
pub struct Clean {}
|
||||||
|
|
||||||
impl RunCommand for Clean {
|
impl RunCommand for Clean {
|
||||||
fn run(&self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
fs::write(vault_manager.vaults_file, "[]").map_err(LprsError::Io)
|
fs::write(vault_manager.vaults_file, "[]").map_err(LprsError::Io)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ pub struct Edit {
|
||||||
/// The new vault username
|
/// The new vault username
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
/// The new password
|
/// The new password, if there is no value for it you will prompt it
|
||||||
password: Option<String>,
|
password: Option<Option<String>>,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
/// The new vault service
|
/// The new vault service
|
||||||
service: Option<String>,
|
service: Option<String>,
|
||||||
|
@ -47,35 +47,48 @@ pub struct Edit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Edit {
|
impl RunCommand for Edit {
|
||||||
fn run(&self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
let index = self.index.get() as usize;
|
let index = self.index.get() as usize;
|
||||||
|
|
||||||
if let Some(vault) = vault_manager.vaults.get_mut(index - 1) {
|
let Some(vault) = vault_manager.vaults.get_mut(index - 1) else {
|
||||||
|
return Err(LprsError::InvalidVaultIndex(format!(
|
||||||
|
"The index `{}` is greater than the vaults count {}",
|
||||||
|
self.index,
|
||||||
|
vault_manager.vaults.len()
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
|
||||||
if self.name.is_none()
|
if self.name.is_none()
|
||||||
&& self.username.is_none()
|
&& self.username.is_none()
|
||||||
&& self.password.is_none()
|
&& self.password.is_none()
|
||||||
&& self.service.is_none()
|
&& self.service.is_none()
|
||||||
&& self.note.is_none()
|
&& self.note.is_none()
|
||||||
{
|
{
|
||||||
Err(LprsError::Other(
|
return Err(LprsError::Other(
|
||||||
"You must edit one option at least".to_owned(),
|
"You must edit one option at least".to_owned(),
|
||||||
))
|
));
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// Get the password from stdin or from its value if provided
|
||||||
|
let password = match self.password {
|
||||||
|
Some(Some(password)) => Some(password),
|
||||||
|
Some(None) => Some(
|
||||||
|
inquire::Password::new("New vault password:")
|
||||||
|
.without_confirmation()
|
||||||
|
.with_formatter(&|p| "*".repeat(p.chars().count()))
|
||||||
|
.with_display_mode(inquire::PasswordDisplayMode::Masked)
|
||||||
|
.prompt()?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
*vault = Vault::<Plain>::new(
|
*vault = Vault::<Plain>::new(
|
||||||
self.name.as_ref().unwrap_or(&vault.name),
|
self.name.as_ref().unwrap_or(&vault.name),
|
||||||
self.username.as_ref().or(vault.username.as_ref()),
|
self.username.as_ref().or(vault.username.as_ref()),
|
||||||
self.password.as_ref().or(vault.password.as_ref()),
|
password.as_ref().or(vault.password.as_ref()),
|
||||||
self.service.as_ref().or(vault.service.as_ref()),
|
self.service.as_ref().or(vault.service.as_ref()),
|
||||||
self.note.as_ref().or(vault.note.as_ref()),
|
self.note.as_ref().or(vault.note.as_ref()),
|
||||||
);
|
);
|
||||||
vault_manager.try_export()
|
vault_manager.try_export()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Err(LprsError::InvalidVaultIndex(format!(
|
|
||||||
"The index `{}` is greater than the vaults count {}",
|
|
||||||
self.index,
|
|
||||||
vault_manager.vaults.len()
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub struct Export {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Export {
|
impl RunCommand for Export {
|
||||||
fn run(&self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
if self
|
if self
|
||||||
.path
|
.path
|
||||||
.extension()
|
.extension()
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub struct Gen {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Gen {
|
impl RunCommand for Gen {
|
||||||
fn run(&self, _vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, _vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
if self.uppercase || self.lowercase || self.numbers || self.symbols {
|
if self.uppercase || self.lowercase || self.numbers || self.symbols {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct Import {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Import {
|
impl RunCommand for Import {
|
||||||
fn run(&self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
if self.path.exists() {
|
if self.path.exists() {
|
||||||
if self
|
if self
|
||||||
.path
|
.path
|
||||||
|
@ -44,10 +44,8 @@ impl RunCommand for Import {
|
||||||
{
|
{
|
||||||
let imported_passwords_len = match self.format {
|
let imported_passwords_len = match self.format {
|
||||||
Format::Lprs => {
|
Format::Lprs => {
|
||||||
let vaults = Vaults::try_reload(
|
let vaults =
|
||||||
self.path.to_path_buf(),
|
Vaults::try_reload(self.path, vault_manager.master_password.to_vec())?;
|
||||||
vault_manager.master_password.to_vec(),
|
|
||||||
)?;
|
|
||||||
let vaults_len = vaults.vaults.len();
|
let vaults_len = vaults.vaults.len();
|
||||||
|
|
||||||
vault_manager.vaults.extend(vaults.vaults);
|
vault_manager.vaults.extend(vaults.vaults);
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub struct List {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for List {
|
impl RunCommand for List {
|
||||||
fn run(&self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
if vault_manager.vaults.is_empty() {
|
if vault_manager.vaults.is_empty() {
|
||||||
return Err(LprsError::Other(
|
return Err(LprsError::Other(
|
||||||
"Looks like there is no passwords to list".to_owned(),
|
"Looks like there is no passwords to list".to_owned(),
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct Remove {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand for Remove {
|
impl RunCommand for Remove {
|
||||||
fn run(&self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
fn run(self, mut vault_manager: Vaults<Plain>) -> LprsResult<()> {
|
||||||
let index = (self.index.get() - 1) as usize;
|
let index = (self.index.get() - 1) as usize;
|
||||||
if index > vault_manager.vaults.len() {
|
if index > vault_manager.vaults.len() {
|
||||||
if !self.force {
|
if !self.force {
|
||||||
|
|
|
@ -63,7 +63,7 @@ macro_rules! create_commands {
|
||||||
|
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl $crate::RunCommand for $enum_name{
|
impl $crate::RunCommand for $enum_name{
|
||||||
fn run(&self, vault_manager: $crate::vault::Vaults<$crate::vault::vault_state::Plain>) -> $crate::LprsResult<()> {
|
fn run(self, vault_manager: $crate::vault::Vaults<$crate::vault::vault_state::Plain>) -> $crate::LprsResult<()> {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
Self::$varint(command) => command.run(vault_manager),
|
Self::$varint(command) => command.run(vault_manager),
|
||||||
|
|
|
@ -21,5 +21,5 @@ use crate::{
|
||||||
|
|
||||||
/// Trait to run the command
|
/// Trait to run the command
|
||||||
pub trait RunCommand {
|
pub trait RunCommand {
|
||||||
fn run(&self, vault_manager: Vaults<Plain>) -> LprsResult<()>;
|
fn run(self, vault_manager: Vaults<Plain>) -> LprsResult<()>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ where
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
/// The password
|
/// The password
|
||||||
#[arg(short, long)]
|
#[arg(skip)]
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
/// The service name. e.g the website url
|
/// The service name. e.g the website url
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
@ -187,11 +187,14 @@ impl Vaults<Plain> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Format {
|
impl std::fmt::Display for Format {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
self.to_possible_value()
|
self.to_possible_value()
|
||||||
.expect("There is no skiped values")
|
.expect("There is no skiped values")
|
||||||
.get_name()
|
.get_name()
|
||||||
.to_owned()
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue