123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- use rand::seq::SliceRandom;
- use std::path::{Path};
- use std::fs::File;
- use std::io;
- use std::io::{BufRead, BufReader};
- use clap::{Arg,App};
- use regex::Regex;
- fn no_word_file() -> io::Result<String> {
- // Fall back to this if we cant find the word file
- let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGIJKLMNOPQRSTUVWXYZ0123456789!@$%^&*()-+".chars().collect();
- let mut password: String = String::new();
- for _x in 0..63 {
- let random_char = chars.choose(&mut rand::thread_rng());
- password.push_str(&random_char.unwrap().to_string());
- }
- Ok(password)
- }
- fn character_weave(passphrase: String) -> io::Result<String> {
- /*
- * a - @
- * i - !
- * o - 0
- * s - $
- * e - 3
- */
- let mut new_passphrase: String = String::new();
- for c in passphrase.chars() {
- // Probably a better way to do this as opposed to a giant if / elsif
- if c.to_string() == "a" {
- new_passphrase.push_str(&"@".to_string());
- } else if c.to_string() == "i" {
- new_passphrase.push_str(&"!".to_string());
- } else if c.to_string() == "o" {
- new_passphrase.push_str(&"0".to_string());
- } else if c.to_string() == "s" {
- new_passphrase.push_str(&"$".to_string());
- } else if c.to_string() == "e" {
- new_passphrase.push_str(&"3".to_string());
- } else {
- new_passphrase.push_str(&c.to_string());
- }
- }
- Ok(new_passphrase)
- }
- // This is stupid TODO
- fn print_password(password: String) {
- println!("{}",password);
- }
- fn read_phrase_file(word_file: String) -> io::Result<Vec<String>> {
- if ! Path::new(&word_file).exists() {
- println!("Could not find {}, generating a password and exiting", word_file);
- print_password(no_word_file().unwrap());
- std::process::exit(1);
- }
- let words_fh = File::open(word_file)?;
- let mut words = vec![];
- let re = Regex::new(r"^([0-9]{5})\s(.*)$").unwrap();
- for line in BufReader::new(words_fh).lines() {
- for re_capture in re.captures_iter(&line.unwrap()) {
- // println!("Capture 1: {}, Capture 2: {}", &re_capture[1], &re_capture[2]);
- // Only push word for now, need to figure out multidimentional arrays
- words.push(re_capture[2].to_string());
- }
- }
- Ok(words)
- }
- fn main() {
- // This variable is used as the default word file path, see Arg::with_name("words_file")
- // This is probably wrong/bad, and limits the functionality to Linux only
- let mut default_words_path = dirs::home_dir().unwrap().to_str().unwrap().to_string();
- default_words_path.push_str(&"/.local/bin/eff_large_wordlist.txt".to_string());
- let args = App::new("swmkp")
- .version("0.1")
- .about("My pw gen. Based on EFF passphrase guidelines\nhttps://www.eff.org/dice")
- .arg(Arg::with_name("words-file")
- .short("f")
- .long("words-file")
- .required(true)
- .takes_value(true)
- .default_value(&default_words_path)
- .help("Path to passphrase file, expects file provided by EFF\nSee:\nhttps://www.eff.org/files/2016/07/18/eff_large_wordlist.txt\nhttps://eff.org/files/2016/09/08/eff_short_wordlist_1.txt\nhttps://eff.org/files/2016/09/08/eff_short_wordlist_2_0.txt\n"))
- .arg(Arg::with_name("length")
- .short("l")
- .long("length")
- .required(false)
- .takes_value(true)
- .default_value("5")
- .help("How many words to use"))
- .arg(Arg::with_name("delimiter")
- .short("d")
- .long("delimiter")
- .required(false)
- .takes_value(true)
- .default_value("-")
- .help("What word delimiter to use"))
- .arg(Arg::with_name("with-characters")
- .short("w")
- .long("with-characters")
- .required(false)
- .takes_value(false)
- .help("Replaces some letters with special characters"))
- .arg(Arg::with_name("password")
- .short("p")
- .long("password")
- .required(false)
- .takes_value(false)
- .help("Generate a 64 character password, as opposed to a passphrase\nFallback here if no passphrase file provided/found"))
- .get_matches();
- if args.is_present("password") {
- print_password(no_word_file().unwrap());
- std::process::exit(0);
- }
- let roll_count: usize = args.value_of("length").unwrap().parse().unwrap();
- let delim: String = args.value_of("delimiter").unwrap().to_string();
- let words = read_phrase_file(args.value_of("words-file").unwrap().to_string()).unwrap();
- let mut passphrase: String = String::new();
- for x in 0..roll_count {
- let random_word = words.choose(&mut rand::thread_rng());
- if x == ( roll_count - 1 ) {
- passphrase.push_str(random_word.unwrap());
- } else {
- passphrase.push_str(random_word.unwrap());
- passphrase.push_str(&delim);
- }
- }
- if args.is_present("with-characters") {
- let new_passphrase = character_weave(passphrase).unwrap();
- println!("{}",new_passphrase);
- } else {
- println!("{}",passphrase);
- }
- }
|