commit 1379e82b3df9f2496fbf72aaac3669e5c826f02a Author: FliegendeWurst <2012gdwu@web.de> Date: Thu Jan 26 12:58:31 2017 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b344318 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,302 @@ +[root] +name = "pwgenr" +version = "0.1.0" +dependencies = [ + "clap 2.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-term 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unichars 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chrono" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clap" +version = "2.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "find_folder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "isatty" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slog" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slog-extra" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "slog 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-stream" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "slog 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-extra 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-term" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", + "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-stream 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "term_size" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unichars" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-segmentation" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unreachable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vec_map" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" +"checksum clap 2.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1cb22651881e6379f4492d0d572ecb8022faef8c8aaae285bb18cb307bfa30" +"checksum find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f6d018fb95a0b59f854aed68ecd96ce2b80af7911b92b1fed3c4b1fa516b91b" +"checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b" +"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70" +"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" +"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92" +"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c" +"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753" +"checksum slog 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c68be52239f59c2d13609defb3d0848b27dc0de1f2a9cec63a13c3a8330e961d" +"checksum slog-extra 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f571614f815a4dc3aad7b9052d1e3eefd5ab76bb36efa90d4dc9ac134142b445" +"checksum slog-stream 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f0fee00b80a7a44f82c5cf44ba03b6dc2712f9c14469a62ad90ea0911635c5" +"checksum slog-term 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "042bf221ecd4f30ca35d73f390f0de260d0696eddc9bf4e3d2ffcae96a4e2e30" +"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" +"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" +"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" +"checksum thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7793b722f0f77ce716e7f1acf416359ca32ff24d04ffbac4269f44a4a83be05d" +"checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade" +"checksum unichars 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07714b6a2461cfba11db77cc67f207c001cc63f962e8c3543164770bc75f0e3a" +"checksum unicode-segmentation 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7baebdc1df1363fa66161fca2fe047e4f4209011cc7e045948298996afdf85df" +"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" +"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..021a805 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "pwgenr" +version = "0.1.0" +authors = ["FliegendeWurst <2012gdwu@web.de>"] +description = "Untypable password generator" +repository = "https://gitlab.com/Sakuhl/pwgenr/" +keywords = ["password", "generator", "unicode"] +readme = "README.md" +license = "GPL-3.0" +build = "build.rs" + +[dependencies] +clap = "^2.20" +unichars = "^0.0" +rand = "^0.3" +term_size = "^0.2" +slog-term = "^1.3" +lazy_static = "^0.2" + +[dependencies.slog] +version = "^1.4" +features = ["release_max_level_debug", + "max_level_trace"] + +[dev-dependencies] +find_folder = "^0.3" +lazy_static = "^0.2" + +[build-dependencies] +clap = "^2.20" +lazy_static = "^0.2" +unichars = "^0.0" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..6bebf02 --- /dev/null +++ b/build.rs @@ -0,0 +1,26 @@ +#[macro_use] extern crate lazy_static; + +extern crate clap; + +use clap::Shell; + +use std::env; + +include!("src/cli.rs"); + +fn main() { + let outdir = match env::var_os("OUT_DIR") { + None => return, + Some(outdir) => outdir, + }; + let mut app = build_cli(); + app.gen_completions("pwgenr", // We need to specify the bin name manually + Shell::Bash, // Then say which shell to build completions for + outdir.clone()); // Then say where write the completions to + app.gen_completions("pwgenr", + Shell::Zsh, + outdir.clone()); + app.gen_completions("pwgenr", + Shell::Fish, + outdir.clone()); +} \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..8d2e5cb --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,72 @@ +use clap::{ App, Arg }; + +extern crate unichars; +use unichars::*; + +use std::collections::HashMap; + +lazy_static! { + pub static ref CATEGORIES: HashMap<&'static str, &'static [char]> = { + let mut map = HashMap::new(); + map.insert("ascii", ASCII); + map.insert("arrows", ARROWS); + map.insert("box", BOX); + map.insert("dingbat", DINGBAT); + map.insert("games", GAMES); + map.insert("math", MATH); + map.insert("symbols", SYMBOLS); + map.insert("tech", TECH); + map + }; +} + +fn is_int(s: String) -> Result<(), String> { + s.parse::().map(|_| ()).map_err(|e| e.to_string()) +} + +pub fn build_cli() -> App<'static, 'static> { + App::new("Password generator") + .version(option_env!("CARGO_PKG_VERSION").unwrap_or("42")) + .author("FliegendeWurst <2012gdwu@web.de>") + .arg(Arg::with_name("list") + .short("l") + .long("list") + .help("Print the generated passwords in a list (default: columns)")) + .arg(Arg::with_name("column-separator") + .short("s") + .long("column-separator") + .takes_value(true) + .empty_values(true) + .conflicts_with("list") + .default_value(" ") + .help("Separator between columns")) + .arg(Arg::with_name("categories") + .short("c") + .takes_value(true) + .multiple(true) + .conflicts_with("ascii") + .possible_values(&CATEGORIES.keys().cloned().collect::>()) + .help("Categories to be used")) + .arg(Arg::with_name("clipboard") + .short("b") + .long("clipboard") + .help("Copy first password to clipboard (requires xclip)")) + .arg(Arg::with_name("ascii") + .short("a") + .long("ascii") + .help("Only use ASCII characters")) + .arg(Arg::with_name("LENGTH") + .takes_value(true) + .validator(is_int) + .default_value("64") + .help("The length of the generated passwords")) + .arg(Arg::with_name("AMOUNT") + .takes_value(true) + .validator(is_int) + .default_value("12") + .help("How many passwords should be generated")) + .arg(Arg::with_name("v") + .short("v") + .multiple(true) + .help("Set the logging level")) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..25be72f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,135 @@ +#[macro_use] extern crate lazy_static; +extern crate clap; + +extern crate unichars; +use unichars::*; + +extern crate rand; +use rand::{ OsRng, Rng }; + +extern crate term_size; + +#[macro_use] +extern crate slog; +use slog::{ LevelFilter, Level, Logger }; +extern crate slog_term; +use slog::DrainExt; + +use std::process; + +mod cli; + +fn gen_pw(alphabet: &[char], length: usize, rng: &mut OsRng) -> String { + let mut buf = String::new(); + for _ in 0..length { + let c = rng.choose(alphabet).map(|x| x.to_string()).unwrap_or_else(|| unreachable!()); + buf.push_str(&c); + } + buf +} + +fn main() { + let matches = cli::build_cli().get_matches(); + + // Create logging context based on verbosity + let verbosity = matches.occurrences_of("v") as usize; + let filter = Level::from_usize(verbosity + 3).unwrap_or(Level::Trace); + let drain = LevelFilter::new(slog_term::StreamerBuilder::new().stderr().compact().build(), filter); + let log = slog::Logger::root(drain.fuse(), o!("version" => option_env!("CARGO_PKG_VERSION").unwrap_or("42"))); + + info!(log, "Verbosity"; "level" => verbosity); + + // these unwraps are safe, since the value is required and validated above + let length = matches.value_of("LENGTH").unwrap().parse::().unwrap(); + let amount = matches.value_of("AMOUNT").unwrap().parse::().unwrap(); + let column_sep = matches.value_of("column-separator").unwrap(); + info!(log, "Passed arguments"; "length" => length, "amount" => amount, "column-separator" => column_sep); + + let alphabet = if matches.is_present("ascii") { + let mut all = Vec::new(); + all.extend(ASCII); + debug!(log, "Chosen characters"; "alphabet" => format!("{:?}", all)); + all + } else if let Some(categories) = matches.values_of("categories") { + let mut all = Vec::new(); + for category in categories { + debug!(log, "Adding category"; "name" => category); + all.extend_from_slice(cli::CATEGORIES.get(category).unwrap()); + } + debug!(log, "Chosen characters"; "alphabet" => format!("{:?}", all)); + all + } else { + let mut all = Vec::new(); + all.extend(ARROWS); + all.extend(ASCII); + all.extend(BOX); + all.extend(DINGBAT); + all.extend(ENCLOSED); + all.extend(GAMES); + all.extend(MATH); + all.extend(SYMBOLS); + all.extend(TECH); + debug!(log, "Chosen characters"; "alphabet" => format!("{:?}", all)); + all + }; + + let mut rng = OsRng::new().unwrap_or_else(|_| { crit!(log, "Couldnt instantiate randomness generator"); std::process::exit(1) }); + + let width = if matches.is_present("list") { + length + } else { + term_size::dimensions().map(|x| x.0).unwrap_or(length) + }; + info!(log, "Got dimensions"; "width" => width); + + let mut used_width = 0; + for i in 0..amount { + let pw = gen_pw(&alphabet, length, &mut rng); + let pw_len = pw.chars().count(); // str.len() measures bytes, not characters :/ + + if i != 0 { + if used_width + column_sep.len() + pw_len <= width { + print!("{}", column_sep); + used_width += column_sep.len(); + } else { + println!(); + used_width = 0; + } + } + + // copy password to clipboard + if i == 0 && matches.is_present("clipboard") { + to_clip(pw.clone(), log.new(o!("purpose" => "clipboard-copying"))); + } + + debug!(log, "Generated password"; "length" => pw_len); + if pw_len != length { + warn!(log, "Generated wrongly sized password"; "size" => pw_len); + } + print!("{}", pw); + used_width += pw_len; + } + if used_width != 0 { println!() } +} + + +fn to_clip(value: String, log: Logger) { + use std::io::*; + let _ = process::Command::new("xclip") + .arg("-selection") + .arg("clipboard") + .current_dir("/usr/bin") + .stdin(process::Stdio::piped()) + .spawn().map_err(|e| { + error!(log, "Couldn't launch xclip"; "error" => e.to_string()) + }).map(|child| { + child.stdin.or_else(|| { + error!(log, "Couldn't open stdin on child"); None + }).map(|mut outstdin| { + let mut writer = BufWriter::new(&mut outstdin); + writer.write_all(value.as_bytes()).unwrap_or_else(|e| { + error!(log, "Couldn't write to stdin on child"; "error" => e.to_string()) + }); + }) + }); +} diff --git a/tests/all.rs b/tests/all.rs new file mode 100644 index 0000000..4d444ee --- /dev/null +++ b/tests/all.rs @@ -0,0 +1,73 @@ +///! All tests assume only one password is printed per line, since we can't get the 'real' terminal width in a test +#[macro_use] extern crate lazy_static; +extern crate find_folder; +use find_folder::Search; + +extern crate unichars; +use unichars::*; + +lazy_static! { + static ref PATH: ::std::path::PathBuf = { Search::ParentsThenKids(3, 3).for_folder("target").unwrap().join(::std::path::Path::new("debug/pwgenr")) }; +} + +macro_rules! exe { + ($($arg:expr),*) => { + match ::std::process::Command::new(&*PATH) + .arg("-vv") + // Start a repetition: + $( + // Each repeat will contain the following statement, with + // $arg replaced with the corresponding expression. + .arg($arg) + )* + .output() + .expect("failed to execute process") { + ::std::process::Output { status: _, stdout: out, stderr: err } => { + let out = String::from_utf8(out).unwrap(); + let err = String::from_utf8(err).unwrap(); + println!("out\n{}\nerr\n{}", out, err); + // skip last empty line + (out.rsplit('\n').skip(1).map(|x| x.to_string()).collect::>(), err) + } + } + } +} + +#[test] +fn length_amount() { + let (out, _) = exe!("19", "15"); + assert_eq!(out.len(), 15); + for line in &out { + assert_eq!(line.chars().count(), 19); + } +} + +#[test] +fn ascii() { + let (out, _) = exe!("-a", "1", "10"); + assert_eq!(out.len(), 10); + for line in &out { + assert_eq!(line.chars().count(), 1); + for c in line.chars() { + assert!(ASCII.contains(&c)); + } + } +} + +#[test] +fn categories() { + let (out, _) = exe!("-c", "box", "arrows", "--", "16", "20"); + assert_eq!(out.len(), 20); + for line in &out { + assert_eq!(line.chars().count(), 16); + for c in line.chars() { + assert!(BOX.contains(&c) || ARROWS.contains(&c)); + } + } +} + +#[test] +fn empty() { + let (out, _) = exe!("0", "0"); + assert_eq!(out.len(), 0); +}