use anyhow::{anyhow, Result};
use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};
use rucksack_lib::util;
use crate::crypto::{decrypt, encrypt};
use super::v020;
pub use super::v020::{Creds, Kind};
pub const VERSION: &str = "0.3.0";
pub type HashMap = dashmap::DashMap<String, EncryptedRecord>;
pub fn decode_hashmap(bytes: Vec<u8>, version: versions::SemVer) -> Result<HashMap> {
log::debug!(
"Decoding hashmap from stored bytes (format version {:})...",
version
);
let hm: HashMap = dashmap::DashMap::new();
log::trace!("Created hashmap.");
let sorted_vec: Vec<(String, EncryptedRecord)>;
log::trace!("Created vec for sorted data.");
match bincode::decode_from_slice(bytes.as_ref(), util::bincode_cfg()) {
Ok((result, _len)) => {
sorted_vec = result;
for (key, val) in sorted_vec {
if hm.insert(key.clone(), val).is_some() {}
}
Ok(hm)
}
Err(e) => {
let msg = format!("couldn't deserialise bincoded hashmap bytes: {e:?}");
log::error!("{}", msg);
Err(anyhow!(msg))
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Encode, Decode)]
pub struct Metadata {
pub kind: Kind,
pub url: String,
pub created: String,
pub imported: String,
pub updated: String,
pub password_changed: String,
pub last_used: String,
pub access_count: u64,
}
pub fn migrate_metadata_from_v020(md: v020::Metadata) -> Metadata {
Metadata {
kind: md.kind,
url: md.url,
created: md.created,
imported: String::new(),
updated: md.updated,
password_changed: md.password_changed,
last_used: String::new(),
access_count: 0,
}
}
#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode)]
pub struct DecryptedRecord {
pub creds: Creds,
pub metadata: Metadata,
}
pub fn migrate_decrypted_record_from_v020(dr: v020::DecryptedRecord) -> DecryptedRecord {
DecryptedRecord {
creds: dr.value,
metadata: migrate_metadata_from_v020(dr.metadata),
}
}
impl DecryptedRecord {
pub fn key(&self) -> String {
format!("{}:{}", self.creds.user, self.metadata.url)
}
pub fn metadata(&self) -> Metadata {
self.metadata.clone()
}
pub fn encrypt(&self, store_pwd: String) -> EncryptedRecord {
let encoded = bincode::encode_to_vec(&self.creds, util::bincode_cfg()).unwrap();
let encrypted = encrypt(encoded, store_pwd, self.metadata().updated);
EncryptedRecord {
key: self.key(),
value: encrypted,
metadata: self.metadata(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Encode, Decode)]
pub struct EncryptedRecord {
pub key: String,
pub value: Vec<u8>,
pub metadata: Metadata,
}
impl EncryptedRecord {
pub fn key(&self) -> String {
self.key.clone()
}
pub fn metadata(&self) -> Metadata {
self.metadata.clone()
}
pub fn decrypt(&self, store_pwd: String) -> Result<DecryptedRecord> {
let decrypted = decrypt(self.value.clone(), store_pwd, self.metadata().updated)?;
let (decoded, _len) =
bincode::decode_from_slice(&decrypted[..], util::bincode_cfg()).unwrap();
Ok(DecryptedRecord {
creds: decoded,
metadata: self.metadata(),
})
}
}