use base64::prelude::{Engine, BASE64_STANDARD};
use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime};
use uuid::Uuid;
pub fn keepass_epoch() -> NaiveDateTime {
NaiveDate::from_ymd_opt(1, 1, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
}
pub fn decode_uuid(b64uuid: &str) -> Option<Uuid> {
let decoded = BASE64_STANDARD.decode(b64uuid).ok()?;
Uuid::from_slice(&decoded).ok()
}
pub(crate) fn decode_datetime_b64(b64date: &str) -> Option<NaiveDateTime> {
let decoded = BASE64_STANDARD.decode(b64date).ok()?;
let mut bytes = [0u8; 8];
let copy_size = usize::min(bytes.len(), decoded.len());
bytes[..copy_size].copy_from_slice(&decoded[..copy_size]);
let timestamp = Duration::seconds(i64::from_le_bytes(bytes));
keepass_epoch().checked_add_signed(timestamp)
}
pub fn decode_datetime(strdate: &str) -> Option<NaiveDateTime> {
if strdate.contains('-') {
let dt = DateTime::parse_from_rfc3339(strdate).ok()?;
Some(dt.naive_utc())
} else {
decode_datetime_b64(strdate)
}
}
pub fn encode_uuid(uuid: Uuid) -> String {
BASE64_STANDARD.encode(uuid.as_bytes())
}
pub fn encode_datetime(date: NaiveDateTime) -> String {
let epoch_seconds = date.signed_duration_since(keepass_epoch()).num_seconds();
BASE64_STANDARD.encode(epoch_seconds.to_le_bytes())
}