Move commands implementations to commands.rs.
This commit is contained in:
+340
@@ -0,0 +1,340 @@
|
|||||||
|
use regex::Regex;
|
||||||
|
use rpassword::prompt_password;
|
||||||
|
use sha1::{Digest, Sha1};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
|
||||||
|
use crate::repl::LKEval;
|
||||||
|
use crate::parser::command_parser;
|
||||||
|
use crate::password::{Name, PasswordRef};
|
||||||
|
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};
|
||||||
|
|
||||||
|
impl<'a> LKEval<'a> {
|
||||||
|
pub fn get_password(&self, name: &String) -> Option<PasswordRef> {
|
||||||
|
match self.state.borrow().db.get(name) {
|
||||||
|
Some(pwd) => Some(pwd.clone()),
|
||||||
|
None => match self.state.borrow().ls.get(name) {
|
||||||
|
Some(pwd) => Some(pwd.clone()),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_master(&self, out: &LKOut, pwd: PasswordRef, read: bool) -> Option<String> {
|
||||||
|
if read {
|
||||||
|
match self.read_master(&out, pwd.clone(), false) {
|
||||||
|
Some(p) => {
|
||||||
|
return Some(p);
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let parent = match &pwd.borrow().parent {
|
||||||
|
Some(p) => p.borrow().name.to_string(),
|
||||||
|
None => "/".to_string(),
|
||||||
|
};
|
||||||
|
let secret = match self.state.borrow().secrets.get(&parent) {
|
||||||
|
Some(p) => Some(p.clone()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
match (pwd.borrow().parent.clone(), secret) {
|
||||||
|
(_, Some(s)) => Some(s.to_string()),
|
||||||
|
(None, None) => {
|
||||||
|
if read {
|
||||||
|
match (self.read_password)("Master: ".to_string()) {
|
||||||
|
Ok(password) => {
|
||||||
|
let name = "/".to_string();
|
||||||
|
self.cmd_correct(&out, &name, true, Some(password.clone()));
|
||||||
|
self.state.borrow_mut().secrets.insert(name, password.clone());
|
||||||
|
Some(password)
|
||||||
|
}
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(pn), None) => {
|
||||||
|
let password = if read {
|
||||||
|
(self.read_password)(format!("Password for {}: ", pn.borrow().name)).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if password.is_some() && password.as_ref().unwrap().len() > 0 {
|
||||||
|
let name = pn.borrow().name.to_string();
|
||||||
|
self.cmd_correct(&out, &name, true, Some(password.as_ref().unwrap().clone()));
|
||||||
|
self.state.borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone());
|
||||||
|
password
|
||||||
|
} else {
|
||||||
|
match self.read_master(&out, pn.clone(), read) {
|
||||||
|
Some(master) => {
|
||||||
|
let password = pn.borrow().encode(master.as_str());
|
||||||
|
let name = pn.borrow().name.to_string();
|
||||||
|
self.cmd_correct(&out, &name, true, Some(master));
|
||||||
|
self.state.borrow_mut().secrets.insert(name, password.clone());
|
||||||
|
Some(password)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_enc(&self, out: &LKOut, name: &String) -> Option<(String, String)> {
|
||||||
|
let root_folder = "/".to_string();
|
||||||
|
let (name, pass) = if name == "/" && self.state.borrow().secrets.contains_key(&root_folder) {
|
||||||
|
(root_folder.to_string(), self.state.borrow().secrets.get(&root_folder).unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
let pwd = match self.get_password(name) {
|
||||||
|
Some(p) => p.clone(),
|
||||||
|
None => {
|
||||||
|
out.e(format!("error: name {} not found", name));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let name = pwd.borrow().name.to_string();
|
||||||
|
if self.state.borrow().secrets.contains_key(&name) {
|
||||||
|
(name.clone(), self.state.borrow().secrets.get(&name).unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
match self.read_master(&out, pwd.clone(), true) {
|
||||||
|
Some(sec) => (name.clone(), pwd.borrow().encode(sec.as_str())),
|
||||||
|
None => {
|
||||||
|
out.e(format!("error: master for {} not found", name));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if out.active() {
|
||||||
|
out.o(pass.clone());
|
||||||
|
self.cmd_correct(&out, &name, true, Some(pass.clone()));
|
||||||
|
}
|
||||||
|
Some((name, pass))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_pb(&self, out: &LKOut, command: &String) {
|
||||||
|
match command_parser::cmd(command) {
|
||||||
|
Ok(cmd) => {
|
||||||
|
let print = LKEval::new(cmd, self.state.clone(), self.read_password).eval();
|
||||||
|
let data = print.out.data();
|
||||||
|
print.out.copy_err(&out);
|
||||||
|
if data.len() > 0 {
|
||||||
|
let (copy_command, copy_cmd_args) = get_copy_command_from_env();
|
||||||
|
match call_cmd_with_input(©_command, ©_cmd_args, &data) {
|
||||||
|
Ok(s) if s.len() > 0 => {
|
||||||
|
out.o(format!(
|
||||||
|
"Copied output with the command {}, and got following output:",
|
||||||
|
copy_command
|
||||||
|
));
|
||||||
|
out.o(s.trim().to_string());
|
||||||
|
}
|
||||||
|
Ok(_) => out.o(format!("Copied output with command {}", copy_command)),
|
||||||
|
Err(e) => out.e(format!("error: failed to copy: {}", e.to_string())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => out.e(format!("error: faild to parse command {}: {}", command, e.to_string())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_source(&self, out: &LKOut, source: &String) {
|
||||||
|
let script = if source.trim().ends_with("|") {
|
||||||
|
let (cmd, args) = match get_cmd_args_from_command(source.trim().trim_end_matches('|')) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to parse command {:?}: {}", source, e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match call_cmd_with_input(&cmd, &args, "") {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to execute command {}: {}", cmd, e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let script = shellexpand::full(source).unwrap().into_owned();
|
||||||
|
match std::fs::read_to_string(script) {
|
||||||
|
Ok(script) => script,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to read file {}: {}", source, e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match command_parser::script(&script) {
|
||||||
|
Ok(cmd_list) => {
|
||||||
|
for cmd in cmd_list {
|
||||||
|
let print = LKEval::new(cmd, self.state.clone(), prompt_password).eval();
|
||||||
|
print.out.copy(&out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: {}", e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_dump(&self, out: &LKOut, script: &Option<String>) {
|
||||||
|
let script = match script {
|
||||||
|
Some(p) => p,
|
||||||
|
None => DUMP_FILE.to_str().unwrap(),
|
||||||
|
};
|
||||||
|
let script = shellexpand::full(script).unwrap().into_owned();
|
||||||
|
fn save_dump(data: &HashMap<Name, PasswordRef>, script: &String) -> std::io::Result<()> {
|
||||||
|
let file = fs::File::create(script)?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
let mut vals = data.values().map(|v| v.clone()).collect::<Vec<PasswordRef>>();
|
||||||
|
vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name));
|
||||||
|
for pwd in vals {
|
||||||
|
writeln!(writer, "add {}", pwd.borrow().to_string())?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
if script.trim().starts_with("|") {
|
||||||
|
let (cmd, args) = match get_cmd_args_from_command(script.trim().trim_start_matches('|')) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to parse command {:?}: {}", script, e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = self
|
||||||
|
.state
|
||||||
|
.borrow()
|
||||||
|
.db
|
||||||
|
.values()
|
||||||
|
.map(|v| format!("add {}", v.borrow().to_string()))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
let output = match call_cmd_with_input(&cmd, &args, data.as_str()) {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to execute command {}: {}", cmd, e.to_string()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if output.len() > 0 {
|
||||||
|
out.e(format!("Passwords dumped to command {} and got following output:", cmd));
|
||||||
|
out.o(output);
|
||||||
|
} else {
|
||||||
|
out.o(format!("Passwords dumped to command {}", cmd));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match save_dump(&self.state.borrow().db, &script) {
|
||||||
|
Ok(()) => out.o(format!("Passwords dumped to {}", script)),
|
||||||
|
Err(e) => out.e(format!("error: failed to dump passswords to {}: {}", script, e.to_string())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_ls(&self, out: &LKOut, filter: String) {
|
||||||
|
let re = match Regex::new(&filter) {
|
||||||
|
Ok(re) => re,
|
||||||
|
Err(e) => {
|
||||||
|
out.e(format!("error: failed to parse re: {:?}", e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut tmp: Vec<PasswordRef> = vec![];
|
||||||
|
for (_, name) in &self.state.borrow().db {
|
||||||
|
if re.find(&name.borrow().to_string()).is_some() {
|
||||||
|
tmp.push(name.clone());
|
||||||
|
} else if re.find(&name.borrow().name).is_some() {
|
||||||
|
tmp.push(name.clone());
|
||||||
|
} else if name.borrow().comment.is_some() && re.find(&name.borrow().comment.as_ref().unwrap()).is_some() {
|
||||||
|
tmp.push(name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name));
|
||||||
|
self.state.borrow_mut().ls.clear();
|
||||||
|
let mut counter = 1;
|
||||||
|
for pwd in tmp {
|
||||||
|
let key = Radix::new(counter, 36).unwrap().to_string();
|
||||||
|
counter += 1;
|
||||||
|
self.state.borrow_mut().ls.insert(key.clone(), pwd.clone());
|
||||||
|
out.o(format!("{:>3} {}", key, pwd.borrow().to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_correct(&self, out: &LKOut, name: &String, correct: bool, check: Option<String>) {
|
||||||
|
let (check, pwd) = match check {
|
||||||
|
Some(p) => (true, Some((name.to_string(), p))),
|
||||||
|
None => (
|
||||||
|
false,
|
||||||
|
self.cmd_enc(
|
||||||
|
&LKOut::from_lkout(
|
||||||
|
None,
|
||||||
|
match &out.err {
|
||||||
|
Some(e) => Some(e.clone()),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
&name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let (name, pwd) = match pwd {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
fn load_lines() -> std::io::Result<HashSet<String>> {
|
||||||
|
let file = fs::File::open(CORRECT_FILE.to_str().unwrap())?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let mut lines = HashSet::new();
|
||||||
|
for line in reader.lines() {
|
||||||
|
lines.insert(line?.trim().to_owned());
|
||||||
|
}
|
||||||
|
Ok(lines)
|
||||||
|
}
|
||||||
|
let mut data = match load_lines() {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(_) => HashSet::new(),
|
||||||
|
};
|
||||||
|
let mut sha1 = Sha1::new();
|
||||||
|
sha1.update(name.to_string());
|
||||||
|
sha1.update(pwd);
|
||||||
|
let encpwd = format!("{:x}", sha1.finalize());
|
||||||
|
if check {
|
||||||
|
if data.contains(&encpwd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.e(format!("warning: password {} is not marked as correct", name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if correct {
|
||||||
|
if data.contains(&encpwd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.insert(encpwd);
|
||||||
|
} else {
|
||||||
|
if !data.contains(&encpwd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.remove(&encpwd);
|
||||||
|
}
|
||||||
|
fn save_lines(data: &HashSet<String>) -> std::io::Result<()> {
|
||||||
|
let file = fs::File::create(CORRECT_FILE.to_str().unwrap())?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
for entry in data {
|
||||||
|
writeln!(writer, "{}", entry)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
match save_lines(&data) {
|
||||||
|
Ok(()) => out.o(format!(
|
||||||
|
"Hash of the password {} {} {}",
|
||||||
|
name,
|
||||||
|
if correct { "remembered to" } else { "removed from" },
|
||||||
|
CORRECT_FILE.to_str().unwrap()
|
||||||
|
)),
|
||||||
|
Err(e) => out.e(format!("error: failed to write: {}", e.to_string())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,7 +1,8 @@
|
|||||||
#[macro_use] extern crate lazy_static;
|
#[macro_use] extern crate lazy_static;
|
||||||
#[macro_use(defer)] extern crate scopeguard;
|
#[allow(unused_imports)] #[macro_use(defer)] extern crate scopeguard;
|
||||||
|
|
||||||
mod lk;
|
mod lk;
|
||||||
|
mod commands;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod password;
|
mod password;
|
||||||
mod repl;
|
mod repl;
|
||||||
|
|||||||
+2
-334
@@ -1,19 +1,12 @@
|
|||||||
use regex::Regex;
|
|
||||||
use rpassword::prompt_password;
|
use rpassword::prompt_password;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
use sha1::{Digest, Sha1};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
use std::io::{BufWriter, Write};
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::lk::LK;
|
use crate::lk::LK;
|
||||||
use crate::parser::command_parser;
|
use crate::parser::command_parser;
|
||||||
use crate::password::{fix_password_recursion, Name, PasswordRef};
|
use crate::password::fix_password_recursion;
|
||||||
use crate::structs::{Command, LKErr, LKOut, Radix, CORRECT_FILE, DUMP_FILE, HISTORY_FILE};
|
use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE};
|
||||||
use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LKRead {
|
pub struct LKRead {
|
||||||
@@ -95,331 +88,6 @@ impl<'a> LKEval<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_password(&self, name: &String) -> Option<PasswordRef> {
|
|
||||||
match self.state.borrow().db.get(name) {
|
|
||||||
Some(pwd) => Some(pwd.clone()),
|
|
||||||
None => match self.state.borrow().ls.get(name) {
|
|
||||||
Some(pwd) => Some(pwd.clone()),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_master(&self, out: &LKOut, pwd: PasswordRef, read: bool) -> Option<String> {
|
|
||||||
if read {
|
|
||||||
match self.read_master(&out, pwd.clone(), false) {
|
|
||||||
Some(p) => {
|
|
||||||
return Some(p);
|
|
||||||
}
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let parent = match &pwd.borrow().parent {
|
|
||||||
Some(p) => p.borrow().name.to_string(),
|
|
||||||
None => "/".to_string(),
|
|
||||||
};
|
|
||||||
let secret = match self.state.borrow().secrets.get(&parent) {
|
|
||||||
Some(p) => Some(p.clone()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
match (pwd.borrow().parent.clone(), secret) {
|
|
||||||
(_, Some(s)) => Some(s.to_string()),
|
|
||||||
(None, None) => {
|
|
||||||
if read {
|
|
||||||
match (self.read_password)("Master: ".to_string()) {
|
|
||||||
Ok(password) => {
|
|
||||||
let name = "/".to_string();
|
|
||||||
self.cmd_correct(&out, &name, true, Some(password.clone()));
|
|
||||||
self.state.borrow_mut().secrets.insert(name, password.clone());
|
|
||||||
Some(password)
|
|
||||||
}
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(pn), None) => {
|
|
||||||
let password = if read {
|
|
||||||
(self.read_password)(format!("Password for {}: ", pn.borrow().name)).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if password.is_some() && password.as_ref().unwrap().len() > 0 {
|
|
||||||
let name = pn.borrow().name.to_string();
|
|
||||||
self.cmd_correct(&out, &name, true, Some(password.as_ref().unwrap().clone()));
|
|
||||||
self.state.borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone());
|
|
||||||
password
|
|
||||||
} else {
|
|
||||||
match self.read_master(&out, pn.clone(), read) {
|
|
||||||
Some(master) => {
|
|
||||||
let password = pn.borrow().encode(master.as_str());
|
|
||||||
let name = pn.borrow().name.to_string();
|
|
||||||
self.cmd_correct(&out, &name, true, Some(master));
|
|
||||||
self.state.borrow_mut().secrets.insert(name, password.clone());
|
|
||||||
Some(password)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_enc(&self, out: &LKOut, name: &String) -> Option<(String, String)> {
|
|
||||||
let root_folder = "/".to_string();
|
|
||||||
let (name, pass) = if name == "/" && self.state.borrow().secrets.contains_key(&root_folder) {
|
|
||||||
(root_folder.to_string(), self.state.borrow().secrets.get(&root_folder).unwrap().to_string())
|
|
||||||
} else {
|
|
||||||
let pwd = match self.get_password(name) {
|
|
||||||
Some(p) => p.clone(),
|
|
||||||
None => {
|
|
||||||
out.e(format!("error: name {} not found", name));
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let name = pwd.borrow().name.to_string();
|
|
||||||
if self.state.borrow().secrets.contains_key(&name) {
|
|
||||||
(name.clone(), self.state.borrow().secrets.get(&name).unwrap().to_string())
|
|
||||||
} else {
|
|
||||||
match self.read_master(&out, pwd.clone(), true) {
|
|
||||||
Some(sec) => (name.clone(), pwd.borrow().encode(sec.as_str())),
|
|
||||||
None => {
|
|
||||||
out.e(format!("error: master for {} not found", name));
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if out.active() {
|
|
||||||
out.o(pass.clone());
|
|
||||||
self.cmd_correct(&out, &name, true, Some(pass.clone()));
|
|
||||||
}
|
|
||||||
Some((name, pass))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_pb(&self, out: &LKOut, command: &String) {
|
|
||||||
match command_parser::cmd(command) {
|
|
||||||
Ok(cmd) => {
|
|
||||||
let print = LKEval::new(cmd, self.state.clone(), self.read_password).eval();
|
|
||||||
let data = print.out.data();
|
|
||||||
print.out.copy_err(&out);
|
|
||||||
if data.len() > 0 {
|
|
||||||
let (copy_command, copy_cmd_args) = get_copy_command_from_env();
|
|
||||||
match call_cmd_with_input(©_command, ©_cmd_args, &data) {
|
|
||||||
Ok(s) if s.len() > 0 => {
|
|
||||||
out.o(format!(
|
|
||||||
"Copied output with the command {}, and got following output:",
|
|
||||||
copy_command
|
|
||||||
));
|
|
||||||
out.o(s.trim().to_string());
|
|
||||||
}
|
|
||||||
Ok(_) => out.o(format!("Copied output with command {}", copy_command)),
|
|
||||||
Err(e) => out.e(format!("error: failed to copy: {}", e.to_string())),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => out.e(format!("error: faild to parse command {}: {}", command, e.to_string())),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_source(&self, out: &LKOut, source: &String) {
|
|
||||||
let script = if source.trim().ends_with("|") {
|
|
||||||
let (cmd, args) = match get_cmd_args_from_command(source.trim().trim_end_matches('|')) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to parse command {:?}: {}", source, e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match call_cmd_with_input(&cmd, &args, "") {
|
|
||||||
Ok(o) => o,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to execute command {}: {}", cmd, e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let script = shellexpand::full(source).unwrap().into_owned();
|
|
||||||
match std::fs::read_to_string(script) {
|
|
||||||
Ok(script) => script,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to read file {}: {}", source, e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match command_parser::script(&script) {
|
|
||||||
Ok(cmd_list) => {
|
|
||||||
for cmd in cmd_list {
|
|
||||||
let print = LKEval::new(cmd, self.state.clone(), prompt_password).eval();
|
|
||||||
print.out.copy(&out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: {}", e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_dump(&self, out: &LKOut, script: &Option<String>) {
|
|
||||||
let script = match script {
|
|
||||||
Some(p) => p,
|
|
||||||
None => DUMP_FILE.to_str().unwrap(),
|
|
||||||
};
|
|
||||||
let script = shellexpand::full(script).unwrap().into_owned();
|
|
||||||
fn save_dump(data: &HashMap<Name, PasswordRef>, script: &String) -> std::io::Result<()> {
|
|
||||||
let file = fs::File::create(script)?;
|
|
||||||
let mut writer = BufWriter::new(file);
|
|
||||||
let mut vals = data.values().map(|v| v.clone()).collect::<Vec<PasswordRef>>();
|
|
||||||
vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name));
|
|
||||||
for pwd in vals {
|
|
||||||
writeln!(writer, "add {}", pwd.borrow().to_string())?
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
if script.trim().starts_with("|") {
|
|
||||||
let (cmd, args) = match get_cmd_args_from_command(script.trim().trim_start_matches('|')) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to parse command {:?}: {}", script, e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let data = self
|
|
||||||
.state
|
|
||||||
.borrow()
|
|
||||||
.db
|
|
||||||
.values()
|
|
||||||
.map(|v| format!("add {}", v.borrow().to_string()))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join("\n");
|
|
||||||
let output = match call_cmd_with_input(&cmd, &args, data.as_str()) {
|
|
||||||
Ok(o) => o,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to execute command {}: {}", cmd, e.to_string()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if output.len() > 0 {
|
|
||||||
out.e(format!("Passwords dumped to command {} and got following output:", cmd));
|
|
||||||
out.o(output);
|
|
||||||
} else {
|
|
||||||
out.o(format!("Passwords dumped to command {}", cmd));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match save_dump(&self.state.borrow().db, &script) {
|
|
||||||
Ok(()) => out.o(format!("Passwords dumped to {}", script)),
|
|
||||||
Err(e) => out.e(format!("error: failed to dump passswords to {}: {}", script, e.to_string())),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_ls(&self, out: &LKOut, filter: String) {
|
|
||||||
let re = match Regex::new(&filter) {
|
|
||||||
Ok(re) => re,
|
|
||||||
Err(e) => {
|
|
||||||
out.e(format!("error: failed to parse re: {:?}", e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut tmp: Vec<PasswordRef> = vec![];
|
|
||||||
for (_, name) in &self.state.borrow().db {
|
|
||||||
if re.find(&name.borrow().to_string()).is_some() {
|
|
||||||
tmp.push(name.clone());
|
|
||||||
} else if re.find(&name.borrow().name).is_some() {
|
|
||||||
tmp.push(name.clone());
|
|
||||||
} else if name.borrow().comment.is_some() && re.find(&name.borrow().comment.as_ref().unwrap()).is_some() {
|
|
||||||
tmp.push(name.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name));
|
|
||||||
self.state.borrow_mut().ls.clear();
|
|
||||||
let mut counter = 1;
|
|
||||||
for pwd in tmp {
|
|
||||||
let key = Radix::new(counter, 36).unwrap().to_string();
|
|
||||||
counter += 1;
|
|
||||||
self.state.borrow_mut().ls.insert(key.clone(), pwd.clone());
|
|
||||||
out.o(format!("{:>3} {}", key, pwd.borrow().to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_correct(&self, out: &LKOut, name: &String, correct: bool, check: Option<String>) {
|
|
||||||
let (check, pwd) = match check {
|
|
||||||
Some(p) => (true, Some((name.to_string(), p))),
|
|
||||||
None => (
|
|
||||||
false,
|
|
||||||
self.cmd_enc(
|
|
||||||
&LKOut::from_lkout(
|
|
||||||
None,
|
|
||||||
match &out.err {
|
|
||||||
Some(e) => Some(e.clone()),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
&name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let (name, pwd) = match pwd {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
fn load_lines() -> std::io::Result<HashSet<String>> {
|
|
||||||
let file = fs::File::open(CORRECT_FILE.to_str().unwrap())?;
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
let mut lines = HashSet::new();
|
|
||||||
for line in reader.lines() {
|
|
||||||
lines.insert(line?.trim().to_owned());
|
|
||||||
}
|
|
||||||
Ok(lines)
|
|
||||||
}
|
|
||||||
let mut data = match load_lines() {
|
|
||||||
Ok(d) => d,
|
|
||||||
Err(_) => HashSet::new(),
|
|
||||||
};
|
|
||||||
let mut sha1 = Sha1::new();
|
|
||||||
sha1.update(name.to_string());
|
|
||||||
sha1.update(pwd);
|
|
||||||
let encpwd = format!("{:x}", sha1.finalize());
|
|
||||||
if check {
|
|
||||||
if data.contains(&encpwd) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
out.e(format!("warning: password {} is not marked as correct", name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if correct {
|
|
||||||
if data.contains(&encpwd) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data.insert(encpwd);
|
|
||||||
} else {
|
|
||||||
if !data.contains(&encpwd) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data.remove(&encpwd);
|
|
||||||
}
|
|
||||||
fn save_lines(data: &HashSet<String>) -> std::io::Result<()> {
|
|
||||||
let file = fs::File::create(CORRECT_FILE.to_str().unwrap())?;
|
|
||||||
let mut writer = BufWriter::new(file);
|
|
||||||
for entry in data {
|
|
||||||
writeln!(writer, "{}", entry)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
match save_lines(&data) {
|
|
||||||
Ok(()) => out.o(format!(
|
|
||||||
"Hash of the password {} {} {}",
|
|
||||||
name,
|
|
||||||
if correct { "remembered to" } else { "removed from" },
|
|
||||||
CORRECT_FILE.to_str().unwrap()
|
|
||||||
)),
|
|
||||||
Err(e) => out.e(format!("error: failed to write: {}", e.to_string())),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(&self) -> LKPrint {
|
pub fn eval(&self) -> LKPrint {
|
||||||
let out = LKOut::new();
|
let out = LKOut::new();
|
||||||
let mut quit: bool = false;
|
let mut quit: bool = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user