#[macro_use]
extern crate clap;
extern crate lich;
extern crate rpassword;
extern crate serde_json;
extern crate unicode_segmentation;
use clap::ErrorKind::ArgumentNotFound;
use std::env;
use std::path::PathBuf;
use unicode_segmentation::UnicodeSegmentation;
#[macro_use]
mod common;
mod delete;
mod entry;
mod init;
mod list;
mod generate;
mod get;
mod rekey;
mod set;
fn main() {
let path = path();
let matches = clap_app!(lich =>
(version: env!("CARGO_PKG_VERSION"))
(about: env!("CARGO_PKG_DESCRIPTION"))
(@setting SubcommandRequiredElseHelp)
(@setting VersionlessSubcommands)
(@subcommand list =>
(about: "List places")
)
(@subcommand get =>
(about: "Get a password")
(@arg place: +required "The place associated with the password")
)
(@subcommand set =>
(about: "Change a password")
(@arg place: +required "The place associated with the password")
)
(@subcommand delete =>
(about: "Remove a password")
(@arg place: +required "The place associated with the password")
)
(@subcommand init =>
(about: "Initialises the password store")
)
(@subcommand rekey =>
(about: "Change the master password")
)
(@subcommand generate =>
(about: "Generate a new password")
(@arg length: -l --length +takes_value "Password length")
(@arg chars: -c --chars +takes_value "Allowed characters")
)
).get_matches();
let res = match matches.subcommand() {
("list", _) => list::run(path),
("get", Some(m)) => get::run(path, m.value_of("place").unwrap()),
("set", Some(m)) => set::run(path, m.value_of("place").unwrap()),
("delete", Some(m)) => delete::run(path, m.value_of("place").unwrap()),
("init", _) => init::run(path),
("rekey", _) => rekey::run(path),
("generate", Some(m)) => {
let length = value_t!(m, "length", usize)
.map(Some)
.unwrap_or_else(|e| match e.kind {
ArgumentNotFound => None,
_ => e.exit()
});
let chars = m.value_of("chars")
.map(|s| s.graphemes(true).collect::<Vec<_>>());
generate::run(length, chars.as_ref().map(Vec::as_slice))
},
_ => unreachable!()
};
if let Err(e) = res {
e.exit();
}
}
fn path() -> PathBuf {
match env::var_os("LICH") {
Some(path) =>
if path.len() > 0 {
path.into()
} else {
default_path()
},
None => default_path()
}
}
fn default_path() -> PathBuf {
#[cfg(windows)]
match env::var_os("APPDATA") {
Some(appdata) => {
let mut path = PathBuf::from(appdata);
path.push("lich");
path
},
None => "lich".into()
}
#[cfg(not(windows))]
match env::home_dir() {
Some(mut home) => {
home.push(".lich");
home
},
None => ".lich".into()
}
}