kpdb/types/
entry.rs

1// Copyright (c) 2016-2017 Martijn Rijkeboer <mrr@sru-systems.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use super::association::Association;
10use super::binary_key::BinaryKey;
11use super::binary_value::BinaryValue;
12use super::color::Color;
13use super::custom_icon_uuid::CustomIconUuid;
14use super::entry_uuid::EntryUuid;
15use super::icon::Icon;
16use super::obfuscation::Obfuscation;
17use super::string_key::StringKey;
18use super::string_value::StringValue;
19use super::strings_map::StringsMap;
20use super::times::Times;
21use crate::{common, GroupUuid};
22use chrono::{DateTime, Utc};
23use std::collections::HashMap;
24use std::str;
25
26/// An entry in the database.
27#[derive(Clone, Debug, PartialEq)]
28pub struct Entry {
29    /// Auto-type associations.
30    pub associations: Vec<Association>,
31
32    /// Default auto-type sequence.
33    pub auto_type_def_sequence: String,
34
35    /// Whether auto-type is enabled.
36    pub auto_type_enabled: bool,
37
38    /// The type of obfuscation to use for auto-typing.
39    pub auto_type_obfuscation: Obfuscation,
40
41    /// The background color.
42    pub background_color: Option<Color>,
43
44    /// Map with binaries.
45    pub binaries: HashMap<BinaryKey, BinaryValue>,
46
47    /// The date and time this entry was created.
48    pub creation_time: DateTime<Utc>,
49
50    /// The identifier of this entry's custom icon if any.
51    pub custom_icon_uuid: Option<CustomIconUuid>,
52
53    /// Whether this entry expires.
54    pub expires: bool,
55
56    /// The date and time this entry will expire if expires is true.
57    pub expiry_time: DateTime<Utc>,
58
59    /// The foreground color.
60    pub foreground_color: Option<Color>,
61
62    /// This entry's history.
63    pub history: Vec<Entry>,
64
65    /// This entry's icon.
66    pub icon: Icon,
67
68    /// The date and time this entry was last accessed.
69    pub last_accessed: DateTime<Utc>,
70
71    /// The date and time this entry was last modified.
72    pub last_modified: DateTime<Utc>,
73
74    /// The date and time the location of this entry was changed.
75    pub location_changed: DateTime<Utc>,
76
77    /// Override URL.
78    pub override_url: String,
79
80    /// Map with strings.
81    pub strings: StringsMap,
82
83    /// The tags associated with this entry.
84    pub tags: String,
85
86    /// The usage count of this entry.
87    pub usage_count: i32,
88
89    /// The identifier of this entry.
90    pub uuid: EntryUuid,
91
92    /// The parent groups GroupUUID.
93    pub parent: GroupUuid,
94}
95
96impl Entry {
97    /// Create a new entry.
98    pub fn new() -> Entry {
99        let mut entry = Entry::default();
100        entry.uuid = EntryUuid::new_random();
101        entry
102    }
103
104    /// Gets the notes string if any.
105    pub fn notes(&self) -> Option<&str> {
106        self.other(StringKey::Notes)
107    }
108
109    /// Gets an other string if any.
110    pub fn other(&self, key: StringKey) -> Option<&str> {
111        match self.strings.get(&key) {
112            Some(&StringValue::Plain(ref string)) => Some(string),
113            Some(&StringValue::Protected(ref secstr)) => str::from_utf8(secstr.unsecure()).ok(),
114            None => None,
115        }
116    }
117
118    /// Gets the password string if any.
119    pub fn password(&self) -> Option<&str> {
120        self.other(StringKey::Password)
121    }
122
123    /// Sets the notes string value.
124    pub fn set_notes<S: Into<String>>(&mut self, val: S) {
125        self.strings
126            .insert(StringKey::Notes, StringValue::new(val, common::PROTECT_NOTES_DEFAULT));
127    }
128
129    /// Sets an other string value.
130    pub fn set_other<S: Into<String>>(&mut self, key: StringKey, val: S) {
131        self.strings.insert(key, StringValue::new(val, false));
132    }
133
134    /// Sets the password string value.
135    pub fn set_password<S: Into<String>>(&mut self, val: S) {
136        self.strings
137            .insert(StringKey::Password, StringValue::new(val, common::PROTECT_PASSWORD_DEFAULT));
138    }
139
140    /// Sets the title string value.
141    pub fn set_title<S: Into<String>>(&mut self, val: S) {
142        self.strings
143            .insert(StringKey::Title, StringValue::new(val, common::PROTECT_TITLE_DEFAULT));
144    }
145
146    /// Sets the url string value.
147    pub fn set_url<S: Into<String>>(&mut self, val: S) {
148        self.strings
149            .insert(StringKey::Url, StringValue::new(val, common::PROTECT_URL_DEFAULT));
150    }
151
152    /// Sets the username string value.
153    pub fn set_username<S: Into<String>>(&mut self, val: S) {
154        self.strings
155            .insert(StringKey::Username, StringValue::new(val, common::PROTECT_USERNAME_DEFAULT));
156    }
157
158    /// Gets the title string if any.
159    pub fn title(&self) -> Option<&str> {
160        self.other(StringKey::Title)
161    }
162
163    /// Gets the url string if any.
164    pub fn url(&self) -> Option<&str> {
165        self.other(StringKey::Url)
166    }
167
168    /// Gets the username string if any.
169    pub fn username(&self) -> Option<&str> {
170        self.other(StringKey::Username)
171    }
172}
173
174impl Default for Entry {
175    fn default() -> Entry {
176        let now = Utc::now();
177        Entry {
178            associations: Vec::new(),
179            auto_type_def_sequence: String::new(),
180            auto_type_enabled: true,
181            auto_type_obfuscation: Obfuscation::None,
182            background_color: None,
183            binaries: HashMap::new(),
184            creation_time: now,
185            custom_icon_uuid: None,
186            expires: false,
187            expiry_time: now,
188            foreground_color: None,
189            history: Vec::new(),
190            icon: Icon::Key,
191            last_accessed: now,
192            last_modified: now,
193            location_changed: now,
194            override_url: String::new(),
195            strings: StringsMap::new(),
196            tags: String::new(),
197            usage_count: 0,
198            uuid: EntryUuid::nil(),
199            parent: GroupUuid::nil(),
200        }
201    }
202}
203
204impl Times for Entry {
205    fn creation_time(&self) -> DateTime<Utc> {
206        self.creation_time
207    }
208
209    fn expires(&self) -> bool {
210        self.expires
211    }
212
213    fn expiry_time(&self) -> DateTime<Utc> {
214        self.expiry_time
215    }
216
217    fn last_accessed(&self) -> DateTime<Utc> {
218        self.last_accessed
219    }
220
221    fn last_modified(&self) -> DateTime<Utc> {
222        self.last_modified
223    }
224
225    fn location_changed(&self) -> DateTime<Utc> {
226        self.location_changed
227    }
228
229    fn usage_count(&self) -> i32 {
230        self.usage_count
231    }
232
233    fn set_creation_time(&mut self, val: DateTime<Utc>) {
234        self.creation_time = val;
235    }
236
237    fn set_expires(&mut self, val: bool) {
238        self.expires = val;
239    }
240
241    fn set_expiry_time(&mut self, val: DateTime<Utc>) {
242        self.expiry_time = val;
243    }
244
245    fn set_last_accessed(&mut self, val: DateTime<Utc>) {
246        self.last_accessed = val;
247    }
248
249    fn set_last_modified(&mut self, val: DateTime<Utc>) {
250        self.last_modified = val;
251    }
252
253    fn set_location_changed(&mut self, val: DateTime<Utc>) {
254        self.location_changed = val;
255    }
256
257    fn set_usage_count(&mut self, val: i32) {
258        self.usage_count = val;
259    }
260}
261
262#[cfg(test)]
263mod tests {
264
265    use super::*;
266    use crate::types::EntryUuid;
267    use crate::types::Icon;
268    use crate::types::Obfuscation;
269    use crate::types::StringKey;
270    use crate::types::StringsMap;
271    use crate::utils::test::approx_equal_datetime;
272    use chrono::Utc;
273    use std::collections::HashMap;
274
275    #[test]
276    fn test_new_returns_correct_instance() {
277        let now = Utc::now();
278        let entry = Entry::new();
279        assert_eq!(entry.associations, Vec::new());
280        assert_eq!(entry.auto_type_def_sequence, "");
281        assert_eq!(entry.auto_type_enabled, true);
282        assert_eq!(entry.auto_type_obfuscation, Obfuscation::None);
283        assert_eq!(entry.background_color, None);
284        assert_eq!(entry.binaries, HashMap::new());
285        assert!(approx_equal_datetime(entry.creation_time, now));
286        assert_eq!(entry.custom_icon_uuid, None);
287        assert_eq!(entry.expires, false);
288        assert!(approx_equal_datetime(entry.expiry_time, now));
289        assert_eq!(entry.foreground_color, None);
290        assert_eq!(entry.history, Vec::new());
291        assert_eq!(entry.icon, Icon::Key);
292        assert!(approx_equal_datetime(entry.last_accessed, now));
293        assert!(approx_equal_datetime(entry.last_modified, now));
294        assert!(approx_equal_datetime(entry.location_changed, now));
295        assert_eq!(entry.override_url, "");
296        assert_eq!(entry.strings, StringsMap::new());
297        assert_eq!(entry.tags, "");
298        assert_eq!(entry.usage_count, 0);
299        assert!(entry.uuid != EntryUuid::nil());
300    }
301
302    #[test]
303    fn test_notes_returns_none_on_default_entry() {
304        let entry = Entry::default();
305        assert_eq!(entry.notes(), None);
306    }
307
308    #[test]
309    fn test_other_returns_none_on_default_entry() {
310        let entry = Entry::default();
311        let key = StringKey::from_string("other");
312        assert_eq!(entry.other(key), None);
313    }
314
315    #[test]
316    fn test_password_returns_none_on_default_entry() {
317        let entry = Entry::default();
318        assert_eq!(entry.password(), None);
319    }
320
321    #[test]
322    fn test_set_notes_sets_notes() {
323        let mut entry = Entry::default();
324        entry.set_notes("test");
325        assert_eq!(entry.notes(), Some("test"));
326    }
327
328    #[test]
329    fn test_set_other_sets_other() {
330        let mut entry = Entry::default();
331        let key = StringKey::from_string("other");
332        entry.set_other(key.clone(), "test");
333        assert_eq!(entry.other(key), Some("test"));
334    }
335
336    #[test]
337    fn test_set_password_sets_password() {
338        let mut entry = Entry::default();
339        entry.set_password("test");
340        assert_eq!(entry.password(), Some("test"));
341    }
342
343    #[test]
344    fn test_set_title_sets_title() {
345        let mut entry = Entry::default();
346        entry.set_title("test");
347        assert_eq!(entry.title(), Some("test"));
348    }
349
350    #[test]
351    fn test_set_url_sets_url() {
352        let mut entry = Entry::default();
353        entry.set_url("test");
354        assert_eq!(entry.url(), Some("test"));
355    }
356
357    #[test]
358    fn test_set_username_sets_username() {
359        let mut entry = Entry::default();
360        entry.set_username("test");
361        assert_eq!(entry.username(), Some("test"));
362    }
363
364    #[test]
365    fn test_title_returns_none_on_default_entry() {
366        let entry = Entry::default();
367        assert_eq!(entry.title(), None);
368    }
369
370    #[test]
371    fn test_url_returns_none_on_default_entry() {
372        let entry = Entry::default();
373        assert_eq!(entry.url(), None);
374    }
375
376    #[test]
377    fn test_username_returns_none_on_default_entry() {
378        let entry = Entry::default();
379        assert_eq!(entry.username(), None);
380    }
381
382    #[test]
383    fn test_default_returns_correct_instance() {
384        let now = Utc::now();
385        let entry = Entry::default();
386        assert_eq!(entry.associations, Vec::new());
387        assert_eq!(entry.auto_type_def_sequence, "");
388        assert_eq!(entry.auto_type_enabled, true);
389        assert_eq!(entry.auto_type_obfuscation, Obfuscation::None);
390        assert_eq!(entry.background_color, None);
391        assert_eq!(entry.binaries, HashMap::new());
392        assert!(approx_equal_datetime(entry.creation_time, now));
393        assert_eq!(entry.custom_icon_uuid, None);
394        assert_eq!(entry.expires, false);
395        assert!(approx_equal_datetime(entry.expiry_time, now));
396        assert_eq!(entry.foreground_color, None);
397        assert_eq!(entry.history, Vec::new());
398        assert_eq!(entry.icon, Icon::Key);
399        assert!(approx_equal_datetime(entry.last_accessed, now));
400        assert!(approx_equal_datetime(entry.last_modified, now));
401        assert!(approx_equal_datetime(entry.location_changed, now));
402        assert_eq!(entry.override_url, "");
403        assert_eq!(entry.strings, StringsMap::new());
404        assert_eq!(entry.tags, "");
405        assert_eq!(entry.usage_count, 0);
406        assert_eq!(entry.uuid, EntryUuid::nil());
407    }
408}