Implement gen command, to generate samples.

This commit is contained in:
Kiyomichi Kosaka
2022-12-22 12:07:13 +00:00
parent b6c7b08320
commit e8345b374d
6 changed files with 72 additions and 6 deletions
+1
View File
@@ -22,3 +22,4 @@ rpassword = "7.2.0"
shlex = "1.1.0" shlex = "1.1.0"
shellexpand = "3.0.0" shellexpand = "3.0.0"
scopeguard = "1.1.0" scopeguard = "1.1.0"
rand = "0.8.5"
+47 -1
View File
@@ -5,10 +5,13 @@ use std::collections::{HashMap, HashSet};
use std::fs; use std::fs;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write};
use std::rc::Rc;
use std::cmp::min;
use rand::{thread_rng, Rng};
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::password::fix_password_recursion; use crate::password::fix_password_recursion;
use crate::password::{Name, PasswordRef}; use crate::password::{Name, Password, PasswordRef};
use crate::repl::LKEval; use crate::repl::LKEval;
use crate::structs::{LKOut, Radix, CORRECT_FILE, DUMP_FILE}; use crate::structs::{LKOut, Radix, CORRECT_FILE, DUMP_FILE};
use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env}; use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env};
@@ -409,4 +412,47 @@ impl<'a> LKEval<'a> {
Err(e) => out.e(format!("error: failed to write: {}", e.to_string())), Err(e) => out.e(format!("error: failed to write: {}", e.to_string())),
}; };
} }
pub fn cmd_gen(&self, out: &LKOut, num: &u32, name: &PasswordRef) {
lazy_static! {
static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap();
}
let mut rng = thread_rng();
let num: usize = (*num).try_into().unwrap();
let pwd = name.borrow();
let secret = "a".to_string();
let mut genpwds: Vec<(PasswordRef, String)> = Vec::new();
match RE.captures(pwd.name.as_ref()) {
Some(caps) => {
let gen = &caps[1];
if gen.starts_with("G") {
let name = pwd.name.trim_end_matches('G');
for num in 1..10_u32.pow(gen.len().try_into().unwrap()) {
let npwd = Password::from_password(&pwd);
npwd.borrow_mut().name = Rc::new(format!("{}{}", name, num).to_string());
let pass = npwd.borrow().encode(&secret);
genpwds.push((npwd, pass));
}
} else {
let name = gen.trim_end_matches('X');
let num = rng.gen_range(1..10_u32.pow(gen.len().try_into().unwrap()));
let npwd = Password::from_password(&pwd);
npwd.borrow_mut().name = Rc::new(format!("{}{}", name, num).to_string());
let pass = npwd.borrow().encode(&secret);
genpwds.push((npwd, pass));
}
}
None => {
let npwd = Password::from_password(&pwd);
let pass = npwd.borrow().encode(&secret);
genpwds.push((npwd, pass));
}
}
genpwds.sort_by(|a, b| b.1.len().cmp(&a.1.len()));
out.o(format!("{:>30}{:>4} {}", "Name", "Len", "Password"));
for num in (genpwds.len()-min(genpwds.len(), num))..genpwds.len() {
let (pwd, pass) = (genpwds[num].0.borrow(), genpwds[num].1.to_string());
out.o(format!("{:>30}{:>4} {}", pwd.to_string(), pass.len(), pass));
}
}
} }
+7 -1
View File
@@ -21,6 +21,7 @@ peg::parser! {
/ dump_cmd() / dump_cmd()
/ dump_def_cmd() / dump_def_cmd()
/ enc_cmd() / enc_cmd()
/ gen_cmd()
/ pass_cmd() / pass_cmd()
/ unpass_cmd() / unpass_cmd()
/ correct_cmd() / correct_cmd()
@@ -51,12 +52,14 @@ peg::parser! {
match name { Some(n) => Ok(n), None => Err("failed to parse password description") } match name { Some(n) => Ok(n), None => Err("failed to parse password description") }
} }
rule date() -> NaiveDate = y:$("-"? ['0'..='9']*<1,4>) "-" m:$(['0'..='9']*<1,2>) "-" d:$(['0'..='9']*<1,2>) {? rule ndate() -> NaiveDate = y:$("-"? ['0'..='9']*<1,4>) "-" m:$(['0'..='9']*<1,2>) "-" d:$(['0'..='9']*<1,2>) {?
let year: i32 = match y.parse() { Ok(n) => n, Err(_) => return Err("year") }; let year: i32 = match y.parse() { Ok(n) => n, Err(_) => return Err("year") };
let month: u32 = match m.parse() { Ok(n) => n, Err(_) => return Err("month") }; let month: u32 = match m.parse() { Ok(n) => n, Err(_) => return Err("month") };
let day: u32 = match d.parse() { Ok(n) => n, Err(_) => return Err("day") }; let day: u32 = match d.parse() { Ok(n) => n, Err(_) => return Err("day") };
NaiveDate::from_ymd_opt(year, month, day).ok_or("date") NaiveDate::from_ymd_opt(year, month, day).ok_or("date")
} }
rule cdate() -> NaiveDate = "now" { Local::now().naive_local().date() }
rule date() -> NaiveDate = d:(ndate() / cdate()) { d }
rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {? rule umode() -> Mode = ("U" / "u") m:$("R" / "r" / "N" / "n" / "H" / "h" / "B" / "b") {?
match m.to_uppercase().as_str() { match m.to_uppercase().as_str() {
"R" => Ok(Mode::RegularUpcase), "R" => Ok(Mode::RegularUpcase),
@@ -88,6 +91,9 @@ peg::parser! {
rule source_cmd() -> Command<'input> = "source" _ s:$(([' '..='~'])+) { Command::Source(s.to_string()) } rule source_cmd() -> Command<'input> = "source" _ s:$(([' '..='~'])+) { Command::Source(s.to_string()) }
rule ls_cmd() -> Command<'input> = "ls" f:comment()? { Command::Ls(f.unwrap_or(".".to_string())) } rule ls_cmd() -> Command<'input> = "ls" f:comment()? { Command::Ls(f.unwrap_or(".".to_string())) }
rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) } rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) }
rule gen_cmd() -> Command<'input> = "gen" n:num()? _ name:name() {
Command::Gen(match n { Some(n) => n, None => 10_u32 }, Rc::new(RefCell::new(name)))
}
rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) } rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) }
rule mv_cmd() -> Command<'input> = "mv" _ name:word() _ folder:word() { Command::Mv(name, folder) } rule mv_cmd() -> Command<'input> = "mv" _ name:word() _ folder:word() { Command::Mv(name, folder) }
rule pass_cmd() -> Command<'input> = "pass" _ name:word() { Command::Pass(name) } rule pass_cmd() -> Command<'input> = "pass" _ name:word() { Command::Pass(name) }
+13
View File
@@ -47,6 +47,19 @@ impl Password {
} }
} }
pub fn from_password(password: &Password) -> PasswordRef {
Rc::new(RefCell::new(Self {
parent: password.parent.clone(),
prefix: password.prefix.clone(),
name: password.name.clone(),
length: password.length.clone(),
mode: password.mode.clone(),
seq: password.seq,
date: password.date.clone(),
comment: password.comment.clone(),
}))
}
pub fn encode(&self, secret: &str) -> String { pub fn encode(&self, secret: &str) -> String {
let skey = SKey::new(&self.name, self.seq, secret); let skey = SKey::new(&self.name, self.seq, secret);
let (sep, len) = match (&self.length, &self.mode) { let (sep, len) = match (&self.length, &self.mode) {
+2 -3
View File
@@ -106,9 +106,8 @@ impl<'a> LKEval<'a> {
} }
None => out.e(format!("error: password {} not found", name)), None => out.e(format!("error: password {} not found", name)),
}, },
Command::Enc(name) => { Command::Enc(name) => { self.cmd_enc(&out, name); }
self.cmd_enc(&out, name); Command::Gen(num, name) => self.cmd_gen(&out, &num, &name),
}
Command::PasteBuffer(command) => self.cmd_pb(&out, command), Command::PasteBuffer(command) => self.cmd_pb(&out, command),
Command::Source(script) => self.cmd_source(&out, script), Command::Source(script) => self.cmd_source(&out, script),
Command::Dump(script) => self.cmd_dump(&out, script), Command::Dump(script) => self.cmd_dump(&out, script),
+2 -1
View File
@@ -60,6 +60,7 @@ pub enum Command<'a> {
Mv(Name, Name), Mv(Name, Name),
Rm(Name), Rm(Name),
Enc(Name), Enc(Name),
Gen(u32, PasswordRef),
Pass(Name), Pass(Name),
UnPass(Name), UnPass(Name),
Correct(Name), Correct(Name),
@@ -74,7 +75,7 @@ pub enum Command<'a> {
Quit, Quit,
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug, Clone)]
pub enum Mode { pub enum Mode {
Regular, Regular,
RegularUpcase, RegularUpcase,