Update and list rule sets if one is not specified

This commit is contained in:
Michael Pfaff 2025-07-21 11:08:35 -04:00
commit 8816e30252
3 changed files with 175 additions and 150 deletions

167
Cargo.lock generated
View file

@ -1,57 +1,36 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "getrandom"
version = "0.2.11"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "password-gen"
@ -64,44 +43,52 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.17"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.70"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
@ -109,27 +96,27 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.6.4"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
@ -138,18 +125,18 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "0.6.4"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
dependencies = [
"serde",
]
[[package]]
name = "syn"
version = "2.0.41"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@ -158,63 +145,81 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.8"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.21.0"
name = "toml_parser"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "winnow"
version = "0.5.30"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"memchr",
"bitflags",
]
[[patch.unused]]
name = "brisk"
version = "0.1.0"
[[package]]
name = "zerocopy"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive",
]
[[patch.unused]]
name = "how"
version = "0.3.0"
[[package]]
name = "zerocopy-derive"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -1,11 +1,9 @@
[package]
name = "password-gen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
edition = "2024"
[dependencies]
rand = "0.8.5"
serde = { version = "1.0.193", features = ["derive"] }
toml = { version = "0.8.8", default-features = false, features = ["parse"] }
rand = { version = "0.9", default-features = false, features = ["alloc", "os_rng", "std_rng"] }
serde = { version = "1", features = ["derive"] }
toml = { version = "0.9", default-features = false, features = ["parse", "serde"] }

View file

@ -4,81 +4,103 @@
extern crate serde;
use std::collections::{HashMap, HashSet};
use std::process::ExitCode;
use rand::Rng;
use rand::distributions::Slice as SliceDist;
use rand::distr::SampleString;
use rand::distr::slice::Choose;
use rand::{Rng, SeedableRng};
#[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,
},
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()
(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();
fn main() -> ExitCode {
let mut rng = rand::rngs::StdRng::from_os_rng();
let mut rule_sets: HashMap<String, RuleSet> = toml::from_str(&std::fs::read_to_string("rules.toml").unwrap()).unwrap();
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 mut args = std::env::args();
_ = args.next().unwrap();
let Some(rule_set_name) = args.next() else {
println!("Must specify a rule set name:");
for name in rule_sets.into_keys() {
println!(" {}", name);
}
return ExitCode::FAILURE;
};
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<_>>();
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);
Choose::new(&chars).unwrap().sample_string(&mut rng, length)
}
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 = Choose::new(&words).unwrap();
let delimiters = delimiters
.iter()
.map(char::to_string)
.collect::<Vec<String>>();
let delimiters = Choose::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);
ExitCode::SUCCESS
}