Switch from Rc<RefCell> to Arc<Mutex<T>> or Arc<ReentrantMutex<RefCell<T>>>.

This commit is contained in:
Oleksandr Kozachuk
2023-01-06 13:12:58 +01:00
parent a2978c1230
commit 538a32a471
13 changed files with 384 additions and 214 deletions
+1
View File
@@ -22,6 +22,7 @@ base64 = "0.20.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"
parking_lot = { version = "0.12.1", features = ["deadlock_detection"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
chrono = "0.4.23" chrono = "0.4.23"
+76 -71
View File
@@ -11,14 +11,14 @@ use crate::password::fix_password_recursion;
use crate::password::{Name, Password, 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, rnd};
use crate::utils::editor::password; use crate::utils::editor::password;
use crate::utils::{call_cmd_with_input, get_cmd_args_from_command, get_copy_command_from_env, rnd};
impl<'a> LKEval<'a> { impl<'a> LKEval<'a> {
pub fn get_password(&self, name: &String) -> Option<PasswordRef> { pub fn get_password(&self, name: &String) -> Option<PasswordRef> {
match self.state.borrow().ls.get(name) { match self.state.lock().borrow().ls.get(name) {
Some(pwd) => Some(pwd.clone()), Some(pwd) => Some(pwd.clone()),
None => match self.state.borrow().db.get(name) { None => match self.state.lock().borrow().db.get(name) {
Some(pwd) => Some(pwd.clone()), Some(pwd) => Some(pwd.clone()),
None => None, None => None,
}, },
@@ -34,15 +34,15 @@ impl<'a> LKEval<'a> {
None => (), None => (),
} }
} }
let parent = match &pwd.borrow().parent { let parent = match &pwd.lock().borrow().parent {
Some(p) => p.borrow().name.to_string(), Some(p) => p.lock().borrow().name.to_string(),
None => "/".to_string(), None => "/".to_string(),
}; };
let secret = match self.state.borrow().secrets.get(&parent) { let secret = match self.state.lock().borrow().secrets.get(&parent) {
Some(p) => Some(p.clone()), Some(p) => Some(p.clone()),
None => None, None => None,
}; };
match (pwd.borrow().parent.clone(), secret) { match (pwd.lock().borrow().parent.clone(), secret) {
(_, Some(s)) => Some(s.to_string()), (_, Some(s)) => Some(s.to_string()),
(None, None) => { (None, None) => {
if read { if read {
@@ -50,7 +50,7 @@ impl<'a> LKEval<'a> {
Ok(password) => { Ok(password) => {
let name = "/".to_string(); let name = "/".to_string();
self.cmd_correct(&out, &name, true, Some(password.clone())); self.cmd_correct(&out, &name, true, Some(password.clone()));
self.state.borrow_mut().secrets.insert(name, password.clone()); self.state.lock().borrow_mut().secrets.insert(name, password.clone());
Some(password) Some(password)
} }
Err(_) => None, Err(_) => None,
@@ -61,22 +61,22 @@ impl<'a> LKEval<'a> {
} }
(Some(pn), None) => { (Some(pn), None) => {
let password = if read { let password = if read {
(self.read_password)(format!("Password for {}: ", pn.borrow().name)).ok() (self.read_password)(format!("Password for {}: ", pn.lock().borrow().name)).ok()
} else { } else {
None None
}; };
if password.is_some() && password.as_ref().unwrap().len() > 0 { if password.is_some() && password.as_ref().unwrap().len() > 0 {
let name = pn.borrow().name.to_string(); let name = pn.lock().borrow().name.to_string();
self.cmd_correct(&out, &name, true, Some(password.as_ref().unwrap().clone())); self.cmd_correct(&out, &name, true, Some(password.as_ref().unwrap().clone()));
self.state.borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone()); self.state.lock().borrow_mut().secrets.insert(name, password.as_ref().unwrap().clone());
password password
} else { } else {
match self.read_master(&out, pn.clone(), read) { match self.read_master(&out, pn.clone(), read) {
Some(master) => { Some(master) => {
let password = pn.borrow().encode(master.as_str()); let password = pn.lock().borrow().encode(master.as_str());
let name = pn.borrow().name.to_string(); let name = pn.lock().borrow().name.to_string();
self.cmd_correct(&out, &name, true, Some(password.to_string())); self.cmd_correct(&out, &name, true, Some(password.to_string()));
self.state.borrow_mut().secrets.insert(name, password.clone()); self.state.lock().borrow_mut().secrets.insert(name, password.clone());
Some(password) Some(password)
} }
None => None, None => None,
@@ -87,15 +87,15 @@ impl<'a> LKEval<'a> {
} }
pub fn cmd_add(&self, out: &LKOut, name: &PasswordRef) { pub fn cmd_add(&self, out: &LKOut, name: &PasswordRef) {
let state = &mut self.state.borrow_mut(); let state_cell = self.state.lock();
let mut state = state_cell.borrow_mut();
let mut fix = false; let mut fix = false;
{ {
let db = &mut state.db; let pwname = &name.lock().borrow().name.to_string();
let pwname = &name.borrow().name.to_string(); if state.db.get(pwname).is_some() {
if db.get(pwname).is_some() {
out.e(format!("error: password {} already exist", pwname)); out.e(format!("error: password {} already exist", pwname));
} else { } else {
db.insert(pwname.to_string(), name.clone()); state.db.insert(pwname.to_string(), name.clone());
fix = true; fix = true;
} }
} }
@@ -105,9 +105,12 @@ impl<'a> LKEval<'a> {
} }
pub fn cmd_leave(&self, out: &LKOut, name: &Name) { pub fn cmd_leave(&self, out: &LKOut, name: &Name) {
let pwd = match self.state.borrow().ls.get(name) { let pwd = match self.state.lock().borrow().ls.get(name) {
Some(pwd) => pwd.clone(), Some(pwd) => pwd.clone(),
None => { out.e(format!("error: {} not found", name)); return; } None => {
out.e(format!("error: {} not found", name));
return;
}
}; };
self.cmd_add(&out, &pwd); self.cmd_add(&out, &pwd);
} }
@@ -116,11 +119,11 @@ impl<'a> LKEval<'a> {
match self.get_password(name) { match self.get_password(name) {
Some(pwd) => { Some(pwd) => {
if folder == "/" { if folder == "/" {
pwd.borrow_mut().parent = None pwd.lock().borrow_mut().parent = None
} else { } else {
match self.get_password(folder) { match self.get_password(folder) {
Some(fld) => { Some(fld) => {
pwd.borrow_mut().parent = Some(fld.clone()); pwd.lock().borrow_mut().parent = Some(fld.clone());
fix_password_recursion(pwd.clone()); fix_password_recursion(pwd.clone());
} }
None => out.e(format!("error: folder {} not found", folder)), None => out.e(format!("error: folder {} not found", folder)),
@@ -134,18 +137,15 @@ impl<'a> LKEval<'a> {
pub fn cmd_pass(&self, out: &LKOut, name: &String) { pub fn cmd_pass(&self, out: &LKOut, name: &String) {
match self.get_password(name) { match self.get_password(name) {
Some(p) => { Some(p) => {
let pwd = (self.read_password)(format!("Password for {}: ", p.borrow().name)).unwrap(); let pwd = (self.read_password)(format!("Password for {}: ", p.lock().borrow().name)).unwrap();
self.cmd_correct(&out, &p.borrow().name, true, Some(pwd.clone())); self.cmd_correct(&out, &p.lock().borrow().name, true, Some(pwd.clone()));
self.state.borrow_mut().secrets.insert(p.borrow().name.to_string(), pwd); self.state.lock().borrow_mut().secrets.insert(p.lock().borrow().name.to_string(), pwd);
} }
None => { None => {
if name == "/" { if name == "/" {
let pwd = (self.read_password)("Master: ".to_string()).unwrap(); let pwd = (self.read_password)("Master: ".to_string()).unwrap();
self.cmd_correct(&out, &"/".to_string(), true, Some(pwd.clone())); self.cmd_correct(&out, &"/".to_string(), true, Some(pwd.clone()));
self.state self.state.lock().borrow_mut().secrets.insert("/".to_string(), pwd);
.borrow_mut()
.secrets
.insert("/".to_string(), pwd);
} else { } else {
out.e(format!("error: password with name {} not found", name)); out.e(format!("error: password with name {} not found", name));
} }
@@ -156,7 +156,7 @@ impl<'a> LKEval<'a> {
pub fn cmd_comment(&self, out: &LKOut, name: &String, comment: &Option<String>) { pub fn cmd_comment(&self, out: &LKOut, name: &String, comment: &Option<String>) {
match self.get_password(name) { match self.get_password(name) {
Some(pwd) => { Some(pwd) => {
pwd.borrow_mut().comment = match comment { pwd.lock().borrow_mut().comment = match comment {
Some(c) => Some(c.to_string()), Some(c) => Some(c.to_string()),
None => None, None => None,
} }
@@ -167,8 +167,8 @@ impl<'a> LKEval<'a> {
pub fn cmd_enc(&self, out: &LKOut, name: &String) -> Option<(String, String)> { pub fn cmd_enc(&self, out: &LKOut, name: &String) -> Option<(String, String)> {
let root_folder = "/".to_string(); let root_folder = "/".to_string();
let (name, pass) = if name == "/" && self.state.borrow().secrets.contains_key(&root_folder) { let (name, pass) = if name == "/" && self.state.lock().borrow().secrets.contains_key(&root_folder) {
(root_folder.to_string(), self.state.borrow().secrets.get(&root_folder).unwrap().to_string()) (root_folder.to_string(), self.state.lock().borrow().secrets.get(&root_folder).unwrap().to_string())
} else { } else {
let pwd = match self.get_password(name) { let pwd = match self.get_password(name) {
Some(p) => p.clone(), Some(p) => p.clone(),
@@ -177,12 +177,12 @@ impl<'a> LKEval<'a> {
return None; return None;
} }
}; };
let name = pwd.borrow().name.to_string(); let name = pwd.lock().borrow().name.to_string();
if self.state.borrow().secrets.contains_key(&name) { if self.state.lock().borrow().secrets.contains_key(&name) {
(name.clone(), self.state.borrow().secrets.get(&name).unwrap().to_string()) (name.clone(), self.state.lock().borrow().secrets.get(&name).unwrap().to_string())
} else { } else {
match self.read_master(&out, pwd.clone(), true) { match self.read_master(&out, pwd.clone(), true) {
Some(sec) => (name.clone(), pwd.borrow().encode(sec.as_str())), Some(sec) => (name.clone(), pwd.lock().borrow().encode(sec.as_str())),
None => { None => {
out.e(format!("error: master for {} not found", name)); out.e(format!("error: master for {} not found", name));
return None; return None;
@@ -253,7 +253,9 @@ impl<'a> LKEval<'a> {
for cmd in cmd_list { for cmd in cmd_list {
let print = LKEval::new(cmd, self.state.clone(), password).eval(); let print = LKEval::new(cmd, self.state.clone(), password).eval();
print.out.copy(&out); print.out.copy(&out);
if print.quit { return true; } if print.quit {
return true;
}
} }
} }
Err(e) => { Err(e) => {
@@ -273,9 +275,9 @@ impl<'a> LKEval<'a> {
let file = fs::File::create(script)?; let file = fs::File::create(script)?;
let mut writer = BufWriter::new(file); let mut writer = BufWriter::new(file);
let mut vals = data.values().map(|v| v.clone()).collect::<Vec<PasswordRef>>(); let mut vals = data.values().map(|v| v.clone()).collect::<Vec<PasswordRef>>();
vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name)); vals.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name));
for pwd in vals { for pwd in vals {
writeln!(writer, "add {}", pwd.borrow().to_string())? writeln!(writer, "add {}", pwd.lock().borrow().to_string())?
} }
Ok(()) Ok(())
} }
@@ -289,10 +291,11 @@ impl<'a> LKEval<'a> {
}; };
let data = self let data = self
.state .state
.lock()
.borrow() .borrow()
.db .db
.values() .values()
.map(|v| format!("add {}", v.borrow().to_string())) .map(|v| format!("add {}", v.lock().borrow().to_string()))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
let output = match call_cmd_with_input(&cmd, &args, data.as_str()) { let output = match call_cmd_with_input(&cmd, &args, data.as_str()) {
@@ -309,13 +312,13 @@ impl<'a> LKEval<'a> {
out.o(format!("Passwords saved to command {}", cmd)); out.o(format!("Passwords saved to command {}", cmd));
} }
} else if script.trim() == "-" { } else if script.trim() == "-" {
let mut vals = (&self.state.borrow().db).values().map(|v| v.clone()).collect::<Vec<PasswordRef>>(); let mut vals = (&self.state.lock().borrow().db).values().map(|v| v.clone()).collect::<Vec<PasswordRef>>();
vals.sort_by(|a, b| a.borrow().name.cmp(&b.borrow().name)); vals.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name));
for pwd in vals { for pwd in vals {
out.o(format!("add {}", pwd.borrow().to_string())) out.o(format!("add {}", pwd.lock().borrow().to_string()))
}; }
} else { } else {
match save_dump(&self.state.borrow().db, &script) { match save_dump(&self.state.lock().borrow().db, &script) {
Ok(()) => out.o(format!("Passwords saved to file {}", script)), Ok(()) => out.o(format!("Passwords saved to file {}", script)),
Err(e) => out.e(format!("error: failed to dump passswords to {}: {}", script, e.to_string())), Err(e) => out.e(format!("error: failed to dump passswords to {}: {}", script, e.to_string())),
}; };
@@ -334,24 +337,26 @@ impl<'a> LKEval<'a> {
} }
}; };
let mut tmp: Vec<PasswordRef> = vec![]; let mut tmp: Vec<PasswordRef> = vec![];
for (_, name) in &self.state.borrow().db { for (_, name) in &self.state.lock().borrow().db {
if re.find(&name.borrow().to_string()).is_some() { if re.find(&name.lock().borrow().to_string()).is_some() {
tmp.push(name.clone()); tmp.push(name.clone());
} else if re.find(&name.borrow().name).is_some() { } else if re.find(&name.lock().borrow().name).is_some() {
tmp.push(name.clone()); tmp.push(name.clone());
} else if name.borrow().comment.is_some() && re.find(&name.borrow().comment.as_ref().unwrap()).is_some() { } else if name.lock().borrow().comment.is_some()
&& re.find(&name.lock().borrow().comment.as_ref().unwrap()).is_some()
{
tmp.push(name.clone()); tmp.push(name.clone());
} }
} }
tmp.sort_by(|a,b| a.borrow().name.cmp(&b.borrow().name)); tmp.sort_by(|a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name));
tmp.sort_by(sort_by); tmp.sort_by(sort_by);
self.state.borrow_mut().ls.clear(); self.state.lock().borrow_mut().ls.clear();
let mut counter = 1; let mut counter = 1;
for pwd in tmp { for pwd in tmp {
let key = Radix::new(counter, 36).unwrap().to_string(); let key = Radix::new(counter, 36).unwrap().to_string();
counter += 1; counter += 1;
self.state.borrow_mut().ls.insert(key.clone(), pwd.clone()); self.state.lock().borrow_mut().ls.insert(key.clone(), pwd.clone());
out.o(format!("{:>3} {}", key, pwd.borrow().to_string())); out.o(format!("{:>3} {}", key, pwd.lock().borrow().to_string()));
} }
} }
@@ -435,42 +440,42 @@ impl<'a> LKEval<'a> {
static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap(); static ref RE: Regex = Regex::new(r"^.+?(G+|X+)$").unwrap();
} }
let num: usize = (*num).try_into().unwrap(); let num: usize = (*num).try_into().unwrap();
let pwd = name.borrow(); let pwd = name.lock();
let mut genpwds: Vec<PasswordRef> = Vec::new(); let mut genpwds: Vec<PasswordRef> = Vec::new();
match RE.captures(pwd.name.as_ref()) { match RE.captures(pwd.borrow().name.as_ref()) {
Some(caps) => { Some(caps) => {
let gen = &caps[1]; let gen = &caps[1];
if gen.starts_with("G") { if gen.starts_with("G") {
let name = pwd.name.trim_end_matches('G'); let name = pwd.borrow().name.trim_end_matches('G').to_string();
for num in 1..10_u32.pow(gen.len().try_into().unwrap()) { for num in 1..10_u32.pow(gen.len().try_into().unwrap()) {
let npwd = Password::from_password(&pwd); let npwd = Password::from_password_ref(&pwd.borrow());
npwd.borrow_mut().name = format!("{}{}", name, num).to_string(); npwd.lock().borrow_mut().name = format!("{}{}", name, num).to_string();
genpwds.push(npwd); genpwds.push(npwd);
} }
} else { } else {
let name = pwd.name.trim_end_matches('X'); let name = pwd.borrow().name.trim_end_matches('X').to_string();
let num = rnd::range(1, 10_u32.pow(gen.len().try_into().unwrap())); let num = rnd::range(1, 10_u32.pow(gen.len().try_into().unwrap()));
let npwd = Password::from_password(&pwd); let npwd = Password::from_password_ref(&pwd.borrow());
npwd.borrow_mut().name = format!("{}{}", name, num).to_string(); npwd.lock().borrow_mut().name = format!("{}{}", name, num).to_string();
genpwds.push(npwd); genpwds.push(npwd);
} }
} }
None => { None => {
let npwd = Password::from_password(&pwd); let npwd = Password::from_password_ref(&pwd.borrow());
genpwds.push(npwd); genpwds.push(npwd);
} }
} }
self.state.borrow_mut().ls.clear(); self.state.lock().borrow_mut().ls.clear();
let mut counter = 1; let mut counter = 1;
let mut lspwds: Vec<(PasswordRef, String)> = Vec::new(); let mut lspwds: Vec<(PasswordRef, String)> = Vec::new();
for num in 0..genpwds.len() { for num in 0..genpwds.len() {
let pwd = genpwds[num].clone(); let pwd = genpwds[num].clone();
let key = Radix::new(counter, 36).unwrap().to_string(); let key = Radix::new(counter, 36).unwrap().to_string();
counter += 1; counter += 1;
self.state.borrow_mut().ls.insert(key.to_string(), pwd.clone()); self.state.lock().borrow_mut().ls.insert(key.to_string(), pwd.clone());
lspwds.push((pwd, key)); lspwds.push((pwd, key));
} }
self.state.borrow().fix_hierarchy(); self.state.lock().borrow().fix_hierarchy();
let mut err = match &out.err { let mut err = match &out.err {
Some(e) => Some(e.clone()), Some(e) => Some(e.clone()),
None => None, None => None,
@@ -479,8 +484,8 @@ impl<'a> LKEval<'a> {
for (pwd, key) in lspwds { for (pwd, key) in lspwds {
let pass = match self.cmd_enc(&LKOut::from_lkout(None, err), &key) { let pass = match self.cmd_enc(&LKOut::from_lkout(None, err), &key) {
Some((name, pass)) => { Some((name, pass)) => {
if name != pwd.borrow().name { if name != pwd.lock().borrow().name {
panic!("INTERNAL_ERROR: wrong name found: {} != {}", name, pwd.borrow().name); panic!("INTERNAL_ERROR: wrong name found: {} != {}", name, pwd.lock().borrow().name);
}; };
pass pass
} }
@@ -493,15 +498,15 @@ impl<'a> LKEval<'a> {
encpwds.push((pwd.clone(), pass)); encpwds.push((pwd.clone(), pass));
} }
encpwds.sort_by(|a, b| b.1.len().cmp(&a.1.len())); encpwds.sort_by(|a, b| b.1.len().cmp(&a.1.len()));
self.state.borrow_mut().ls.clear(); self.state.lock().borrow_mut().ls.clear();
let mut counter = 1; let mut counter = 1;
out.o(format!("{:>3} {:>36} {:>4} {}", "", "Password", "Len", "Name")); out.o(format!("{:>3} {:>36} {:>4} {}", "", "Password", "Len", "Name"));
for num in (encpwds.len() - min(genpwds.len(), num))..encpwds.len() { for num in (encpwds.len() - min(genpwds.len(), num))..encpwds.len() {
let (pwd, pass) = (encpwds[num].0.clone(), encpwds[num].1.to_string()); let (pwd, pass) = (encpwds[num].0.clone(), encpwds[num].1.to_string());
let key = Radix::new(counter, 36).unwrap().to_string(); let key = Radix::new(counter, 36).unwrap().to_string();
counter += 1; counter += 1;
self.state.borrow_mut().ls.insert(key.clone(), pwd.clone()); self.state.lock().borrow_mut().ls.insert(key.clone(), pwd.clone());
out.o(format!("{:>3} {:>36} {:>4} {}", key, pass, pass.len(), pwd.borrow().to_string())); out.o(format!("{:>3} {:>36} {:>4} {}", key, pass, pass.len(), pwd.lock().borrow().to_string()));
} }
} }
} }
-1
View File
@@ -12,4 +12,3 @@ pub mod repl;
pub mod skey; pub mod skey;
pub mod structs; pub mod structs;
pub mod utils; pub mod utils;
+28 -4
View File
@@ -1,8 +1,13 @@
use crate::password::{fix_password_recursion, Name, PasswordRef}; use crate::password::{fix_password_recursion, Name, PasswordRef};
use parking_lot::ReentrantMutex;
use regex::{Captures, Regex}; use regex::{Captures, Regex};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc;
#[derive(PartialEq, Debug)] pub type LKRef = Arc<ReentrantMutex<RefCell<LK>>>;
#[derive(Debug)]
pub struct LK { pub struct LK {
pub db: HashMap<Name, PasswordRef>, pub db: HashMap<Name, PasswordRef>,
pub ls: HashMap<String, PasswordRef>, pub ls: HashMap<String, PasswordRef>,
@@ -24,7 +29,7 @@ impl LK {
} }
for db in vec![&self.db, &self.ls] { for db in vec![&self.db, &self.ls] {
for (_, name) in db { for (_, name) in db {
let comment = name.borrow().comment.clone(); let comment = name.lock().borrow().comment.clone();
match comment { match comment {
Some(comment) => { Some(comment) => {
let mut changed = false; let mut changed = false;
@@ -33,7 +38,7 @@ impl LK {
let folder = c[1].to_string(); let folder = c[1].to_string();
match self.db.get(&folder) { match self.db.get(&folder) {
Some(entry) => { Some(entry) => {
name.borrow_mut().parent = Some(entry.clone()); name.lock().borrow_mut().parent = Some(entry.clone());
changed = true; changed = true;
} }
None => (), None => (),
@@ -43,7 +48,7 @@ impl LK {
.trim() .trim()
.to_string(); .to_string();
if changed && new != comment { if changed && new != comment {
name.borrow_mut().comment = if new.len() > 0 { Some(new) } else { None } name.lock().borrow_mut().comment = if new.len() > 0 { Some(new) } else { None }
} }
} }
None => (), None => (),
@@ -53,3 +58,22 @@ impl LK {
} }
} }
} }
impl PartialEq for LK {
fn eq(&self, other: &Self) -> bool {
if self.db.len() != other.db.len() || self.ls.len() != other.ls.len() || self.secrets != other.secrets {
return false;
}
for (k, v) in &self.db {
if !other.db.contains_key(k) || *other.db[k].lock() != *v.lock() {
return false;
}
}
for (k, v) in &self.ls {
if !other.ls.contains_key(k) || *other.ls[k].lock() != *v.lock() {
return false;
}
}
true
}
}
+20 -21
View File
@@ -3,7 +3,6 @@ extern crate peg;
use crate::password::Password; use crate::password::Password;
use crate::structs::{Command, LKErr, Mode}; use crate::structs::{Command, LKErr, Mode};
use crate::utils::date::Date; use crate::utils::date::Date;
use std::{cell::RefCell, rc::Rc};
peg::parser! { peg::parser! {
pub grammar command_parser() for str { pub grammar command_parser() for str {
@@ -89,10 +88,10 @@ 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 ld_cmd() -> Command<'input> = "ld" f:comment()? { Command::Ld(f.unwrap_or(".".to_string())) } rule ld_cmd() -> Command<'input> = "ld" f:comment()? { Command::Ld(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(Password::from_password(name)) }
rule leave_cmd() -> Command<'input> = "leave" _ name:word() { Command::Leave(name.to_string()) } rule leave_cmd() -> Command<'input> = "leave" _ name:word() { Command::Leave(name.to_string()) }
rule gen_cmd() -> Command<'input> = "gen" n:num()? _ name: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))) Command::Gen(match n { Some(n) => n, None => 10_u32 }, Password::from_password(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) }
@@ -119,7 +118,7 @@ add t2 C 99 2022-12-14
add t3 C 99 2022-12-14"### add t3 C 99 2022-12-14"###
), ),
Ok(vec![ Ok(vec![
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t1".to_string(), name: "t1".to_string(),
@@ -128,8 +127,8 @@ add t3 C 99 2022-12-14"###
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t2".to_string(), name: "t2".to_string(),
@@ -138,8 +137,8 @@ add t3 C 99 2022-12-14"###
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t3".to_string(), name: "t3".to_string(),
@@ -148,7 +147,7 @@ add t3 C 99 2022-12-14"###
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))) }))
]) ])
); );
assert_eq!( assert_eq!(
@@ -159,7 +158,7 @@ add t3 C 99 2022-12-14
"### "###
), ),
Ok(vec![ Ok(vec![
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t1".to_string(), name: "t1".to_string(),
@@ -168,8 +167,8 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t2".to_string(), name: "t2".to_string(),
@@ -178,8 +177,8 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t3".to_string(), name: "t3".to_string(),
@@ -188,7 +187,7 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Noop Command::Noop
]) ])
); );
@@ -201,7 +200,7 @@ add t3 C 99 2022-12-14
"### "###
), ),
Ok(vec![ Ok(vec![
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t1".to_string(), name: "t1".to_string(),
@@ -210,8 +209,8 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t2".to_string(), name: "t2".to_string(),
@@ -220,8 +219,8 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Add(Rc::new(RefCell::new(Password { Command::Add(Password::from_password(Password {
parent: None, parent: None,
prefix: None, prefix: None,
name: "t3".to_string(), name: "t3".to_string(),
@@ -230,7 +229,7 @@ add t3 C 99 2022-12-14
seq: 99, seq: 99,
date: Date::new(2022, 12, 14), date: Date::new(2022, 12, 14),
comment: None comment: None
}))), })),
Command::Noop, Command::Noop,
Command::Noop Command::Noop
]) ])
+56 -33
View File
@@ -1,17 +1,19 @@
use crate::skey::SKey; use crate::skey::SKey;
use crate::structs::Mode; use crate::structs::Mode;
use crate::utils::date::Date; use crate::utils::date::Date;
use std::{cell::RefCell, rc::Rc}; use parking_lot::ReentrantMutex;
use std::cell::RefCell;
use std::sync::Arc;
pub type Name = String; pub type Name = String;
pub type Prefix = Option<String>; pub type Prefix = Option<String>;
pub type Comment = Option<String>; pub type Comment = Option<String>;
pub type PasswordRef = Rc<RefCell<Password>>; pub type PasswordRef = Arc<ReentrantMutex<RefCell<Password>>>;
pub type Parent = Option<PasswordRef>; pub type Parent = Option<PasswordRef>;
pub type Length = Option<u32>; pub type Length = Option<u32>;
pub type Seq = u32; pub type Seq = u32;
#[derive(PartialEq, Debug)] #[derive(Debug)]
pub struct Password { pub struct Password {
pub parent: Parent, pub parent: Parent,
pub prefix: Prefix, pub prefix: Prefix,
@@ -45,8 +47,8 @@ impl Password {
} }
} }
pub fn from_password(password: &Password) -> PasswordRef { pub fn from_password_ref(password: &Password) -> PasswordRef {
Rc::new(RefCell::new(Self { Arc::new(ReentrantMutex::new(RefCell::new(Self {
parent: password.parent.clone(), parent: password.parent.clone(),
prefix: password.prefix.clone(), prefix: password.prefix.clone(),
name: password.name.clone(), name: password.name.clone(),
@@ -55,7 +57,11 @@ impl Password {
seq: password.seq, seq: password.seq,
date: password.date.clone(), date: password.date.clone(),
comment: password.comment.clone(), comment: password.comment.clone(),
})) })))
}
pub fn from_password(password: Password) -> PasswordRef {
Arc::new(ReentrantMutex::new(RefCell::new(password)))
} }
pub fn encode(&self, secret: &str) -> String { pub fn encode(&self, secret: &str) -> String {
@@ -109,13 +115,28 @@ impl std::string::ToString for Password {
None => "".to_string(), None => "".to_string(),
}; };
let parent = match &self.parent { let parent = match &self.parent {
Some(s) => format!(" ^{}", s.borrow().name), Some(s) => format!(" ^{}", s.lock().borrow().name),
None => "".to_string(), None => "".to_string(),
}; };
format!("{:>6}{} {}{} {} {}{}{}", prefix, self.name, length, self.mode, self.seq, self.date, comment, parent) format!("{:>6}{} {}{} {} {}{}{}", prefix, self.name, length, self.mode, self.seq, self.date, comment, parent)
} }
} }
impl PartialEq for Password {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& match (&self.parent, &other.parent) {
(Some(s), Some(o)) => *s.lock() == *o.lock(),
(None, None) => true,
_ => false,
}
&& self.prefix == other.prefix
&& self.length == other.length
&& self.mode == other.mode
&& self.seq == other.seq
}
}
fn camel_case(words: [&str; 6]) -> String { fn camel_case(words: [&str; 6]) -> String {
let mut camel_case_string = String::new(); let mut camel_case_string = String::new();
@@ -128,34 +149,34 @@ fn camel_case(words: [&str; 6]) -> String {
camel_case_string camel_case_string
} }
pub fn fix_password_recursion(entry: Rc<RefCell<Password>>) { pub fn fix_password_recursion(entry: PasswordRef) {
let mut t1 = entry.clone(); let mut t1 = entry.clone();
let mut t2 = entry; let mut t2 = entry;
let mut t3: Option<Rc<RefCell<Password>>> = None; let mut t3: Option<PasswordRef> = None;
loop { loop {
t2 = match &t2.clone().borrow().parent { t2 = match &t2.clone().lock().borrow().parent {
Some(o) => o.clone(), Some(o) => o.clone(),
None => break, None => break,
}; };
if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { if std::ptr::eq(&*t1.lock().borrow(), &*t2.lock().borrow()) {
t3 = Some(t2.clone()); t3 = Some(t2.clone());
break; break;
} }
t1 = match &t1.clone().borrow().parent { t1 = match &t1.clone().lock().borrow().parent {
Some(o) => o.clone(), Some(o) => o.clone(),
None => break, None => break,
}; };
t2 = match &t2.clone().borrow().parent { t2 = match &t2.clone().lock().borrow().parent {
Some(o) => o.clone(), Some(o) => o.clone(),
None => break, None => break,
}; };
if std::ptr::eq(&*t1.borrow(), &*t2.borrow()) { if std::ptr::eq(&*t1.lock().borrow(), &*t2.lock().borrow()) {
t3 = Some(t2.clone()); t3 = Some(t2.clone());
break; break;
} }
} }
match t3 { match t3 {
Some(o) => o.borrow_mut().parent = None, Some(o) => o.lock().borrow_mut().parent = None,
None => (), None => (),
} }
} }
@@ -166,7 +187,7 @@ mod tests {
#[test] #[test]
fn exec_recursion_test() { fn exec_recursion_test() {
let p1 = Rc::new(RefCell::new(Password::new( let p1 = Password::from_password(Password::new(
None, None,
"p1".to_string(), "p1".to_string(),
None, None,
@@ -174,13 +195,15 @@ mod tests {
99, 99,
Date::new(2022, 12, 3), Date::new(2022, 12, 3),
None, None,
))); ));
p1.borrow_mut().parent = Some(p1.clone()); {
p1.lock().borrow_mut().parent = Some(p1.clone());
};
fix_password_recursion(p1.clone()); fix_password_recursion(p1.clone());
assert_eq!(p1.borrow().parent, None); assert_eq!(p1.lock().borrow().parent.is_none(), true);
let p2 = Rc::new(RefCell::new(Password::new( let p2 = Password::from_password(Password::new(
None, None,
"p2".to_string(), "p2".to_string(),
None, None,
@@ -188,9 +211,9 @@ mod tests {
99, 99,
Date::new(2022, 12, 3), Date::new(2022, 12, 3),
None, None,
))); ));
p2.borrow_mut().parent = Some(p1.clone()); p2.lock().borrow_mut().parent = Some(p1.clone());
let p3 = Rc::new(RefCell::new(Password::new( let p3 = Password::from_password(Password::new(
None, None,
"p3".to_string(), "p3".to_string(),
None, None,
@@ -198,9 +221,9 @@ mod tests {
99, 99,
Date::new(2022, 12, 3), Date::new(2022, 12, 3),
None, None,
))); ));
p3.borrow_mut().parent = Some(p2.clone()); p3.lock().borrow_mut().parent = Some(p2.clone());
let p4 = Rc::new(RefCell::new(Password::new( let p4 = Password::from_password(Password::new(
None, None,
"p4".to_string(), "p4".to_string(),
None, None,
@@ -208,9 +231,9 @@ mod tests {
99, 99,
Date::new(2022, 12, 3), Date::new(2022, 12, 3),
None, None,
))); ));
p4.borrow_mut().parent = Some(p3.clone()); p4.lock().borrow_mut().parent = Some(p3.clone());
let p5 = Rc::new(RefCell::new(Password::new( let p5 = Password::from_password(Password::new(
None, None,
"p5".to_string(), "p5".to_string(),
None, None,
@@ -218,12 +241,12 @@ mod tests {
99, 99,
Date::new(2022, 12, 3), Date::new(2022, 12, 3),
None, None,
))); ));
p5.borrow_mut().parent = Some(p4.clone()); p5.lock().borrow_mut().parent = Some(p4.clone());
p1.borrow_mut().parent = Some(p3.clone()); p1.lock().borrow_mut().parent = Some(p3.clone());
fix_password_recursion(p5.clone()); fix_password_recursion(p5.clone());
assert_eq!(p3.borrow().parent, None); assert_eq!(p3.lock().borrow().parent.is_none(), true);
} }
#[test] #[test]
+89 -42
View File
@@ -1,15 +1,13 @@
use std::{cell::RefCell, rc::Rc}; use crate::lk::LKRef;
use crate::lk::LK;
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE}; use crate::structs::{Command, LKErr, LKOut, HISTORY_FILE};
use crate::utils::editor::{ Editor, password }; use crate::utils::editor::{password, Editor};
#[derive(Debug)] #[derive(Debug)]
pub struct LKRead { pub struct LKRead {
pub rl: Editor, pub rl: Editor,
pub prompt: String, pub prompt: String,
pub state: Rc<RefCell<LK>>, pub state: LKRef,
pub cmd: String, pub cmd: String,
pub read_password: fn(String) -> std::io::Result<String>, pub read_password: fn(String) -> std::io::Result<String>,
} }
@@ -17,19 +15,19 @@ pub struct LKRead {
#[derive(Debug)] #[derive(Debug)]
pub struct LKEval<'a> { pub struct LKEval<'a> {
pub cmd: Command<'a>, pub cmd: Command<'a>,
pub state: Rc<RefCell<LK>>, pub state: LKRef,
pub read_password: fn(String) -> std::io::Result<String>, pub read_password: fn(String) -> std::io::Result<String>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug)]
pub struct LKPrint { pub struct LKPrint {
pub out: LKOut, pub out: LKOut,
pub quit: bool, pub quit: bool,
pub state: Rc<RefCell<LK>>, pub state: LKRef,
} }
impl LKRead { impl LKRead {
pub fn new(rl: Editor, prompt: String, state: Rc<RefCell<LK>>) -> Self { pub fn new(rl: Editor, prompt: String, state: LKRef) -> Self {
Self { Self {
rl, rl,
prompt, prompt,
@@ -77,7 +75,7 @@ impl LKRead {
} }
impl<'a> LKEval<'a> { impl<'a> LKEval<'a> {
pub fn new(cmd: Command<'a>, state: Rc<RefCell<LK>>, read_password: fn(String) -> std::io::Result<String>) -> Self { pub fn new(cmd: Command<'a>, state: LKRef, read_password: fn(String) -> std::io::Result<String>) -> Self {
Self { Self {
cmd, cmd,
state, state,
@@ -94,25 +92,33 @@ impl<'a> LKEval<'a> {
out.e("Bye!".to_string()); out.e("Bye!".to_string());
quit = true; quit = true;
} }
Command::Ls(filter) => self.cmd_ls(&out, filter.to_string(), |a,b| a.borrow().name.cmp(&b.borrow().name)), Command::Ls(filter) => {
Command::Ld(filter) => self.cmd_ls(&out, filter.to_string(), |a,b| a.borrow().date.cmp(&b.borrow().date)), self.cmd_ls(&out, filter.to_string(), |a, b| a.lock().borrow().name.cmp(&b.lock().borrow().name))
}
Command::Ld(filter) => {
self.cmd_ls(&out, filter.to_string(), |a, b| a.lock().borrow().date.cmp(&b.lock().borrow().date))
}
Command::Add(name) => self.cmd_add(&out, &name), Command::Add(name) => self.cmd_add(&out, &name),
Command::Leave(name) => self.cmd_leave(&out, &name), Command::Leave(name) => self.cmd_leave(&out, &name),
Command::Comment(name, comment) => self.cmd_comment(&out, &name, &comment), Command::Comment(name, comment) => self.cmd_comment(&out, &name, &comment),
Command::Rm(name) => match self.get_password(name) { Command::Rm(name) => match self.get_password(name) {
Some(pwd) => { Some(pwd) => {
self.state.borrow_mut().db.remove(&pwd.borrow().name); self.state.lock().borrow_mut().db.remove(&pwd.lock().borrow().name);
out.o(format!("removed {}", pwd.borrow().name)); out.o(format!("removed {}", pwd.lock().borrow().name));
} }
None => out.e(format!("error: password {} not found", name)), None => out.e(format!("error: password {} not found", name)),
}, },
Command::Enc(name) => { self.cmd_enc(&out, name); } Command::Enc(name) => {
self.cmd_enc(&out, name);
}
Command::Gen(num, name) => self.cmd_gen(&out, &num, &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) => { quit = self.cmd_source(&out, script); } Command::Source(script) => {
quit = self.cmd_source(&out, script);
}
Command::Dump(script) => self.cmd_dump(&out, script), Command::Dump(script) => self.cmd_dump(&out, script),
Command::Pass(name) => self.cmd_pass(&out, &name), Command::Pass(name) => self.cmd_pass(&out, &name),
Command::UnPass(name) => match self.state.borrow_mut().secrets.remove(name) { Command::UnPass(name) => match self.state.lock().borrow_mut().secrets.remove(name) {
Some(_) => out.o(format!("Removed saved password for {}", name)), Some(_) => out.o(format!("Removed saved password for {}", name)),
None => out.e(format!("error: saved password for {} not found", name)), None => out.e(format!("error: saved password for {} not found", name)),
}, },
@@ -136,7 +142,7 @@ impl<'a> LKEval<'a> {
} }
impl LKPrint { impl LKPrint {
pub fn new(out: LKOut, quit: bool, state: Rc<RefCell<LK>>) -> Self { pub fn new(out: LKOut, quit: bool, state: LKRef) -> Self {
Self { out, quit, state } Self { out, quit, state }
} }
@@ -147,16 +153,26 @@ impl LKPrint {
} }
} }
impl PartialEq for LKPrint {
fn eq(&self, other: &Self) -> bool {
self.out == other.out && self.quit == other.quit && *self.state.lock() == *other.state.lock()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::lk::LK;
use crate::password::Password; use crate::password::Password;
use crate::structs::Mode; use crate::structs::Mode;
use std::collections::HashMap;
use crate::utils::date::Date; use crate::utils::date::Date;
use parking_lot::ReentrantMutex;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;
impl<'a> LKEval<'a> { impl<'a> LKEval<'a> {
pub fn news(cmd: Command<'a>, state: Rc<RefCell<LK>>) -> Self { pub fn news(cmd: Command<'a>, state: LKRef) -> Self {
Self { Self {
cmd, cmd,
state, state,
@@ -169,12 +185,12 @@ mod tests {
#[test] #[test]
fn exec_cmds_basic() { fn exec_cmds_basic() {
let lk = Rc::new(RefCell::new(LK::new())); let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new())));
assert_eq!( assert_eq!(
LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone())
); );
let pwd1 = Rc::new(RefCell::new(Password { let pwd1 = Password::from_password(Password {
name: "t1".to_string(), name: "t1".to_string(),
prefix: None, prefix: None,
length: None, length: None,
@@ -183,12 +199,25 @@ mod tests {
date: Date::new(2022, 12, 30), date: Date::new(2022, 12, 30),
comment: Some("comment".to_string()), comment: Some("comment".to_string()),
parent: None, parent: None,
}));
assert_eq!(LKEval::news(Command::Add(pwd1.clone()), lk.clone()).eval().state.borrow().db, {
let mut db = HashMap::new();
db.insert(pwd1.borrow().name.to_string(), pwd1.clone());
db
}); });
assert_eq!(
LKEval::news(Command::Add(pwd1.clone()), lk.clone())
.eval()
.state
.lock()
.borrow()
.db
.iter()
.map(|x| (x.0.to_string(), x.1.lock().borrow().to_string()))
.collect::<Vec<(String, String)>>(),
{
let mut db = HashMap::new();
db.insert(pwd1.lock().borrow().name.to_string(), pwd1.clone());
db.into_iter()
.map(|x| (x.0.to_string(), x.1.lock().borrow().to_string()))
.collect::<Vec<(String, String)>>()
}
);
assert_eq!( assert_eq!(
LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(),
LKPrint::new( LKPrint::new(
@@ -201,7 +230,7 @@ mod tests {
LKEval::news(Command::Quit, lk.clone()).eval(), LKEval::news(Command::Quit, lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec!["Bye!".to_string()]), true, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec!["Bye!".to_string()]), true, lk.clone())
); );
let pwd2 = Rc::new(RefCell::new(Password { let pwd2 = Password::from_password(Password {
name: "t2".to_string(), name: "t2".to_string(),
prefix: None, prefix: None,
length: None, length: None,
@@ -210,18 +239,32 @@ mod tests {
date: Date::new(2022, 12, 31), date: Date::new(2022, 12, 31),
comment: Some("bli blup".to_string()), comment: Some("bli blup".to_string()),
parent: None, parent: None,
}));
assert_eq!(LKEval::news(Command::Add(pwd2.clone()), lk.clone()).eval().state.borrow().db, {
let mut db = HashMap::new();
db.insert(pwd1.borrow().name.to_string(), pwd1.clone());
db.insert(pwd2.borrow().name.to_string(), pwd2.clone());
db
}); });
assert_eq!(
LKEval::news(Command::Add(pwd2.clone()), lk.clone())
.eval()
.state
.lock()
.borrow()
.db
.iter()
.map(|x| (x.0.to_string(), x.1.lock().borrow().to_string()))
.collect::<Vec<(String, String)>>(),
{
let mut db = HashMap::new();
db.insert(pwd1.lock().borrow().name.to_string(), pwd1.clone());
db.insert(pwd2.lock().borrow().name.to_string(), pwd2.clone());
db.into_iter().map(|x| (x.0, x.1.lock().borrow().to_string())).collect::<Vec<(String, String)>>()
}
);
assert_eq!( assert_eq!(
LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(), LKEval::news(Command::Ls(".".to_string()), lk.clone()).eval(),
LKPrint::new( LKPrint::new(
LKOut::from_vecs( LKOut::from_vecs(
vec![" 1 t1 R 99 2022-12-30 comment".to_string(), " 2 t2 R 99 2022-12-31 bli blup".to_string()], vec![
" 1 t1 R 99 2022-12-30 comment".to_string(),
" 2 t2 R 99 2022-12-31 bli blup".to_string()
],
vec![] vec![]
), ),
false, false,
@@ -244,8 +287,8 @@ mod tests {
#[test] #[test]
fn read_pwd_test() { fn read_pwd_test() {
let lk = Rc::new(RefCell::new(LK::new())); let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new())));
let t1 = Rc::new(RefCell::new(Password::new( let t1 = Password::from_password(Password::new(
None, None,
"t1".to_string(), "t1".to_string(),
None, None,
@@ -253,8 +296,8 @@ mod tests {
99, 99,
Date::new(2022, 12, 30), Date::new(2022, 12, 30),
None, None,
))); ));
let t2 = Rc::new(RefCell::new(Password::new( let t2 = Password::from_password(Password::new(
None, None,
"t2".to_string(), "t2".to_string(),
None, None,
@@ -262,8 +305,8 @@ mod tests {
99, 99,
Date::new(2022, 12, 30), Date::new(2022, 12, 30),
None, None,
))); ));
let t3 = Rc::new(RefCell::new(Password::new( let t3 = Password::from_password(Password::new(
None, None,
"t3".to_string(), "t3".to_string(),
None, None,
@@ -271,19 +314,23 @@ mod tests {
99, 99,
Date::new(2022, 12, 30), Date::new(2022, 12, 30),
None, None,
))); ));
println!("POINT 1");
assert_eq!( assert_eq!(
LKEval::news(Command::Add(t1.clone()), lk.clone()).eval(), LKEval::news(Command::Add(t1.clone()), lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone())
); );
println!("POINT 2");
assert_eq!( assert_eq!(
LKEval::news(Command::Add(t2.clone()), lk.clone()).eval(), LKEval::news(Command::Add(t2.clone()), lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone())
); );
println!("POINT 3");
assert_eq!( assert_eq!(
LKEval::news(Command::Add(t3.clone()), lk.clone()).eval(), LKEval::news(Command::Add(t3.clone()), lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone())
); );
println!("POINT 4");
assert_eq!( assert_eq!(
LKEval::news(Command::Mv("t3".to_string(), "t2".to_string()), lk.clone()).eval(), LKEval::news(Command::Mv("t3".to_string(), "t2".to_string()), lk.clone()).eval(),
LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone()) LKPrint::new(LKOut::from_vecs(vec![], vec![]), false, lk.clone())
+81 -36
View File
@@ -1,13 +1,16 @@
use crate::password::{Comment, Name, PasswordRef}; use crate::password::{Comment, Name, PasswordRef};
use parking_lot::Mutex;
use parking_lot::ReentrantMutex;
use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::path::Path; use std::path::Path;
use std::{cell::RefCell, rc::Rc}; use std::sync::Arc;
use crate::lk::LK; use crate::lk::LK;
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::repl::{LKEval, LKRead}; use crate::repl::{LKEval, LKRead};
use crate::utils::editor::{password, Editor};
use crate::utils::home; use crate::utils::home;
use crate::utils::editor::{ Editor, password };
lazy_static! { lazy_static! {
pub static ref HISTORY_FILE: Box<Path> = { pub static ref HISTORY_FILE: Box<Path> = {
@@ -54,7 +57,7 @@ pub enum LKErr<'a> {
ParseError(peg::error::ParseError<peg::str::LineCol>), ParseError(peg::error::ParseError<peg::str::LineCol>),
} }
#[derive(PartialEq, Debug)] #[derive(Debug)]
pub enum Command<'a> { pub enum Command<'a> {
Add(PasswordRef), Add(PasswordRef),
Leave(Name), Leave(Name),
@@ -78,6 +81,34 @@ pub enum Command<'a> {
Quit, Quit,
} }
impl<'a> PartialEq for Command<'a> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Command::Add(s), Command::Add(o)) => *s.lock() == *o.lock(),
(Command::Leave(s), Command::Leave(o)) => s == o,
(Command::Ls(s), Command::Ls(o)) => s == o,
(Command::Ld(s), Command::Ld(o)) => s == o,
(Command::Mv(a, b), Command::Mv(x, y)) => a == x && b == y,
(Command::Rm(s), Command::Rm(o)) => s == o,
(Command::Enc(s), Command::Enc(o)) => s == o,
(Command::Gen(a, b), Command::Gen(x, y)) => a == x && *b.lock() == *y.lock(),
(Command::Pass(s), Command::Pass(o)) => s == o,
(Command::UnPass(s), Command::UnPass(o)) => s == o,
(Command::Correct(s), Command::Correct(o)) => s == o,
(Command::Uncorrect(s), Command::Uncorrect(o)) => s == o,
(Command::PasteBuffer(s), Command::PasteBuffer(o)) => s == o,
(Command::Source(s), Command::Source(o)) => s == o,
(Command::Dump(s), Command::Dump(o)) => s == o,
(Command::Comment(a, b), Command::Comment(x, y)) => a == x && b == y,
(Command::Error(s), Command::Error(o)) => s == o,
(Command::Noop, Command::Noop) => true,
(Command::Help, Command::Help) => true,
(Command::Quit, Command::Quit) => true,
_ => false,
}
}
}
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum Mode { pub enum Mode {
Regular, Regular,
@@ -114,21 +145,21 @@ impl std::fmt::Display for Mode {
} }
} }
#[derive(PartialEq, Debug)] #[derive(Debug)]
pub struct LKOut { pub struct LKOut {
pub out: Option<Rc<RefCell<Vec<String>>>>, pub out: Option<Arc<Mutex<Vec<String>>>>,
pub err: Option<Rc<RefCell<Vec<String>>>>, pub err: Option<Arc<Mutex<Vec<String>>>>,
} }
impl LKOut { impl LKOut {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
out: Some(Rc::new(RefCell::new(vec![]))), out: Some(Arc::new(Mutex::new(vec![]))),
err: Some(Rc::new(RefCell::new(vec![]))), err: Some(Arc::new(Mutex::new(vec![]))),
} }
} }
pub fn from_lkout(out: Option<Rc<RefCell<Vec<String>>>>, err: Option<Rc<RefCell<Vec<String>>>>) -> Self { pub fn from_lkout(out: Option<Arc<Mutex<Vec<String>>>>, err: Option<Arc<Mutex<Vec<String>>>>) -> Self {
let o = match out { let o = match out {
Some(v) => Some(v.clone()), Some(v) => Some(v.clone()),
None => None, None => None,
@@ -143,8 +174,8 @@ impl LKOut {
#[allow(dead_code)] #[allow(dead_code)]
pub fn from_vecs(out: Vec<String>, err: Vec<String>) -> Self { pub fn from_vecs(out: Vec<String>, err: Vec<String>) -> Self {
Self { Self {
out: Some(Rc::new(RefCell::new(out))), out: Some(Arc::new(Mutex::new(out))),
err: Some(Rc::new(RefCell::new(err))), err: Some(Arc::new(Mutex::new(err))),
} }
} }
@@ -152,7 +183,7 @@ impl LKOut {
if !self.out.is_some() { if !self.out.is_some() {
return; return;
} }
for line in self.out.as_ref().unwrap().borrow().iter() { for line in self.out.as_ref().unwrap().lock().iter() {
out.o(line.to_string()) out.o(line.to_string())
} }
} }
@@ -161,7 +192,7 @@ impl LKOut {
if !self.err.is_some() { if !self.err.is_some() {
return; return;
} }
for line in self.err.as_ref().unwrap().borrow().iter() { for line in self.err.as_ref().unwrap().lock().iter() {
out.e(line.to_string()) out.e(line.to_string())
} }
} }
@@ -170,7 +201,7 @@ impl LKOut {
if !self.out.is_some() { if !self.out.is_some() {
return; return;
} }
for line in self.out.as_ref().unwrap().borrow().iter() { for line in self.out.as_ref().unwrap().lock().iter() {
println!("{}", line); println!("{}", line);
} }
} }
@@ -179,7 +210,7 @@ impl LKOut {
if !self.err.is_some() { if !self.err.is_some() {
return; return;
} }
for line in self.err.as_ref().unwrap().borrow().iter() { for line in self.err.as_ref().unwrap().lock().iter() {
eprintln!("{}", line); eprintln!("{}", line);
} }
} }
@@ -191,7 +222,7 @@ impl LKOut {
pub fn data(&self) -> String { pub fn data(&self) -> String {
if self.out.is_some() { if self.out.is_some() {
self.out.as_ref().unwrap().borrow().join("\n") self.out.as_ref().unwrap().lock().join("\n")
} else { } else {
"".to_string() "".to_string()
} }
@@ -202,16 +233,30 @@ impl LKOut {
} }
pub fn o(&self, line: String) { pub fn o(&self, line: String) {
if self.out.is_some() { if self.out.is_some() {
self.out.as_ref().unwrap().borrow_mut().push(line); self.out.as_ref().unwrap().lock().push(line);
} }
} }
pub fn e(&self, line: String) { pub fn e(&self, line: String) {
if self.err.is_some() { if self.err.is_some() {
self.err.as_ref().unwrap().borrow_mut().push(line); self.err.as_ref().unwrap().lock().push(line);
} }
} }
} }
impl PartialEq for LKOut {
fn eq(&self, other: &Self) -> bool {
(match (&self.out, &other.out) {
(Some(a), Some(b)) => *a.lock() == *b.lock(),
(None, None) => true,
_ => false,
} && match (&self.err, &other.err) {
(Some(a), Some(b)) => *a.lock() == *b.lock(),
(None, None) => true,
_ => false,
})
}
}
pub struct Radix { pub struct Radix {
x: i32, x: i32,
radix: u32, radix: u32,
@@ -263,13 +308,15 @@ impl fmt::Display for Radix {
} }
pub fn init() -> Option<LKRead> { pub fn init() -> Option<LKRead> {
let lk = Rc::new(RefCell::new(LK::new())); let lk = Arc::new(ReentrantMutex::new(RefCell::new(LK::new())));
match std::fs::read_to_string(INIT_FILE.to_str().unwrap()) { match std::fs::read_to_string(INIT_FILE.to_str().unwrap()) {
Ok(script) => match command_parser::script(&script) { Ok(script) => match command_parser::script(&script) {
Ok(cmd_list) => { Ok(cmd_list) => {
for cmd in cmd_list { for cmd in cmd_list {
if !LKEval::new(cmd, lk.clone(), password).eval().print() { return None; } if !LKEval::new(cmd, lk.clone(), password).eval().print() {
return None;
}
} }
} }
Err(err) => { Err(err) => {
@@ -349,9 +396,9 @@ mod tests {
let lkread = init().unwrap(); let lkread = init().unwrap();
assert_eq!(lkread.prompt, "test> "); assert_eq!(lkread.prompt, "test> ");
assert_eq!(lkread.state.borrow().db.contains_key("t1"), true); assert_eq!(lkread.state.lock().borrow().db.contains_key("t1"), true);
let t1 = Rc::new(RefCell::new(Password::new( let t1 = Password::from_password(Password::new(
None, None,
"t1".to_string(), "t1".to_string(),
None, None,
@@ -359,8 +406,8 @@ mod tests {
99, 99,
Date::new(2022, 10, 10), Date::new(2022, 10, 10),
None, None,
))); ));
let t2 = Rc::new(RefCell::new(Password::new( let t2 = Password::from_password(Password::new(
None, None,
"t2".to_string(), "t2".to_string(),
None, None,
@@ -368,9 +415,9 @@ mod tests {
99, 99,
Date::new(2022, 10, 10), Date::new(2022, 10, 10),
Some("test".to_string()), Some("test".to_string()),
))); ));
t2.borrow_mut().parent = Some(t1.clone()); t2.lock().borrow_mut().parent = Some(t1.clone());
let t3 = Rc::new(RefCell::new(Password::new( let t3 = Password::from_password(Password::new(
None, None,
"t3".to_string(), "t3".to_string(),
None, None,
@@ -378,15 +425,13 @@ mod tests {
99, 99,
Date::new(2022, 10, 10), Date::new(2022, 10, 10),
Some("aoeu".to_string()), Some("aoeu".to_string()),
))); ));
t3.borrow_mut().parent = Some(t2.clone()); t3.lock().borrow_mut().parent = Some(t2.clone());
assert_eq!(*lkread.state.borrow().db.get("t1").unwrap().borrow(), *t1.borrow()); assert_eq!(*lkread.state.lock().borrow().db.get("t1").unwrap().lock(), *t1.lock());
assert_eq!(*lkread.state.borrow().db.get("t2").unwrap().borrow(), *t2.borrow()); assert_eq!(*lkread.state.lock().borrow().db.get("t2").unwrap().lock(), *t2.lock());
assert_eq!(*lkread.state.borrow().db.get("t3").unwrap().borrow(), *t3.borrow()); assert_eq!(*lkread.state.lock().borrow().db.get("t3").unwrap().lock(), *t3.lock());
LKEval::new(command_parser::cmd("save").unwrap(), lkread.state.clone(), password) LKEval::new(command_parser::cmd("save").unwrap(), lkread.state.clone(), password).eval().print();
.eval()
.print();
assert_eq!( assert_eq!(
std::fs::read_to_string("test_dump").expect("read"), std::fs::read_to_string("test_dump").expect("read"),
"add t1 R 99 2022-10-10\nadd t2 R 99 2022-10-10 test ^t1\nadd t3 R 99 2022-10-10 aoeu ^t2\n".to_string() "add t1 R 99 2022-10-10\nadd t2 R 99 2022-10-10 test ^t1\nadd t3 R 99 2022-10-10 aoeu ^t2\n".to_string()
@@ -412,7 +457,7 @@ mod tests {
] ]
) )
); );
lkread.state.borrow_mut().secrets.clear(); lkread.state.lock().borrow_mut().secrets.clear();
let pr = LKEval::new(command_parser::cmd("pb enc t3").unwrap(), lkread.state.clone(), |v| { let pr = LKEval::new(command_parser::cmd("pb enc t3").unwrap(), lkread.state.clone(), |v| {
if v == "/" { if v == "/" {
Ok("a".to_string()) Ok("a".to_string())
+10 -4
View File
@@ -11,12 +11,14 @@ pub mod date {
#[derive(PartialEq, Debug, Clone, Copy)] #[derive(PartialEq, Debug, Clone, Copy)]
pub struct Date { pub struct Date {
date: NaiveDate date: NaiveDate,
} }
impl Date { impl Date {
pub fn new(year: i32, month: u32, day: u32) -> Self { pub fn new(year: i32, month: u32, day: u32) -> Self {
Self { date: NaiveDate::from_ymd_opt(year, month, day).unwrap() } Self {
date: NaiveDate::from_ymd_opt(year, month, day).unwrap(),
}
} }
pub fn try_new(year: i32, month: u32, day: u32) -> Result<Self, &'static str> { pub fn try_new(year: i32, month: u32, day: u32) -> Result<Self, &'static str> {
@@ -27,7 +29,9 @@ pub mod date {
} }
pub fn now() -> Self { pub fn now() -> Self {
Self { date: Local::now().naive_local().date() } Self {
date: Local::now().naive_local().date(),
}
} }
pub fn cmp(&self, other: &Self) -> core::cmp::Ordering { pub fn cmp(&self, other: &Self) -> core::cmp::Ordering {
@@ -95,7 +99,9 @@ pub mod editor {
impl Editor { impl Editor {
pub fn new() -> Self { pub fn new() -> Self {
Self { editor: rustyline::Editor::<()>::new().unwrap() } Self {
editor: rustyline::Editor::<()>::new().unwrap(),
}
} }
pub fn clear_history(&mut self) { pub fn clear_history(&mut self) {
+1
View File
@@ -13,6 +13,7 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
hel = { version = "0.1.0", path = "../hel" } hel = { version = "0.1.0", path = "../hel" }
lazy_static = "1.4.0"
wasm-bindgen = "0.2.83" wasm-bindgen = "0.2.83"
[dependencies.web-sys] [dependencies.web-sys]
+8 -2
View File
@@ -1,7 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script type="module" src="./pkg/helwasm.js"></script>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
@@ -76,7 +75,9 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="text/javascript"> <script type="module">
import init, { ok_add } from "./pkg/helwasm.js";
function read_line(prompt) { function read_line(prompt) {
console.log("called read_line: " + prompt); console.log("called read_line: " + prompt);
return "line"; return "line";
@@ -87,6 +88,11 @@
return "password"; return "password";
} }
init().then(() => {
window.hel = {
ok_add: ok_add,
}
});
</script> </script>
<script type="text/babel"> <script type="text/babel">
function Terminal() { function Terminal() {
+6
View File
@@ -0,0 +1,6 @@
use hel::lk::LK;
use std::sync::{Arc, Mutex};
lazy_static! {
static ref STATE: Arc<Mutex<LK>> = Arc::new(Mutex::new(LK::new()));
}
+8
View File
@@ -1,3 +1,5 @@
#[macro_use]
extern crate lazy_static;
extern crate hel; extern crate hel;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@@ -6,3 +8,9 @@ use wasm_bindgen::prelude::*;
pub fn ok_add(a: i32, b: i32) -> i32 { pub fn ok_add(a: i32, b: i32) -> i32 {
a + b + 1 a + b + 1
} }
mod hel_state;
#[wasm_bindgen]
pub fn hel_init() {
}