main.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. use rand::seq::SliceRandom;
  2. use std::path::{Path};
  3. use std::fs::File;
  4. use std::io;
  5. use std::io::{BufRead, BufReader};
  6. use clap::{Arg,App};
  7. use regex::Regex;
  8. fn no_word_file() -> io::Result<String> {
  9. // Fall back to this if we cant find the word file
  10. let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGIJKLMNOPQRSTUVWXYZ0123456789!@$%^&*()-+".chars().collect();
  11. let mut password: String = String::new();
  12. for _x in 0..63 {
  13. let random_char = chars.choose(&mut rand::thread_rng());
  14. password.push_str(&random_char.unwrap().to_string());
  15. }
  16. Ok(password)
  17. }
  18. fn character_weave(passphrase: String) -> io::Result<String> {
  19. /*
  20. * a - @
  21. * i - !
  22. * o - 0
  23. * s - $
  24. * e - 3
  25. */
  26. let mut new_passphrase: String = String::new();
  27. for c in passphrase.chars() {
  28. // Probably a better way to do this as opposed to a giant if / elsif
  29. if c.to_string() == "a" {
  30. new_passphrase.push_str(&"@".to_string());
  31. } else if c.to_string() == "i" {
  32. new_passphrase.push_str(&"!".to_string());
  33. } else if c.to_string() == "o" {
  34. new_passphrase.push_str(&"0".to_string());
  35. } else if c.to_string() == "s" {
  36. new_passphrase.push_str(&"$".to_string());
  37. } else if c.to_string() == "e" {
  38. new_passphrase.push_str(&"3".to_string());
  39. } else {
  40. new_passphrase.push_str(&c.to_string());
  41. }
  42. }
  43. Ok(new_passphrase)
  44. }
  45. // This is stupid TODO
  46. fn print_password(password: String) {
  47. println!("{}",password);
  48. }
  49. fn read_phrase_file(word_file: String) -> io::Result<Vec<String>> {
  50. if ! Path::new(&word_file).exists() {
  51. println!("Could not find {}, generating a password and exiting", word_file);
  52. print_password(no_word_file().unwrap());
  53. std::process::exit(1);
  54. }
  55. let words_fh = File::open(word_file)?;
  56. let mut words = vec![];
  57. let re = Regex::new(r"^([0-9]{5})\s(.*)$").unwrap();
  58. for line in BufReader::new(words_fh).lines() {
  59. for re_capture in re.captures_iter(&line.unwrap()) {
  60. // println!("Capture 1: {}, Capture 2: {}", &re_capture[1], &re_capture[2]);
  61. // Only push word for now, need to figure out multidimentional arrays
  62. words.push(re_capture[2].to_string());
  63. }
  64. }
  65. Ok(words)
  66. }
  67. fn main() {
  68. // This variable is used as the default word file path, see Arg::with_name("words_file")
  69. // This is probably wrong/bad, and limits the functionality to Linux only
  70. let mut default_words_path = dirs::home_dir().unwrap().to_str().unwrap().to_string();
  71. default_words_path.push_str(&"/.local/bin/eff_large_wordlist.txt".to_string());
  72. let args = App::new("swmkp")
  73. .version("0.1")
  74. .about("My pw gen. Based on EFF passphrase guidelines\nhttps://www.eff.org/dice")
  75. .arg(Arg::with_name("words-file")
  76. .short("f")
  77. .long("words-file")
  78. .required(true)
  79. .takes_value(true)
  80. .default_value(&default_words_path)
  81. .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"))
  82. .arg(Arg::with_name("length")
  83. .short("l")
  84. .long("length")
  85. .required(false)
  86. .takes_value(true)
  87. .default_value("5")
  88. .help("How many words to use"))
  89. .arg(Arg::with_name("delimiter")
  90. .short("d")
  91. .long("delimiter")
  92. .required(false)
  93. .takes_value(true)
  94. .default_value("-")
  95. .help("What word delimiter to use"))
  96. .arg(Arg::with_name("with-characters")
  97. .short("w")
  98. .long("with-characters")
  99. .required(false)
  100. .takes_value(false)
  101. .help("Replaces some letters with special characters"))
  102. .arg(Arg::with_name("password")
  103. .short("p")
  104. .long("password")
  105. .required(false)
  106. .takes_value(false)
  107. .help("Generate a 64 character password, as opposed to a passphrase\nFallback here if no passphrase file provided/found"))
  108. .get_matches();
  109. if args.is_present("password") {
  110. print_password(no_word_file().unwrap());
  111. std::process::exit(0);
  112. }
  113. let roll_count: usize = args.value_of("length").unwrap().parse().unwrap();
  114. let delim: String = args.value_of("delimiter").unwrap().to_string();
  115. let words = read_phrase_file(args.value_of("words-file").unwrap().to_string()).unwrap();
  116. let mut passphrase: String = String::new();
  117. for x in 0..roll_count {
  118. let random_word = words.choose(&mut rand::thread_rng());
  119. if x == ( roll_count - 1 ) {
  120. passphrase.push_str(random_word.unwrap());
  121. } else {
  122. passphrase.push_str(random_word.unwrap());
  123. passphrase.push_str(&delim);
  124. }
  125. }
  126. if args.is_present("with-characters") {
  127. let new_passphrase = character_weave(passphrase).unwrap();
  128. println!("{}",new_passphrase);
  129. } else {
  130. println!("{}",passphrase);
  131. }
  132. }