aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-04-11 16:03:30 -0400
committerJesse Luehrs <doy@tozt.net>2020-04-11 16:03:30 -0400
commit85e3c46466119c94724a7b48d22eda7e50538505 (patch)
tree4f18fd77b1ce19eec70023d075ea36136b3c2c9a /src
parent40a3cf1ee2124419c3c9336b5849652e74d4a00b (diff)
downloadrbw-85e3c46466119c94724a7b48d22eda7e50538505.tar.gz
rbw-85e3c46466119c94724a7b48d22eda7e50538505.zip
add password generation
Diffstat (limited to 'src')
-rw-r--r--src/bin/rbw.rs57
-rw-r--r--src/lib.rs1
-rw-r--r--src/pwgen.rs64
3 files changed, 117 insertions, 5 deletions
diff --git a/src/bin/rbw.rs b/src/bin/rbw.rs
index 9a968ff..0671080 100644
--- a/src/bin/rbw.rs
+++ b/src/bin/rbw.rs
@@ -159,10 +159,19 @@ fn add() {
todo!()
}
-fn generate() {
- ensure_agent();
+fn generate(
+ name: Option<&str>,
+ user: Option<&str>,
+ len: usize,
+ ty: rbw::pwgen::Type,
+) {
+ let pw = rbw::pwgen::pwgen(ty, len);
+ println!("{}", std::str::from_utf8(pw.data()).unwrap());
- todo!()
+ if name.is_some() && user.is_some() {
+ ensure_agent();
+ todo!();
+ }
}
fn edit() {
@@ -230,7 +239,27 @@ fn main() {
.arg(clap::Arg::with_name("user")),
)
.subcommand(clap::SubCommand::with_name("add"))
- .subcommand(clap::SubCommand::with_name("generate"))
+ .subcommand(
+ clap::SubCommand::with_name("generate")
+ .arg(clap::Arg::with_name("len").required(true))
+ .arg(clap::Arg::with_name("name"))
+ .arg(clap::Arg::with_name("user"))
+ .arg(clap::Arg::with_name("no-symbols").long("no-symbols"))
+ .arg(
+ clap::Arg::with_name("only-numbers").long("only-numbers"),
+ )
+ .arg(
+ clap::Arg::with_name("nonconfusables")
+ .long("nonconfusables"),
+ )
+ .arg(clap::Arg::with_name("diceware").long("diceware"))
+ .group(clap::ArgGroup::with_name("password-type").args(&[
+ "no-symbols",
+ "only-numbers",
+ "nonconfusables",
+ "diceware",
+ ])),
+ )
.subcommand(clap::SubCommand::with_name("edit"))
.subcommand(clap::SubCommand::with_name("remove"))
.subcommand(clap::SubCommand::with_name("lock"))
@@ -259,7 +288,25 @@ fn main() {
smatches.value_of("user"),
),
("add", Some(_)) => add(),
- ("generate", Some(_)) => generate(),
+ ("generate", Some(smatches)) => {
+ let ty = if smatches.is_present("no-symbols") {
+ rbw::pwgen::Type::NoSymbols
+ } else if smatches.is_present("only-numbers") {
+ rbw::pwgen::Type::Numbers
+ } else if smatches.is_present("nonconfusables") {
+ rbw::pwgen::Type::NonConfusables
+ } else if smatches.is_present("diceware") {
+ rbw::pwgen::Type::Diceware
+ } else {
+ rbw::pwgen::Type::AllChars
+ };
+ generate(
+ smatches.value_of("name"),
+ smatches.value_of("user"),
+ smatches.value_of("len").unwrap().parse().unwrap(),
+ ty,
+ );
+ }
("edit", Some(_)) => edit(),
("remove", Some(_)) => remove(),
("lock", Some(_)) => lock(),
diff --git a/src/lib.rs b/src/lib.rs
index d197fbb..e5d887a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,3 +17,4 @@ pub mod identity;
pub mod locked;
pub mod pinentry;
mod prelude;
+pub mod pwgen;
diff --git a/src/pwgen.rs b/src/pwgen.rs
new file mode 100644
index 0000000..656305e
--- /dev/null
+++ b/src/pwgen.rs
@@ -0,0 +1,64 @@
+use chbs::scheme::ToScheme as _;
+use rand::seq::SliceRandom as _;
+use zeroize::Zeroize as _;
+
+const SYMBOLS: &[u8] = b"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
+const NUMBERS: &[u8] = b"0123456789";
+const LETTERS: &[u8] =
+ b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+const NONCONFUSABLES: &[u8] = b"34678abcdefhjkmnpqrtuwxy";
+
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub enum Type {
+ AllChars,
+ NoSymbols,
+ Numbers,
+ NonConfusables,
+ Diceware,
+}
+
+pub fn pwgen(ty: Type, len: usize) -> crate::locked::Vec {
+ if ty == Type::Diceware {
+ let mut locked_pass = crate::locked::Vec::new();
+ let mut config = chbs::config::BasicConfig::default();
+ config.words = len;
+ config.capitalize_first = chbs::probability::Probability::Never;
+ config.capitalize_words = chbs::probability::Probability::Never;
+ let mut pass = config.to_scheme().generate();
+ locked_pass.extend(pass.as_bytes().iter().copied());
+ pass.zeroize();
+ return locked_pass;
+ }
+
+ let alphabet = match ty {
+ Type::AllChars => {
+ let mut v = vec![];
+ v.extend(SYMBOLS.iter().copied());
+ v.extend(NUMBERS.iter().copied());
+ v.extend(LETTERS.iter().copied());
+ v
+ }
+ Type::NoSymbols => {
+ let mut v = vec![];
+ v.extend(NUMBERS.iter().copied());
+ v.extend(LETTERS.iter().copied());
+ v
+ }
+ Type::Numbers => {
+ let mut v = vec![];
+ v.extend(NUMBERS.iter().copied());
+ v
+ }
+ Type::NonConfusables => {
+ let mut v = vec![];
+ v.extend(NONCONFUSABLES.iter().copied());
+ v
+ }
+ Type::Diceware => unreachable!(),
+ };
+
+ let mut rng = rand::thread_rng();
+ let mut pass = crate::locked::Vec::new();
+ pass.extend(alphabet.choose_multiple(&mut rng, len).copied());
+ pass
+}