Compare commits
No commits in common. "6f83bcccf94b88181d86358a922e61e3d3a2dad8" and "c2fafd87e62c724732e1f6f1446163d146975340" have entirely different histories.
6f83bcccf9
...
c2fafd87e6
14 changed files with 37 additions and 241 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -106,12 +106,6 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base32"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
|
@ -335,7 +329,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -538,15 +531,6 @@ version = "0.3.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
|
@ -741,7 +725,6 @@ name = "lprs"
|
|||
version = "1.2.1"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base32",
|
||||
"base64 0.22.1",
|
||||
"bincode",
|
||||
"cbc",
|
||||
|
@ -759,7 +742,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"totp-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1183,17 +1165,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
|
@ -1272,12 +1243,6 @@ version = "0.11.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.60"
|
||||
|
@ -1409,18 +1374,6 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "totp-lite"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8e43134db17199f7f721803383ac5854edd0d3d523cc34dba321d6acfbe76c3"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
"sha1",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
|
|
|
@ -30,8 +30,6 @@ sha2 = "0.10.8"
|
|||
serde_json = "1.0.116"
|
||||
base64 = "0.22.1"
|
||||
clap_complete = "4.5.2"
|
||||
totp-lite = "2.0.1"
|
||||
base32 = "0.4.0"
|
||||
|
||||
[features]
|
||||
default = ["update-notify"]
|
||||
|
|
|
@ -31,14 +31,10 @@ use crate::{
|
|||
pub struct Add {
|
||||
#[command(flatten)]
|
||||
vault_info: Vault,
|
||||
/// The password, if there is no value you will prompt it
|
||||
/// The password, if there is no value for it you will prompt it
|
||||
#[arg(short, long)]
|
||||
#[allow(clippy::option_option)]
|
||||
password: Option<Option<String>>,
|
||||
/// The TOTP secret, if there is no value you will prompt it
|
||||
#[arg(short, long)]
|
||||
#[allow(clippy::option_option)]
|
||||
totp_secret: Option<Option<String>>,
|
||||
/// Add a custom field to the vault
|
||||
#[arg(name = "KEY=VALUE", short = 'c', long = "custom")]
|
||||
#[arg(value_parser = clap_parsers::kv_parser)]
|
||||
|
@ -55,8 +51,7 @@ impl LprsCommand for Add {
|
|||
fn run(mut self, mut vault_manager: Vaults) -> LprsResult<()> {
|
||||
if !self.vault_info.is_empty() {
|
||||
self.vault_info.name = self.vault_info.name.trim().to_string();
|
||||
self.vault_info.password = utils::user_secret(self.password, "Vault password:")?;
|
||||
self.vault_info.totp_secret = utils::user_secret(self.totp_secret, "TOTP Secret:")?;
|
||||
self.vault_info.password = utils::user_password(self.password, "Vault password:")?;
|
||||
self.vault_info.custom_fields = self.custom_fields.into_iter().collect();
|
||||
vault_manager.add_vault(self.vault_info);
|
||||
vault_manager.try_export()?;
|
||||
|
@ -76,13 +71,6 @@ impl LprsCommand for Add {
|
|||
)));
|
||||
}
|
||||
}
|
||||
if self
|
||||
.custom_fields
|
||||
.iter()
|
||||
.any(|(k, _)| k.starts_with(crate::RESERVED_FIELD_PREFIX))
|
||||
{
|
||||
return Err(LprsError::ReservedPrefix(crate::RESERVED_FIELD_PREFIX));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -42,16 +42,12 @@ pub struct Edit {
|
|||
#[arg(short = 'o', long)]
|
||||
/// The new vault note
|
||||
note: Option<String>,
|
||||
/// The TOTP secret, if there is no value you will prompt it
|
||||
#[arg(short, long)]
|
||||
#[allow(clippy::option_option)]
|
||||
totp_secret: Option<Option<String>>,
|
||||
/// The custom field, make its value empty to delete it
|
||||
///
|
||||
/// If the custom field not exist will created it, if it's will update it
|
||||
#[arg(name = "KEY=VALUE", short = 'c', long = "custom")]
|
||||
#[arg(value_parser = clap_parsers::kv_parser)]
|
||||
custom_fields: Vec<(String, String)>,
|
||||
pub custom_fields: Vec<(String, String)>,
|
||||
/// Force edit, will not return error if there is a problem with the args.
|
||||
///
|
||||
/// For example, duplication in the custom fields and try to editing nothing
|
||||
|
@ -77,10 +73,7 @@ impl LprsCommand for Edit {
|
|||
vault.name = new_name;
|
||||
}
|
||||
if self.password.is_some() {
|
||||
vault.password = utils::user_secret(self.password, "New vault password:")?;
|
||||
}
|
||||
if self.totp_secret.is_some() {
|
||||
vault.totp_secret = utils::user_secret(self.totp_secret, "TOTP Secret:")?;
|
||||
vault.password = utils::user_password(self.password, "New vault password:")?;
|
||||
}
|
||||
if let Some(new_username) = self.username {
|
||||
vault.username = Some(new_username);
|
||||
|
@ -116,13 +109,6 @@ impl LprsCommand for Edit {
|
|||
)));
|
||||
}
|
||||
}
|
||||
if self
|
||||
.custom_fields
|
||||
.iter()
|
||||
.any(|(k, _)| k.starts_with(crate::RESERVED_FIELD_PREFIX))
|
||||
{
|
||||
return Err(LprsError::ReservedPrefix(crate::RESERVED_FIELD_PREFIX));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ impl LprsCommand for Export {
|
|||
);
|
||||
|
||||
let encryption_key: Option<[u8; 32]> =
|
||||
utils::user_secret(self.encryption_password, "Encryption Password:")?
|
||||
utils::user_password(self.encryption_password, "Encryption Password:")?
|
||||
.map(|p| sha2::Sha256::digest(p).into());
|
||||
|
||||
let exported_data = match self.format {
|
||||
|
|
|
@ -20,7 +20,7 @@ use clap::Args;
|
|||
|
||||
use crate::{
|
||||
utils,
|
||||
vault::{cipher, Vault, Vaults},
|
||||
vault::{Vault, Vaults},
|
||||
LprsCommand,
|
||||
LprsError,
|
||||
LprsResult,
|
||||
|
@ -34,8 +34,6 @@ enum VaultGetField {
|
|||
Password,
|
||||
Service,
|
||||
Note,
|
||||
TotpSecret,
|
||||
TotpCode,
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
|
@ -50,8 +48,6 @@ impl FromStr for VaultGetField {
|
|||
"password" => Self::Password,
|
||||
"service" => Self::Service,
|
||||
"note" => Self::Note,
|
||||
"totp_secret" => Self::TotpSecret,
|
||||
"totp_code" => Self::TotpCode,
|
||||
_ => Self::Custom(input.to_owned()),
|
||||
})
|
||||
}
|
||||
|
@ -67,8 +63,6 @@ impl VaultGetField {
|
|||
Self::Password => vault.password.as_deref(),
|
||||
Self::Service => vault.service.as_deref(),
|
||||
Self::Note => vault.note.as_deref(),
|
||||
Self::TotpSecret => vault.totp_secret.as_deref(),
|
||||
Self::TotpCode => None,
|
||||
Self::Custom(custom_field) => vault.custom_fields.get(custom_field).map(|x| x.as_str()),
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +76,6 @@ impl VaultGetField {
|
|||
Self::Password => "password",
|
||||
Self::Service => "service",
|
||||
Self::Note => "note",
|
||||
Self::TotpSecret => "totp_secret",
|
||||
Self::TotpCode => "totp_code",
|
||||
Self::Custom(field) => field.as_str(),
|
||||
}
|
||||
}
|
||||
|
@ -98,10 +90,8 @@ pub struct Get {
|
|||
location: String,
|
||||
/// A Specific field to get.
|
||||
///
|
||||
/// Can be [name, username, password, service, note, totp_secret, totp_code,
|
||||
/// "string"]
|
||||
///
|
||||
/// where the string means a custom field
|
||||
/// Can be [name,username,password,service,note,"string"] where the string
|
||||
/// means a custom field
|
||||
#[arg(value_parser = VaultGetField::from_str)]
|
||||
field: Option<VaultGetField>,
|
||||
}
|
||||
|
@ -116,25 +106,13 @@ impl LprsCommand for Get {
|
|||
print!("{index}");
|
||||
return Ok(());
|
||||
}
|
||||
if field == VaultGetField::TotpCode {
|
||||
if let Some(ref totp_secret) = vault.totp_secret {
|
||||
let totp_code = cipher::totp_now(totp_secret, &vault.totp_hash)?.0;
|
||||
print!("{totp_code}");
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(LprsError::Other(
|
||||
"There is no TOTP secret to get TOTP code".to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = field.get_from_vault(vault) {
|
||||
print!("{value}")
|
||||
} else {
|
||||
return Err(LprsError::Other(format!(
|
||||
"There is no value for `{}` at \"{}\" vault",
|
||||
field.as_str(),
|
||||
vault.name
|
||||
"There is no value for `{}`",
|
||||
field.as_str()
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -60,7 +60,7 @@ impl LprsCommand for Import {
|
|||
);
|
||||
|
||||
let decryption_key: Option<[u8; 32]> =
|
||||
utils::user_secret(self.decryption_password, "Decryption password:")?
|
||||
utils::user_password(self.decryption_password, "Decryption password:")?
|
||||
.map(|p| sha2::Sha256::digest(p).into());
|
||||
|
||||
let imported_passwords_len = match self.format {
|
||||
|
@ -71,14 +71,6 @@ impl LprsCommand for Import {
|
|||
.unwrap_or(&vault_manager.master_password),
|
||||
&fs::read(self.path)?,
|
||||
)?;
|
||||
|
||||
if vaults.iter().any(|v| {
|
||||
v.custom_fields
|
||||
.iter()
|
||||
.any(|(k, _)| k.starts_with(crate::RESERVED_FIELD_PREFIX))
|
||||
}) {
|
||||
return Err(LprsError::ReservedPrefix(crate::RESERVED_FIELD_PREFIX));
|
||||
}
|
||||
let vaults_len = vaults.len();
|
||||
|
||||
vault_manager.vaults.extend(vaults);
|
||||
|
|
|
@ -17,13 +17,7 @@
|
|||
use clap::Args;
|
||||
use inquire::{InquireError, Select};
|
||||
|
||||
use crate::{
|
||||
vault::{cipher, Vaults},
|
||||
LprsCommand,
|
||||
LprsError,
|
||||
LprsResult,
|
||||
RESERVED_FIELD_PREFIX,
|
||||
};
|
||||
use crate::{vault::Vaults, LprsCommand, LprsError, LprsResult};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
|
@ -41,7 +35,7 @@ pub struct List {
|
|||
}
|
||||
|
||||
impl LprsCommand for List {
|
||||
fn run(self, mut vault_manager: Vaults) -> LprsResult<()> {
|
||||
fn run(self, vault_manager: Vaults) -> LprsResult<()> {
|
||||
if vault_manager.vaults.is_empty() {
|
||||
return Err(LprsError::Other(
|
||||
"Looks like there is no vaults to list".to_owned(),
|
||||
|
@ -101,22 +95,15 @@ impl LprsCommand for List {
|
|||
|
||||
log::debug!("The user selected the vault at index: {vault_idx}");
|
||||
|
||||
let vault = vault_manager
|
||||
println!(
|
||||
"{}",
|
||||
vault_manager
|
||||
.vaults
|
||||
.get_mut(vault_idx - 1)
|
||||
.expect("The index is correct");
|
||||
|
||||
if let Some(ref totp_secret) = vault.totp_secret {
|
||||
let (code, remaining) = cipher::totp_now(totp_secret, &vault.totp_hash)?;
|
||||
vault.custom_fields.insert(
|
||||
format!("{RESERVED_FIELD_PREFIX}TOTP Code"),
|
||||
format!("{code} ({remaining}s remaining)"),
|
||||
.get(vault_idx - 1)
|
||||
.expect("The index is correct")
|
||||
);
|
||||
}
|
||||
|
||||
println!("{vault}",);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,6 @@ pub enum Error {
|
|||
InvalidVaultIndex(String),
|
||||
#[error("{0}")]
|
||||
ArgParse(String),
|
||||
#[error(
|
||||
"Reserved Prefix Error: Sorry, but the following prefix is reserved and cannot be used in \
|
||||
custom fields {0}"
|
||||
)]
|
||||
ReservedPrefix(&'static str),
|
||||
#[error("Base32 Error: {0}")]
|
||||
Base32(String),
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
|
||||
|
|
|
@ -48,8 +48,6 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||
#[cfg(feature = "update-notify")]
|
||||
/// The last version check file. Used to store the last version check time.
|
||||
pub const LAST_VERSION_CHECK_FILE: &str = ".last_version_check";
|
||||
/// The prefix of the reserved custom fields
|
||||
const RESERVED_FIELD_PREFIX: &str = ".lprsfield.";
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let lprs_cli = cli::Cli::parse();
|
||||
|
|
18
src/utils.rs
18
src/utils.rs
|
@ -45,24 +45,24 @@ pub fn local_project_file(filename: &str) -> LprsResult<PathBuf> {
|
|||
Ok(local_dir.join(filename))
|
||||
}
|
||||
|
||||
/// Returns the user secret if any
|
||||
/// Returns the user password if any
|
||||
///
|
||||
/// - If the `secret` is `None` will return `None`
|
||||
/// - If the `secret` is `Some(None)` will ask the user for a secret in the
|
||||
/// - If the `password` is `None` will return `None`
|
||||
/// - If the `password` is `Some(None)` will ask the user for a password in the
|
||||
/// stdin and return it
|
||||
/// - If the `secret` is `Some(Some(secret))` will return `Some(secret)`
|
||||
/// - If the `password` is `Some(Some(password))` will return `Some(password)`
|
||||
///
|
||||
/// ## Errors
|
||||
/// - When failed to get the secret from stdin
|
||||
pub fn user_secret(
|
||||
secret: Option<Option<String>>,
|
||||
/// - When failed to get the password from stdin
|
||||
pub fn user_password(
|
||||
password: Option<Option<String>>,
|
||||
prompt_message: &str,
|
||||
) -> LprsResult<Option<String>> {
|
||||
Ok(match secret {
|
||||
Ok(match password {
|
||||
None => None,
|
||||
Some(Some(p)) => Some(p),
|
||||
Some(None) => {
|
||||
log::debug!("User didn't provide a secret, prompting it");
|
||||
log::debug!("User didn't provide a password, prompting it");
|
||||
Some(
|
||||
Password::new(prompt_message)
|
||||
.without_confirmation()
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{cipher::TotpHash, Vault, Vaults};
|
||||
use super::{Vault, Vaults};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct BitWardenLoginData {
|
||||
|
@ -84,8 +84,6 @@ impl From<BitWardenPassword> for Vault {
|
|||
.into_iter()
|
||||
.map(|nv| (nv.name, nv.value))
|
||||
.collect(),
|
||||
None::<String>,
|
||||
TotpHash::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,63 +17,13 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
use base32::Alphabet as Base32Alphabet;
|
||||
use clap::ValueEnum;
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{LprsError, LprsResult};
|
||||
|
||||
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
|
||||
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
|
||||
|
||||
#[derive(Default, Clone, Debug, ValueEnum, Eq, PartialEq, Deserialize, Serialize)]
|
||||
/// The TOTP hash functions
|
||||
pub enum TotpHash {
|
||||
/// Sha1 hash function
|
||||
#[default]
|
||||
Sha1,
|
||||
/// Sha256 hash function
|
||||
Sha256,
|
||||
/// Sha512 hash function
|
||||
Sha512,
|
||||
}
|
||||
|
||||
|
||||
/// Create the TOTP code of the current time
|
||||
///
|
||||
/// ## Errors
|
||||
/// - If the given `secret_base32` are vaild base32
|
||||
pub fn totp_now(secret_base32: &str, hash_function: &TotpHash) -> LprsResult<(String, u8)> {
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("SystemTime before UNIX EPOCH!")
|
||||
.as_secs();
|
||||
let remaining = 30 - (now % 30) as u8;
|
||||
let secret = base32::decode(Base32Alphabet::RFC4648 { padding: true }, secret_base32)
|
||||
.ok_or_else(|| LprsError::Base32("Can't decode the TOTP secret".to_owned()))?;
|
||||
Ok(match hash_function {
|
||||
TotpHash::Sha1 => {
|
||||
(
|
||||
totp_lite::totp_custom::<totp_lite::Sha1>(30, 6, &secret, now),
|
||||
remaining,
|
||||
)
|
||||
}
|
||||
TotpHash::Sha256 => {
|
||||
(
|
||||
totp_lite::totp_custom::<totp_lite::Sha256>(30, 6, &secret, now),
|
||||
remaining,
|
||||
)
|
||||
}
|
||||
TotpHash::Sha512 => {
|
||||
(
|
||||
totp_lite::totp_custom::<totp_lite::Sha512>(30, 6, &secret, now),
|
||||
remaining,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Encrypt the given data by the given key using AES-256 CBC
|
||||
///
|
||||
/// Note: The IV will be add it to the end of the ciphertext (Last 16 bytes)
|
||||
|
|
|
@ -29,8 +29,6 @@ mod bitwarden;
|
|||
|
||||
pub use bitwarden::*;
|
||||
|
||||
use self::cipher::TotpHash;
|
||||
|
||||
#[derive(Clone, Debug, ValueEnum, Eq, PartialEq)]
|
||||
/// The vaults format
|
||||
pub enum Format {
|
||||
|
@ -63,12 +61,6 @@ pub struct Vault {
|
|||
/// The vault custom fields
|
||||
#[arg(skip)]
|
||||
pub custom_fields: BTreeMap<String, String>,
|
||||
/// The TOTP secret
|
||||
#[arg(skip)]
|
||||
pub totp_secret: Option<String>,
|
||||
/// The TOTP hash function
|
||||
#[arg(long, value_name = "HASH_FUNCTION", value_enum, default_value_t)]
|
||||
pub totp_hash: TotpHash,
|
||||
}
|
||||
|
||||
/// The vaults manager
|
||||
|
@ -84,7 +76,6 @@ pub struct Vaults {
|
|||
|
||||
impl Vault {
|
||||
/// Create new [`Vault`] instance
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
username: Option<impl Into<String>>,
|
||||
|
@ -92,8 +83,6 @@ impl Vault {
|
|||
service: Option<impl Into<String>>,
|
||||
note: Option<impl Into<String>>,
|
||||
custom_fields: BTreeMap<String, String>,
|
||||
totp_secret: Option<impl Into<String>>,
|
||||
totp_hash: TotpHash,
|
||||
) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
|
@ -102,8 +91,6 @@ impl Vault {
|
|||
service: service.map(Into::into),
|
||||
note: note.map(Into::into),
|
||||
custom_fields,
|
||||
totp_secret: totp_secret.map(Into::into),
|
||||
totp_hash,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,8 +163,6 @@ impl Vaults {
|
|||
.iter()
|
||||
.map(|(key, value)| (encrypt(key), encrypt(value)))
|
||||
.collect(),
|
||||
v.totp_secret.as_ref().map(|t| encrypt(t)),
|
||||
v.totp_hash.clone(),
|
||||
))
|
||||
})
|
||||
.collect::<LprsResult<Vec<_>>>()?,
|
||||
|
@ -214,8 +199,6 @@ impl Vaults {
|
|||
.into_iter()
|
||||
.map(|(key, value)| LprsResult::Ok((decrypt(&key)?, decrypt(&value)?)))
|
||||
.collect::<LprsResult<_>>()?,
|
||||
v.totp_secret.as_ref().and_then(|t| decrypt(t).ok()),
|
||||
v.totp_hash,
|
||||
))
|
||||
})
|
||||
.collect()
|
||||
|
@ -283,16 +266,8 @@ impl fmt::Display for Vault {
|
|||
if let Some(ref note) = self.note {
|
||||
write!(f, "\nNote:\n{note}")?;
|
||||
}
|
||||
if let Some(ref totp_secret) = self.totp_secret {
|
||||
write!(f, "\nTOTP Secret: {totp_secret}")?;
|
||||
}
|
||||
for (key, value) in &self.custom_fields {
|
||||
write!(
|
||||
f,
|
||||
"\n{}: {value}",
|
||||
key.strip_prefix(crate::RESERVED_FIELD_PREFIX)
|
||||
.unwrap_or(key)
|
||||
)?;
|
||||
write!(f, "\n{key}: {value}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue