password-gen/src/main.rs

85 lines
2.1 KiB
Rust

#![feature(iter_intersperse)]
#[macro_use]
extern crate serde;
use std::collections::{HashMap, HashSet};
use rand::Rng;
use rand::distributions::Slice as SliceDist;
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum RuleSet {
Password {
length: usize,
lowercase: bool,
uppercase: bool,
numbers: bool,
#[serde(default = "default_special_characters")]
special_characters: Vec<char>,
},
Passphrase {
count: usize,
delimiters: Vec<char>,
/// Path to words list.
words: String,
},
}
fn default_special_characters() -> Vec<char> {
(0..128)
.map(|b| char::from_u32(b).unwrap())
.filter(|c| c.is_ascii_graphic() && !c.is_ascii_alphanumeric())
.collect()
}
fn main() {
let mut rng = rand::thread_rng();
let mut rule_sets: HashMap<String, RuleSet> = toml::from_str(&std::fs::read_to_string("rules.toml").unwrap()).unwrap();
let mut args = std::env::args();
_ = args.next().unwrap();
let rule_set_name = args.next().expect("Must specify a rule set name");
let password = match rule_sets.remove(&rule_set_name).unwrap() {
RuleSet::Password { length, lowercase, uppercase, numbers, special_characters } => {
let mut chars = HashSet::new();
if lowercase {
chars.extend('a'..='z');
}
if uppercase {
chars.extend('A'..='Z');
}
if numbers {
chars.extend('0'..='9');
}
chars.extend(&special_characters);
let chars = chars.into_iter().collect::<Vec<_>>();
rng.sample_iter(SliceDist::new(&chars).unwrap())
.take(length)
.collect::<String>()
}
RuleSet::Passphrase { count, delimiters, words } => {
assert!(count > 0);
let words = std::fs::read_to_string(&words).unwrap();
let words = words.lines().filter(|s| !s.is_empty()).collect::<Vec<_>>();
let words = SliceDist::new(&words).unwrap();
let delimiters = delimiters.iter().map(char::to_string).collect::<Vec<String>>();
let delimiters = SliceDist::new(&delimiters).unwrap();
let mut s = String::new();
let mut word = rng.sample(&words);
for _ in 0..count-1 {
s.push_str(word);
word = rng.sample(&words);
s.push_str(rng.sample(&delimiters));
}
s.push_str(word);
s
}
};
println!("{}", password);
}