Skip to main content

keepass_ng/db/types/
times.rs

1use chrono::NaiveDateTime;
2
3/// Timestamps for a [Group][crate::db::Group] or [Entry][crate::db::Entry]
4///
5/// As the KeePass file format does not store time zone information and does not store sub-second
6/// precision, all times are stored as [NaiveDateTime] with second precision.
7#[derive(Debug, Default, PartialEq, Eq, Clone)]
8#[non_exhaustive]
9#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
10pub struct Times {
11    /// The time of creation
12    pub creation: Option<NaiveDateTime>,
13
14    /// The time of the last modification
15    pub last_modification: Option<NaiveDateTime>,
16
17    /// The time of the last access
18    pub last_access: Option<NaiveDateTime>,
19
20    /// The time of expiration
21    pub expiry: Option<NaiveDateTime>,
22
23    /// The time of the last location change, which is updated when an entry is moved to a different group.
24    pub location_changed: Option<NaiveDateTime>,
25
26    /// Whether the entry or group expires.
27    ///
28    /// A `None` value indicates that the expiration status is not set
29    pub expires: Option<bool>,
30
31    /// The number of times the entry or group has been accessed.
32    pub usage_count: Option<usize>,
33}
34
35// On non-browser targets — including wasm32-wasip1 and wasm32-wasip2 —
36// chrono::Utc::now() works (wasi clocks via WASI 0.1+ are supported by
37// chrono's `clock` feature).  The `js_sys::Date::now()` path is only
38// usable in true browser contexts (target_arch = "wasm32" with target_os
39// = "unknown"), where wasm-bindgen post-processes the binary to resolve
40// the placeholder imports.  Targeting "wasm32" alone unintentionally
41// catches WASI builds and breaks linking.
42#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
43fn now_timestamp() -> i64 {
44    // Use JS Date.now() to get the current time in milliseconds, then convert it to seconds.
45    let millis = js_sys::Date::now();
46    (millis / 1000.0) as i64
47}
48
49#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
50fn now_timestamp() -> i64 {
51    chrono::Utc::now().timestamp()
52}
53
54impl Times {
55    pub fn set_creation(&mut self, value: Option<NaiveDateTime>) {
56        self.creation = value;
57    }
58    pub fn set_last_modification(&mut self, value: Option<NaiveDateTime>) {
59        self.last_modification = value;
60    }
61    pub fn set_last_access(&mut self, value: Option<NaiveDateTime>) {
62        self.last_access = value;
63    }
64    pub fn set_expiry_time(&mut self, value: Option<NaiveDateTime>) {
65        self.expiry = value;
66    }
67    pub fn set_location_changed(&mut self, value: Option<NaiveDateTime>) {
68        self.location_changed = value;
69    }
70    pub fn set_expires(&mut self, value: bool) {
71        self.expires = Some(value);
72    }
73    pub fn set_usage_count(&mut self, value: usize) {
74        self.usage_count = Some(value);
75    }
76    pub fn get_last_modification(&self) -> Option<NaiveDateTime> {
77        self.last_modification
78    }
79    pub fn get_creation(&self) -> Option<NaiveDateTime> {
80        self.creation
81    }
82    pub fn get_last_access(&self) -> Option<NaiveDateTime> {
83        self.last_access
84    }
85    pub fn get_expiry_time(&self) -> Option<NaiveDateTime> {
86        self.expiry
87    }
88    pub fn get_location_changed(&self) -> Option<NaiveDateTime> {
89        self.location_changed
90    }
91    pub fn get_expires(&self) -> bool {
92        self.expires.unwrap_or(false)
93    }
94    pub fn get_usage_count(&self) -> usize {
95        self.usage_count.unwrap_or(0)
96    }
97
98    // Returns the current time, without the nanoseconds since
99    // the last leap second.
100    pub fn now() -> NaiveDateTime {
101        let now = now_timestamp();
102        chrono::DateTime::from_timestamp(now, 0).unwrap().naive_utc()
103    }
104
105    pub fn epoch() -> NaiveDateTime {
106        chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc()
107    }
108
109    pub fn new() -> Self {
110        let now = Times::now();
111        Times {
112            creation: Some(now),
113            last_modification: Some(now),
114            last_access: Some(now),
115            expiry: None,
116            location_changed: Some(now),
117            expires: Some(false),
118            usage_count: Some(0),
119        }
120    }
121}