added simple password generator to duralumin binary
This commit is contained in:
parent
edc25af9de
commit
9e7d8c3494
|
@ -8,13 +8,14 @@ name = "libduralumin"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = ["passphrase-gen", "ed25519", "clap", "rpassword", "base64"]
|
||||
default = ["passphrase-gen", "password-gen", "ed25519", "clap", "rpassword", "base64"]
|
||||
ed25519 = ["osshkeys", "sha2"]
|
||||
passphrase-gen = []
|
||||
password-gen = []
|
||||
|
||||
[[bin]]
|
||||
name = "duralumin"
|
||||
required-features = ["passphrase-gen", "clap"]
|
||||
required-features = ["passphrase-gen", "password-gen", "clap", "clap/derive"]
|
||||
|
||||
[[bin]]
|
||||
name = "duralumin-keygen"
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use libduralumin::passphrase_gen::{PassPhraseGenerator, Words};
|
||||
use clap::{Parser, Subcommand};
|
||||
use libduralumin::{
|
||||
passphrase_gen::{PassPhraseGenerator, Words},
|
||||
password_gen::PasswordGenerator,
|
||||
};
|
||||
|
||||
/// program that generates random passphrases.
|
||||
#[derive(Parser)]
|
||||
|
@ -11,6 +14,18 @@ use libduralumin::passphrase_gen::{PassPhraseGenerator, Words};
|
|||
author = "No One <noonebtw@nirgendwo.xyz>"
|
||||
)]
|
||||
struct Opts {
|
||||
#[clap(subcommand)]
|
||||
command: Subcommands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Subcommands {
|
||||
Passphrase(PassphraseGenArgs),
|
||||
Password(PasswordGenArgs),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct PassphraseGenArgs {
|
||||
#[clap(short = 'l', long)]
|
||||
num_words: Option<i16>,
|
||||
#[clap(long)]
|
||||
|
@ -27,7 +42,35 @@ struct Opts {
|
|||
backend: String,
|
||||
}
|
||||
|
||||
impl Opts {
|
||||
#[derive(Parser)]
|
||||
struct PasswordGenArgs {
|
||||
/// number of passwords to generate
|
||||
#[clap(short = 'c', long = "count", default_value = "1")]
|
||||
count: u16,
|
||||
/// if given, generate a password with an exact length, otherwise choses a length between min and max length.
|
||||
#[clap(long = "length")]
|
||||
exact_length: Option<u16>,
|
||||
/// minimum length of the generated password
|
||||
#[clap(long = "min", default_value = "10")]
|
||||
min_length: u16,
|
||||
/// maximum length of the generated password
|
||||
#[clap(long = "max", default_value = "20")]
|
||||
max_length: u16,
|
||||
/// whether to use lowercase letters in the password
|
||||
#[clap(short = 'l', long)]
|
||||
use_letters: bool,
|
||||
/// whether to use uppercase letters in the password
|
||||
#[clap(short = 'L', long)]
|
||||
use_capital_letters: bool,
|
||||
/// whether to use numbers in the password
|
||||
#[clap(short = 'N', long)]
|
||||
use_numbers: bool,
|
||||
/// whether to use special symbols `(!"§$%$%&\/\\()=?_:;,.-*+#'\\)` in the password
|
||||
#[clap(short = 'S', long)]
|
||||
use_symbols: bool,
|
||||
}
|
||||
|
||||
impl PassphraseGenArgs {
|
||||
/// gets the number of words per passphrase
|
||||
pub fn words_per_passphrase(&self) -> i16 {
|
||||
self.num_words.unwrap_or(6)
|
||||
|
@ -76,28 +119,53 @@ impl Backend {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let opts = Opts::parse();
|
||||
let gen = PassPhraseGenerator::new()
|
||||
.with_capitalized(opts.capitalize())
|
||||
.with_min_word_length(opts.min_word_length)
|
||||
.with_length(opts.words_per_passphrase());
|
||||
let opts: Opts = Opts::parse();
|
||||
|
||||
let words = match opts.backend() {
|
||||
Some(Backend::UseAPassPhrase) => Words::from_str(include_str!("../../useapassphrase.txt")),
|
||||
Some(Backend::EnglishWords) => Words::from_str(include_str!("../../words_alpha.txt")),
|
||||
Some(path) => {
|
||||
Words::from_text_file(std::fs::File::open(path).expect("failed to read word list."))
|
||||
.expect("word list from path.")
|
||||
}
|
||||
None => {
|
||||
panic!("invalid backend.")
|
||||
}
|
||||
};
|
||||
match opts.command {
|
||||
Subcommands::Passphrase(opts) => {
|
||||
let gen = PassPhraseGenerator::new()
|
||||
.with_capitalized(opts.capitalize())
|
||||
.with_min_word_length(opts.min_word_length)
|
||||
.with_length(opts.words_per_passphrase());
|
||||
|
||||
for passphrase in gen
|
||||
.generate_n(&words, opts.passphrase_count() as usize)
|
||||
.expect("failed to generate passphrases. this is bad.")
|
||||
{
|
||||
println!("{}", passphrase);
|
||||
let words = match opts.backend() {
|
||||
Some(Backend::UseAPassPhrase) => {
|
||||
Words::from_str(include_str!("../../useapassphrase.txt"))
|
||||
}
|
||||
Some(Backend::EnglishWords) => {
|
||||
Words::from_str(include_str!("../../words_alpha.txt"))
|
||||
}
|
||||
Some(Backend::File(path)) => Words::from_text_file(
|
||||
std::fs::File::open(path).expect("failed to read word list."),
|
||||
)
|
||||
.expect("word list from path."),
|
||||
None => {
|
||||
panic!("invalid backend.")
|
||||
}
|
||||
};
|
||||
|
||||
for passphrase in gen
|
||||
.generate_n(&words, opts.passphrase_count() as usize)
|
||||
.expect("failed to generate passphrases. this is bad.")
|
||||
{
|
||||
println!("{}", passphrase);
|
||||
}
|
||||
}
|
||||
Subcommands::Password(args) => {
|
||||
let min_length = args.exact_length.unwrap_or(args.min_length);
|
||||
let max_length = args.exact_length.unwrap_or(args.max_length);
|
||||
let gen = PasswordGenerator::new(
|
||||
min_length,
|
||||
max_length,
|
||||
args.use_letters,
|
||||
args.use_capital_letters,
|
||||
args.use_numbers,
|
||||
args.use_symbols,
|
||||
);
|
||||
|
||||
for password in gen.generate_n(args.count as usize) {
|
||||
println!("{}", password);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#[cfg(feature = "passphrase-gen")]
|
||||
pub mod passphrase_gen;
|
||||
|
||||
#[cfg(feature = "password-gen")]
|
||||
pub mod password_gen;
|
||||
|
||||
#[cfg(feature = "ed25519")]
|
||||
pub mod ed25519;
|
||||
|
|
|
@ -80,11 +80,7 @@ impl PassPhraseGenerator {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn generate_n(
|
||||
&self,
|
||||
words: &Words,
|
||||
count: usize,
|
||||
) -> Option<Vec<String>> {
|
||||
pub fn generate_n(&self, words: &Words, count: usize) -> Option<Vec<String>> {
|
||||
(0..count).map(|_| self.generate(words)).collect()
|
||||
}
|
||||
|
||||
|
@ -104,10 +100,7 @@ impl PassPhraseGenerator {
|
|||
|
||||
match chars.next() {
|
||||
None => String::new(),
|
||||
Some(c) => {
|
||||
c.to_uppercase().collect::<String>()
|
||||
+ chars.as_str()
|
||||
}
|
||||
Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
|
||||
}
|
||||
} else {
|
||||
word.to_string()
|
||||
|
|
71
src/password_gen.rs
Normal file
71
src/password_gen.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use rand::{prelude::SliceRandom, rngs::OsRng, Rng};
|
||||
|
||||
const LETTERS: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
|
||||
const CAPITAL_LETTERS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const NUMBERS: &[u8] = b"0123456789";
|
||||
const SYMBOLS: &[u8] = br#" !#$%"&'()*+,-./:;<=>?@[\]^_`{|}~"#;
|
||||
|
||||
pub struct PasswordGenerator {
|
||||
min_length: u16,
|
||||
max_length: u16,
|
||||
letters: bool,
|
||||
capital_letters: bool,
|
||||
numbers: bool,
|
||||
symbols: bool,
|
||||
}
|
||||
|
||||
impl PasswordGenerator {
|
||||
pub fn new_exact_length(
|
||||
length: u16,
|
||||
letters: bool,
|
||||
capital_letters: bool,
|
||||
numbers: bool,
|
||||
symbols: bool,
|
||||
) -> Self {
|
||||
Self::new(length, length, letters, capital_letters, numbers, symbols)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
min_length: u16,
|
||||
max_length: u16,
|
||||
letters: bool,
|
||||
capital_letters: bool,
|
||||
numbers: bool,
|
||||
symbols: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
min_length,
|
||||
max_length,
|
||||
letters,
|
||||
capital_letters,
|
||||
numbers,
|
||||
symbols,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(&self) -> String {
|
||||
let length = OsRng.gen_range(self.min_length..=self.max_length) as usize;
|
||||
|
||||
let set = [
|
||||
self.letters.then(|| LETTERS.iter()),
|
||||
self.capital_letters.then(|| CAPITAL_LETTERS.iter()),
|
||||
self.numbers.then(|| NUMBERS.iter()),
|
||||
self.symbols.then(|| SYMBOLS.iter()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut bytes = std::iter::repeat_with(|| **set.choose(&mut OsRng).unwrap())
|
||||
.take(length)
|
||||
.collect::<Vec<_>>();
|
||||
bytes.shuffle(&mut OsRng);
|
||||
|
||||
String::from_utf8(bytes).expect("password bytes to utf8 string.")
|
||||
}
|
||||
|
||||
pub fn generate_n(&self, n: usize) -> Vec<String> {
|
||||
std::iter::repeat_with(|| self.generate()).take(n).collect()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue