From f9fbf1a0b7b85638ad64287738e05ec1a1c35d25 Mon Sep 17 00:00:00 2001
From: Awiteb
Date: Fri, 10 May 2024 09:12:59 +0300
Subject: [PATCH] feat: Add `get` command
Fixes: https://git.4rs.nl/awiteb/lprs/issues/32
---
src/cli/get_command.rs | 140 +++++++++++++++++++++++++++++++++++++++++
src/cli/mod.rs | 6 +-
2 files changed, 145 insertions(+), 1 deletion(-)
create mode 100644 src/cli/get_command.rs
diff --git a/src/cli/get_command.rs b/src/cli/get_command.rs
new file mode 100644
index 0000000..beae329
--- /dev/null
+++ b/src/cli/get_command.rs
@@ -0,0 +1,140 @@
+// Lprs - A local CLI vault manager
+// Copyright (C) 2024 Awiteb
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use std::str::FromStr;
+
+use clap::Args;
+
+use crate::{
+ vault::{Vault, Vaults},
+ LprsCommand,
+ LprsError,
+ LprsResult,
+};
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+enum VaultGetField {
+ Index,
+ Name,
+ Username,
+ Password,
+ Service,
+ Note,
+ Custom(String),
+}
+
+impl FromStr for VaultGetField {
+ type Err = LprsError;
+
+ fn from_str(input: &str) -> Result {
+ Ok(match input.to_lowercase().as_str() {
+ "index" => Self::Index,
+ "name" => Self::Name,
+ "username" => Self::Username,
+ "password" => Self::Password,
+ "service" => Self::Service,
+ "note" => Self::Note,
+ _ => Self::Custom(input.to_owned()),
+ })
+ }
+}
+
+impl VaultGetField {
+ /// Returns the field from the vault
+ pub fn get_from_vault<'a>(&self, vault: &'a Vault) -> Option<&'a str> {
+ match self {
+ Self::Index => None,
+ Self::Name => Some(&vault.name),
+ Self::Username => vault.username.as_deref(),
+ Self::Password => vault.password.as_deref(),
+ Self::Service => vault.service.as_deref(),
+ Self::Note => vault.note.as_deref(),
+ Self::Custom(custom_field) => vault.custom_fields.get(custom_field).map(|x| x.as_str()),
+ }
+ }
+
+ /// Returns the field as `&str`
+ pub fn as_str(&self) -> &str {
+ match self {
+ Self::Index => "index",
+ Self::Name => "name",
+ Self::Username => "username",
+ Self::Password => "password",
+ Self::Service => "service",
+ Self::Note => "note",
+ Self::Custom(field) => field.as_str(),
+ }
+ }
+}
+
+#[derive(Debug, Args)]
+#[command(author, version, about, long_about = None)]
+/// Command to get a entire vault or single field from it
+pub struct Get {
+ /// Whether the index of the vault or its name
+ #[arg(value_name = "INDEX-or-NAME")]
+ location: String,
+ /// A Specific field to get.
+ ///
+ /// Can be [name,username,password,service,note,"string"] where the string
+ /// means a custom field
+ #[arg(value_parser = VaultGetField::from_str)]
+ field: Option,
+}
+
+impl LprsCommand for Get {
+ fn run(self, vault_manager: Vaults) -> LprsResult<()> {
+ let parsed_index = self.location.trim().parse::();
+ let Some((index, vault)) = (if let Ok(index) = parsed_index {
+ vault_manager.vaults.get(index - 1).map(|v| (index, v))
+ } else {
+ vault_manager
+ .vaults
+ .iter()
+ .enumerate()
+ .find(|(_, v)| v.name == self.location)
+ }) else {
+ return Err(LprsError::Other(format!(
+ "There is no vault with the given {} `{}`",
+ if parsed_index.is_ok() {
+ "index"
+ } else {
+ "name"
+ },
+ self.location.trim(),
+ )));
+ };
+
+ if let Some(field) = self.field {
+ if field == VaultGetField::Index {
+ print!("{index}");
+ return Ok(());
+ }
+
+ if let Some(value) = field.get_from_vault(vault) {
+ print!("{value}")
+ } else {
+ return Err(LprsError::Other(format!(
+ "There is no value for `{}`",
+ field.as_str()
+ )));
+ }
+ } else {
+ println!("{vault}");
+ }
+ Ok(())
+ }
+}
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index a9f055a..7b0ae8f 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -31,6 +31,8 @@ pub mod edit_command;
pub mod export_command;
/// Generate command, used to generate a password
pub mod gen_command;
+/// Command to get a entire vault or single field from it
+pub mod get_command;
/// Import command, used to import vaults from the exported files, `lprs` or
/// `BitWarden`
pub mod import_command;
@@ -56,13 +58,15 @@ pub enum Commands {
Edit(edit_command::Edit),
/// Generate a password
Gen(gen_command::Gen),
+ /// Get a entire vault or single field from it
+ Get(get_command::Get),
/// Export the vaults
Export(export_command::Export),
/// Import vaults
Import(import_command::Import),
}
-impl_commands!(Commands, Add Remove List Clean Edit Gen Export Import);
+impl_commands!(Commands, Add Remove List Clean Edit Gen Get Export Import);
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]