Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ description = "A simple utility to generate random passwords based on a user-spe
repository = "https://github.com/kostDev/genpass"
readme = "README.md"

[lib]
name = "genpass"
path = "src/lib.rs"

[[bin]]
name = "genpass"
path = "src/main.rs"

[dependencies]
rand = "0.8.5"

[profile.release]
debug = 0
codegen-units = 1
opt-level = "z"
lto = "fat"
codegen-units = 1
panic = "abort"
debug = 0
strip = true
14 changes: 14 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use std::process::exit;
use super::{
info::display_help,
consts::CMD_HELP,
};

pub fn handle_cli() {
let _args: Vec<String> = std::env::args().collect();

if _args.contains(&CMD_HELP.to_string()) {
display_help();
exit(0);
}
}
13 changes: 13 additions & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// ALL Characters
pub const LOW_CASE: &str = "abcdefghijklmnopqrstuvwxyz";
pub const UP_CASE: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
pub const NUMBERS: &str = "0123456789";
pub const SYMBOLS: &str = "#$%^*_-=+~;[<{(:&|@:)}>];~.?!";
pub const ARROWS: &str = "→←↑↓↔↕↩↪";
pub const MATH_SYMBOLS: &str = "∑∆∞∫∏√≠≈±∂";
pub const MOOD_SYMBOLS: &str = "😁😇🙂🙃🥳🤠😎";
// --------------------------
pub const DEFAULT_ARGS: [&str;4] = ["a", "aa", "s", "n"];
// --------------------------
// Command
pub const CMD_HELP: &str = "-help";
25 changes: 25 additions & 0 deletions src/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

pub fn display_help() {
println!("═════════════════════════════════════════════════════════════");
println!(" Password Generator Help ");
println!("═════════════════════════════════════════════════════════════");
println!(" Use the following options to customize your password: ");
println!(" ┌───────────────┬───────────────────────────────────────┐");
println!(" │ Option │ Description │");
println!(" ├───────────────┼───────────────────────────────────────┤");
println!(" │ a │ Lowercase letters (a-z) │");
println!(" │ aa │ Uppercase letters (A-Z) │");
println!(" │ n │ Numbers [0-9] │");
println!(" │ s │ Symbols (e.g., @, #, %, &, etc.) │");
println!(" │ r │ Arrows (→, ←, ↑, ↓, etc.) │");
println!(" │ m │ Math symbols (e.g., ∑, ∆, ∞) │");
println!(" │ mm │ Mood symbols (e.g., 😁, 🙂, 🙃) │");
println!(" │ custom │ Custom string of characters │");
println!(" └───────────────┴───────────────────────────────────────┘");
println!(" Example usage:");
println!(" genpass 16 a n s -> Generates a 16-char password with lowercase, numbers, and symbols.");
println!(" genpass 12 a aa n -> Generates a 12-char password with lowercase, uppercase, and numbers.");
println!(" genpass 20 m mm -> Generates a 20-char password with math and mood symbols.");
println!(" genpass 8 ^@_@^ -> Generates an 8-char password from your custom character set.");
println!("═════════════════════════════════════════════════════════════");
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod cli;
pub mod info;
pub mod consts;
75 changes: 34 additions & 41 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,52 @@
use rand::{Rng,seq::SliceRandom, thread_rng};
use std::iter::repeat_with;
use std::io::{stdout, stdin, Write};

const LOW_CASE: &str = "abcdefghijklmnopqrstuvwxyz";
const UP_CASE: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const SYMBOLS: &str = "#$%^*_-=+~;[<{(:&|@:)}>];~.?!";
const NUMBERS: &str = "0123456789";

const DEFAULT_ARGS: [&str;4] = ["a", "aa", "s", "n"];

fn generate_line(args: &[&str]) -> String {
let mut rng = thread_rng();
let mut list = args.iter().map(|&x| match x {
"a" => LOW_CASE,
"aa" => UP_CASE,
"s" => SYMBOLS,
"n" => NUMBERS,
use rand::{seq::{SliceRandom, IteratorRandom}, thread_rng};
use std::{
io::{ stdout, stdin, Write },
iter::repeat_with
};
use genpass::{ consts, cli };

fn create_ch_pool(args: &[&str]) -> String {
let mut pool = args.iter().map(|&x| match x {
"a" | "lower" => consts::LOW_CASE,
"aa" | "upper" => consts::UP_CASE,
"n" | "nums" => consts::NUMBERS,
"s" | "symbols" => consts::SYMBOLS,
"r" | "arrows" => consts::ARROWS,
"m" | "math" => consts::MATH_SYMBOLS,
"mm" | "mood" => consts::MOOD_SYMBOLS,
custom => custom,
}).collect::<Vec<&str>>();

list.shuffle(&mut rng);
list.concat()
pool.shuffle(&mut thread_rng());
pool.concat()
}

fn generate_pass(line: &str, max: usize) -> String {
fn create_password(pool: &str, n: usize) -> String {
let mut rng = thread_rng();
repeat_with(|| { line.chars().nth(rng.gen_range(0..line.len())).unwrap() })
.take(max)
.collect()
repeat_with(|| pool.chars().choose(&mut rng).unwrap())
.take(n).collect()
}

fn main() {
cli::handle_cli();

let mut input: String = String::new();
print!(">> ");
stdout().flush().unwrap();
stdin().read_line(&mut input).unwrap();

let input_items = input.split_whitespace().collect::<Vec<&str>>();
let tokens = input.split_whitespace().collect::<Vec<&str>>();

if input_items.len().eq(&0usize) {
eprintln!("Empty input!");
if tokens.is_empty() {
eprintln!("Empty input! Please provide a password length or/and optional character set!");
return;
}
// first arg always number
let password_len = input_items[0].parse::<usize>()
.expect("invalid value for password length!");

let args = &input_items[1..];
let line = match &args.len() {
0 => generate_line(&DEFAULT_ARGS), // default
_ => generate_line(&args), // custom [ .., .., ... ]
};
let password = generate_pass(&line, password_len);

println!("Yours generated password[{password_len}]: {password}");
// println!("Unique generated line: {}", new_line);

// first arg always number as password length
let lens = tokens[0].parse::<usize>().expect("Invalid value for password length!");
let args = &tokens[1..];
let pool = create_ch_pool(if args.is_empty() { &consts::DEFAULT_ARGS } else { args });
let password = create_password(&pool, lens);

println!("Yours generated password[{lens}]: {password}");
// println!("Unique pool: {}", pool);
}