use super::association::Association;
use super::binary_key::BinaryKey;
use super::binary_value::BinaryValue;
use super::color::Color;
use super::custom_icon_uuid::CustomIconUuid;
use super::entry_uuid::EntryUuid;
use super::icon::Icon;
use super::obfuscation::Obfuscation;
use super::string_key::StringKey;
use super::string_value::StringValue;
use super::strings_map::StringsMap;
use super::times::Times;
use crate::{common, GroupUuid};
use chrono::{DateTime, Utc};
use std::collections::HashMap;
use std::str;
#[derive(Clone, Debug, PartialEq)]
pub struct Entry {
pub associations: Vec<Association>,
pub auto_type_def_sequence: String,
pub auto_type_enabled: bool,
pub auto_type_obfuscation: Obfuscation,
pub background_color: Option<Color>,
pub binaries: HashMap<BinaryKey, BinaryValue>,
pub creation_time: DateTime<Utc>,
pub custom_icon_uuid: Option<CustomIconUuid>,
pub expires: bool,
pub expiry_time: DateTime<Utc>,
pub foreground_color: Option<Color>,
pub history: Vec<Entry>,
pub icon: Icon,
pub last_accessed: DateTime<Utc>,
pub last_modified: DateTime<Utc>,
pub location_changed: DateTime<Utc>,
pub override_url: String,
pub strings: StringsMap,
pub tags: String,
pub usage_count: i32,
pub uuid: EntryUuid,
pub parent: GroupUuid,
}
impl Entry {
pub fn new() -> Entry {
let mut entry = Entry::default();
entry.uuid = EntryUuid::new_random();
entry
}
pub fn notes(&self) -> Option<&str> {
self.other(StringKey::Notes)
}
pub fn other(&self, key: StringKey) -> Option<&str> {
match self.strings.get(&key) {
Some(&StringValue::Plain(ref string)) => Some(string),
Some(&StringValue::Protected(ref secstr)) => str::from_utf8(secstr.unsecure()).ok(),
None => None,
}
}
pub fn password(&self) -> Option<&str> {
self.other(StringKey::Password)
}
pub fn set_notes<S: Into<String>>(&mut self, val: S) {
self.strings
.insert(StringKey::Notes, StringValue::new(val, common::PROTECT_NOTES_DEFAULT));
}
pub fn set_other<S: Into<String>>(&mut self, key: StringKey, val: S) {
self.strings.insert(key, StringValue::new(val, false));
}
pub fn set_password<S: Into<String>>(&mut self, val: S) {
self.strings
.insert(StringKey::Password, StringValue::new(val, common::PROTECT_PASSWORD_DEFAULT));
}
pub fn set_title<S: Into<String>>(&mut self, val: S) {
self.strings
.insert(StringKey::Title, StringValue::new(val, common::PROTECT_TITLE_DEFAULT));
}
pub fn set_url<S: Into<String>>(&mut self, val: S) {
self.strings
.insert(StringKey::Url, StringValue::new(val, common::PROTECT_URL_DEFAULT));
}
pub fn set_username<S: Into<String>>(&mut self, val: S) {
self.strings
.insert(StringKey::Username, StringValue::new(val, common::PROTECT_USERNAME_DEFAULT));
}
pub fn title(&self) -> Option<&str> {
self.other(StringKey::Title)
}
pub fn url(&self) -> Option<&str> {
self.other(StringKey::Url)
}
pub fn username(&self) -> Option<&str> {
self.other(StringKey::Username)
}
}
impl Default for Entry {
fn default() -> Entry {
let now = Utc::now();
Entry {
associations: Vec::new(),
auto_type_def_sequence: String::new(),
auto_type_enabled: true,
auto_type_obfuscation: Obfuscation::None,
background_color: None,
binaries: HashMap::new(),
creation_time: now,
custom_icon_uuid: None,
expires: false,
expiry_time: now,
foreground_color: None,
history: Vec::new(),
icon: Icon::Key,
last_accessed: now,
last_modified: now,
location_changed: now,
override_url: String::new(),
strings: StringsMap::new(),
tags: String::new(),
usage_count: 0,
uuid: EntryUuid::nil(),
parent: GroupUuid::nil(),
}
}
}
impl Times for Entry {
fn creation_time(&self) -> DateTime<Utc> {
self.creation_time
}
fn expires(&self) -> bool {
self.expires
}
fn expiry_time(&self) -> DateTime<Utc> {
self.expiry_time
}
fn last_accessed(&self) -> DateTime<Utc> {
self.last_accessed
}
fn last_modified(&self) -> DateTime<Utc> {
self.last_modified
}
fn location_changed(&self) -> DateTime<Utc> {
self.location_changed
}
fn usage_count(&self) -> i32 {
self.usage_count
}
fn set_creation_time(&mut self, val: DateTime<Utc>) {
self.creation_time = val;
}
fn set_expires(&mut self, val: bool) {
self.expires = val;
}
fn set_expiry_time(&mut self, val: DateTime<Utc>) {
self.expiry_time = val;
}
fn set_last_accessed(&mut self, val: DateTime<Utc>) {
self.last_accessed = val;
}
fn set_last_modified(&mut self, val: DateTime<Utc>) {
self.last_modified = val;
}
fn set_location_changed(&mut self, val: DateTime<Utc>) {
self.location_changed = val;
}
fn set_usage_count(&mut self, val: i32) {
self.usage_count = val;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::EntryUuid;
use crate::types::Icon;
use crate::types::Obfuscation;
use crate::types::StringKey;
use crate::types::StringsMap;
use crate::utils::test::approx_equal_datetime;
use chrono::Utc;
use std::collections::HashMap;
#[test]
fn test_new_returns_correct_instance() {
let now = Utc::now();
let entry = Entry::new();
assert_eq!(entry.associations, Vec::new());
assert_eq!(entry.auto_type_def_sequence, "");
assert_eq!(entry.auto_type_enabled, true);
assert_eq!(entry.auto_type_obfuscation, Obfuscation::None);
assert_eq!(entry.background_color, None);
assert_eq!(entry.binaries, HashMap::new());
assert!(approx_equal_datetime(entry.creation_time, now));
assert_eq!(entry.custom_icon_uuid, None);
assert_eq!(entry.expires, false);
assert!(approx_equal_datetime(entry.expiry_time, now));
assert_eq!(entry.foreground_color, None);
assert_eq!(entry.history, Vec::new());
assert_eq!(entry.icon, Icon::Key);
assert!(approx_equal_datetime(entry.last_accessed, now));
assert!(approx_equal_datetime(entry.last_modified, now));
assert!(approx_equal_datetime(entry.location_changed, now));
assert_eq!(entry.override_url, "");
assert_eq!(entry.strings, StringsMap::new());
assert_eq!(entry.tags, "");
assert_eq!(entry.usage_count, 0);
assert!(entry.uuid != EntryUuid::nil());
}
#[test]
fn test_notes_returns_none_on_default_entry() {
let entry = Entry::default();
assert_eq!(entry.notes(), None);
}
#[test]
fn test_other_returns_none_on_default_entry() {
let entry = Entry::default();
let key = StringKey::from_string("other");
assert_eq!(entry.other(key), None);
}
#[test]
fn test_password_returns_none_on_default_entry() {
let entry = Entry::default();
assert_eq!(entry.password(), None);
}
#[test]
fn test_set_notes_sets_notes() {
let mut entry = Entry::default();
entry.set_notes("test");
assert_eq!(entry.notes(), Some("test"));
}
#[test]
fn test_set_other_sets_other() {
let mut entry = Entry::default();
let key = StringKey::from_string("other");
entry.set_other(key.clone(), "test");
assert_eq!(entry.other(key), Some("test"));
}
#[test]
fn test_set_password_sets_password() {
let mut entry = Entry::default();
entry.set_password("test");
assert_eq!(entry.password(), Some("test"));
}
#[test]
fn test_set_title_sets_title() {
let mut entry = Entry::default();
entry.set_title("test");
assert_eq!(entry.title(), Some("test"));
}
#[test]
fn test_set_url_sets_url() {
let mut entry = Entry::default();
entry.set_url("test");
assert_eq!(entry.url(), Some("test"));
}
#[test]
fn test_set_username_sets_username() {
let mut entry = Entry::default();
entry.set_username("test");
assert_eq!(entry.username(), Some("test"));
}
#[test]
fn test_title_returns_none_on_default_entry() {
let entry = Entry::default();
assert_eq!(entry.title(), None);
}
#[test]
fn test_url_returns_none_on_default_entry() {
let entry = Entry::default();
assert_eq!(entry.url(), None);
}
#[test]
fn test_username_returns_none_on_default_entry() {
let entry = Entry::default();
assert_eq!(entry.username(), None);
}
#[test]
fn test_default_returns_correct_instance() {
let now = Utc::now();
let entry = Entry::default();
assert_eq!(entry.associations, Vec::new());
assert_eq!(entry.auto_type_def_sequence, "");
assert_eq!(entry.auto_type_enabled, true);
assert_eq!(entry.auto_type_obfuscation, Obfuscation::None);
assert_eq!(entry.background_color, None);
assert_eq!(entry.binaries, HashMap::new());
assert!(approx_equal_datetime(entry.creation_time, now));
assert_eq!(entry.custom_icon_uuid, None);
assert_eq!(entry.expires, false);
assert!(approx_equal_datetime(entry.expiry_time, now));
assert_eq!(entry.foreground_color, None);
assert_eq!(entry.history, Vec::new());
assert_eq!(entry.icon, Icon::Key);
assert!(approx_equal_datetime(entry.last_accessed, now));
assert!(approx_equal_datetime(entry.last_modified, now));
assert!(approx_equal_datetime(entry.location_changed, now));
assert_eq!(entry.override_url, "");
assert_eq!(entry.strings, StringsMap::new());
assert_eq!(entry.tags, "");
assert_eq!(entry.usage_count, 0);
assert_eq!(entry.uuid, EntryUuid::nil());
}
}