diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/api.rs | 12 | ||||
-rw-r--r-- | src/locked.rs | 6 | ||||
-rw-r--r-- | src/pwgen.rs | 44 |
3 files changed, 55 insertions, 7 deletions
@@ -252,14 +252,18 @@ impl SyncResCipher { let history = if let Some(history) = &self.password_history { history .iter() - .map(|entry| crate::db::HistoryEntry { - last_used_date: entry.last_used_date.clone(), - password: entry.password.clone(), + .filter_map(|entry| { + // Gets rid of entries with a non-existent password + entry.password.clone().map(|p| crate::db::HistoryEntry { + last_used_date: entry.last_used_date.clone(), + password: p, + }) }) .collect() } else { vec![] }; + let (folder, folder_id) = if let Some(folder_id) = &self.folder_id { let mut folder_name = None; for folder in folders { @@ -459,7 +463,7 @@ struct SyncResPasswordHistory { #[serde(rename = "LastUsedDate")] last_used_date: String, #[serde(rename = "Password")] - password: String, + password: Option<String>, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] diff --git a/src/locked.rs b/src/locked.rs index 3cad927..aecc54d 100644 --- a/src/locked.rs +++ b/src/locked.rs @@ -1,13 +1,15 @@ use zeroize::Zeroize; +const LEN: usize = 4096; + pub struct Vec { - data: Box<arrayvec::ArrayVec<[u8; 4096]>>, + data: Box<arrayvec::ArrayVec<u8, LEN>>, _lock: region::LockGuard, } impl Default for Vec { fn default() -> Self { - let data = Box::new(arrayvec::ArrayVec::<_>::new()); + let data = Box::new(arrayvec::ArrayVec::<_, LEN>::new()); // XXX it'd be nice to handle this better than .unwrap(), but it'd be // a lot of effort let lock = region::lock(data.as_ptr(), data.capacity()).unwrap(); diff --git a/src/pwgen.rs b/src/pwgen.rs index dc6808f..cf63bb2 100644 --- a/src/pwgen.rs +++ b/src/pwgen.rs @@ -56,8 +56,50 @@ pub fn pwgen(ty: Type, len: usize) -> String { let mut rng = rand::thread_rng(); let mut pass = vec![]; - pass.extend(alphabet.choose_multiple(&mut rng, len).copied()); + pass.extend( + std::iter::repeat_with(|| alphabet.choose(&mut rng).unwrap()) + .take(len), + ); // unwrap is safe because the method of generating passwords guarantees // valid utf8 String::from_utf8(pass).unwrap() } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_pwgen() { + let pw = pwgen(Type::AllChars, 50); + assert_eq!(pw.len(), 50); + // technically this could fail, but the chances are incredibly low + // (around 0.000009%) + assert_duplicates(&pw); + + let pw = pwgen(Type::AllChars, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::NoSymbols, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::Numbers, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + + let pw = pwgen(Type::NonConfusables, 100); + assert_eq!(pw.len(), 100); + assert_duplicates(&pw); + } + + #[track_caller] + fn assert_duplicates(s: &str) { + let mut set = std::collections::HashSet::new(); + for c in s.chars() { + set.insert(c); + } + assert!(set.len() < s.len()) + } +} |