Add export
command
This commit is contained in:
parent
7b58e9e9a6
commit
5df67e772c
4 changed files with 151 additions and 14 deletions
63
src/cli/export_command.rs
Normal file
63
src/cli/export_command.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Local CLI password 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 <https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use clap::{Args, ValueEnum};
|
||||
|
||||
use crate::{
|
||||
password::{BitWardenPasswords, Passwords},
|
||||
LprsError, LprsResult, RunCommand,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, ValueEnum)]
|
||||
pub enum ExportFormat {
|
||||
Lprs,
|
||||
BitWarden,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Export {
|
||||
/// The path to export to
|
||||
path: PathBuf,
|
||||
/// Format to export passwords in
|
||||
#[arg(short, long, value_name = "FORMAT", default_value_t= ExportFormat::Lprs)]
|
||||
format: ExportFormat,
|
||||
}
|
||||
|
||||
impl ToString for ExportFormat {
|
||||
fn to_string(&self) -> String {
|
||||
self.to_possible_value()
|
||||
.expect("There is no skiped values")
|
||||
.get_name()
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl RunCommand for Export {
|
||||
fn run(&self, password_manager: Passwords) -> LprsResult<()> {
|
||||
let exported_data = match self.format {
|
||||
ExportFormat::Lprs => serde_json::to_string(&password_manager.encrypt()?.passwords),
|
||||
ExportFormat::BitWarden => {
|
||||
serde_json::to_string(&BitWardenPasswords::from(password_manager))
|
||||
}
|
||||
}
|
||||
.map_err(LprsError::from)?;
|
||||
|
||||
fs::write(&self.path, exported_data).map_err(LprsError::from)
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ use crate::{
|
|||
pub mod add_command;
|
||||
pub mod clean_command;
|
||||
pub mod edit_command;
|
||||
pub mod export_command;
|
||||
pub mod gen_command;
|
||||
pub mod list_command;
|
||||
pub mod remove_command;
|
||||
|
@ -38,6 +39,7 @@ crate::create_commands!(
|
|||
"Clean the password file", Clean => clean_command::Clean
|
||||
"Edit the password content", Edit => edit_command::Edit
|
||||
"Generate password", Gen => gen_command::Gen
|
||||
"Export the passwords", Export => export_command::Export
|
||||
// TODO: Export command
|
||||
// TODO: Import command
|
||||
);
|
||||
|
|
71
src/password/bitwarden.rs
Normal file
71
src/password/bitwarden.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Password, Passwords};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct BitWardenLoginData {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub uris: Option<Vec<BitWardenUri>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct BitWardenUri {
|
||||
#[serde(rename = "match")]
|
||||
pub mt: Option<i32>,
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub struct BitWardenFolder {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct BitWardenPassword {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: i32,
|
||||
pub name: String,
|
||||
pub login: BitWardenLoginData,
|
||||
pub notes: Option<String>,
|
||||
}
|
||||
|
||||
/// The bitwarden password struct
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub struct BitWardenPasswords {
|
||||
pub encrypted: bool,
|
||||
pub folders: Vec<BitWardenFolder>,
|
||||
pub items: Vec<BitWardenPassword>,
|
||||
}
|
||||
|
||||
impl From<Password> for BitWardenPassword {
|
||||
fn from(value: Password) -> Self {
|
||||
Self {
|
||||
ty: 1,
|
||||
name: value.name,
|
||||
login: BitWardenLoginData {
|
||||
username: value.username,
|
||||
password: value.password,
|
||||
uris: value
|
||||
.service
|
||||
.map(|s| vec![BitWardenUri { mt: None, uri: s }]),
|
||||
},
|
||||
notes: value.note,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Passwords> for BitWardenPasswords {
|
||||
fn from(value: Passwords) -> Self {
|
||||
Self {
|
||||
encrypted: false,
|
||||
folders: Vec::new(),
|
||||
items: value
|
||||
.passwords
|
||||
.into_iter()
|
||||
.map(BitWardenPassword::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,23 +22,13 @@ use serde::{Deserialize, Serialize};
|
|||
use crate::{LprsError, LprsResult};
|
||||
|
||||
pub mod cipher;
|
||||
|
||||
mod bitwarden;
|
||||
mod validator;
|
||||
|
||||
pub use bitwarden::*;
|
||||
pub use validator::*;
|
||||
|
||||
/// The passwords manager
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub struct Passwords {
|
||||
/// Hash of the master password
|
||||
#[serde(skip)]
|
||||
pub master_password: Vec<u8>,
|
||||
/// The json passwords file
|
||||
#[serde(skip)]
|
||||
pub passwords_file: PathBuf,
|
||||
/// The passwords
|
||||
pub passwords: Vec<Password>,
|
||||
}
|
||||
|
||||
/// The password struct
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Parser)]
|
||||
|
@ -60,6 +50,17 @@ pub struct Password {
|
|||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
/// The passwords manager
|
||||
#[derive(Default)]
|
||||
pub struct Passwords {
|
||||
/// Hash of the master password
|
||||
pub master_password: Vec<u8>,
|
||||
/// The json passwords file
|
||||
pub passwords_file: PathBuf,
|
||||
/// The passwords
|
||||
pub passwords: Vec<Password>,
|
||||
}
|
||||
|
||||
impl Password {
|
||||
/// Encrypt the password data
|
||||
pub fn encrypt(self, master_password: &[u8]) -> LprsResult<Self> {
|
||||
|
@ -111,7 +112,7 @@ impl Passwords {
|
|||
}
|
||||
|
||||
/// Encrypt the passwords
|
||||
fn encrypt(self) -> LprsResult<Self> {
|
||||
pub fn encrypt(self) -> LprsResult<Self> {
|
||||
Ok(Self {
|
||||
passwords: self
|
||||
.passwords
|
||||
|
|
Loading…
Reference in a new issue