rucksack_db/csv/
firefox.rs1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4use rucksack_lib::time;
5
6use crate::records;
7use crate::records::secrets_from_user_pass;
8
9#[derive(Debug, Default, Deserialize, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct Record {
15 pub url: String,
16 pub username: String,
17 pub password: String,
18 pub http_realm: String,
19 pub form_action_origin: String,
20 pub guid: String,
21 pub time_created: i64,
22 pub time_last_used: i64,
23 pub time_password_changed: i64,
24}
25
26pub fn new(url: String, username: String) -> Record {
27 new_with_password(url, username, "".to_string())
28}
29
30pub fn new_with_password(url: String, username: String, password: String) -> Record {
31 Record {
32 url,
33 username,
34 password,
35
36 ..Default::default()
37 }
38}
39
40impl Record {
41 pub fn to_decrypted(&self) -> records::DecryptedRecord {
42 let secrets = secrets_from_user_pass(self.username.as_str(), self.password.as_str());
43 let mut metadata = records::default_metadata();
44 metadata.name = secrets.user.clone();
45 metadata.url = self.url.clone();
46 metadata.created = time::epoch_to_string(self.time_created);
47 metadata.password_changed = time::epoch_to_string(self.time_password_changed);
48 metadata.last_used = time::epoch_to_string(self.time_last_used);
49 records::DecryptedRecord {
50 secrets,
51 metadata,
52 history: Vec::<records::History>::new(),
53 }
54 }
55}
56
57pub fn from_decrypted(dr: records::DecryptedRecord) -> Record {
58 let md = dr.metadata();
59 let mut name = md.name.clone();
60 if name.is_empty() {
61 name = dr.secrets.user.clone();
62 };
63 Record {
64 url: md.url.clone(),
65 username: name,
66 password: dr.password(),
67 form_action_origin: md.url,
68 guid: Uuid::new_v4().to_string(),
69 time_created: time::string_to_epoch(md.created),
70 time_last_used: time::string_to_epoch(md.last_used),
71 time_password_changed: time::string_to_epoch(md.password_changed),
72
73 ..Default::default()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_new() {
83 let record = new("https://example.com".to_string(), "testuser".to_string());
84 assert_eq!(record.url, "https://example.com");
85 assert_eq!(record.username, "testuser");
86 assert_eq!(record.password, "");
87 }
88
89 #[test]
90 fn test_new_with_password() {
91 let record = new_with_password(
92 "https://example.com".to_string(),
93 "testuser".to_string(),
94 "testpass".to_string(),
95 );
96 assert_eq!(record.url, "https://example.com");
97 assert_eq!(record.username, "testuser");
98 assert_eq!(record.password, "testpass");
99 }
100
101 #[test]
102 fn test_to_decrypted() {
103 let record = new_with_password(
104 "https://example.com".to_string(),
105 "testuser".to_string(),
106 "testpass".to_string(),
107 );
108 let decrypted = record.to_decrypted();
109 assert_eq!(decrypted.secrets.user, "testuser");
110 assert_eq!(decrypted.secrets.password, "testpass");
111 assert_eq!(decrypted.metadata.url, "https://example.com");
112 assert_eq!(decrypted.metadata.name, "testuser");
113 }
114
115 #[test]
116 fn test_to_decrypted_with_timestamps() {
117 let record = Record {
118 url: "https://example.com".to_string(),
119 username: "testuser".to_string(),
120 password: "testpass".to_string(),
121 time_created: 1609459200,
122 time_last_used: 1609545600,
123 time_password_changed: 1609632000,
124 ..Default::default()
125 };
126 let decrypted = record.to_decrypted();
127 assert!(!decrypted.metadata.created.is_empty());
128 assert!(!decrypted.metadata.last_used.is_empty());
129 assert!(!decrypted.metadata.password_changed.is_empty());
130 }
131
132 #[test]
133 fn test_from_decrypted() {
134 let mut decrypted = records::DecryptedRecord {
135 secrets: secrets_from_user_pass("testuser", "testpass"),
136 metadata: records::default_metadata(),
137 history: Vec::new(),
138 };
139 decrypted.metadata.url = "https://example.com".to_string();
140 decrypted.metadata.name = "testuser".to_string();
141
142 let firefox_record = from_decrypted(decrypted.clone());
143 assert_eq!(firefox_record.url, "https://example.com");
144 assert_eq!(firefox_record.username, "testuser");
145 assert_eq!(firefox_record.password, "testpass");
146 assert!(!firefox_record.guid.is_empty());
147 }
148
149 #[test]
150 fn test_from_decrypted_empty_name() {
151 let mut decrypted = records::DecryptedRecord {
152 secrets: secrets_from_user_pass("testuser", "testpass"),
153 metadata: records::default_metadata(),
154 history: Vec::new(),
155 };
156 decrypted.metadata.url = "https://example.com".to_string();
157 decrypted.metadata.name = "".to_string();
158
159 let firefox_record = from_decrypted(decrypted);
160 assert_eq!(firefox_record.username, "testuser");
161 }
162
163 #[test]
164 fn test_default_record() {
165 let record = Record::default();
166 assert_eq!(record.url, "");
167 assert_eq!(record.username, "");
168 assert_eq!(record.password, "");
169 assert_eq!(record.time_created, 0);
170 }
171}