1use crate::db::models::address::{Address, UpdatableAddressFields};
6use crate::db::models::credit_card::{CreditCard, UpdatableCreditCardFields};
7use crate::db::{addresses, credit_cards, credit_cards::CreditCardsDeletionMetrics, AutofillDb};
8use crate::error::*;
9use error_support::handle_error;
10use rusqlite::{
11 types::{FromSql, ToSql},
12 Connection,
13};
14use sql_support::{self, run_maintenance, ConnExt};
15use std::path::Path;
16use std::sync::{Arc, Mutex, Weak};
17use sync15::engine::{SyncEngine, SyncEngineId};
18use sync_guid::Guid;
19
20lazy_static::lazy_static! {
22 static ref STORE_FOR_MANAGER: Mutex<Weak<Store>> = Mutex::new(Weak::new());
26}
27
28pub fn get_registered_sync_engine(engine_id: &SyncEngineId) -> Option<Box<dyn SyncEngine>> {
31 let weak = STORE_FOR_MANAGER.lock().unwrap();
32 match weak.upgrade() {
33 None => None,
34 Some(store) => match engine_id {
35 SyncEngineId::Addresses => Some(Box::new(crate::sync::address::create_engine(store))),
36 SyncEngineId::CreditCards => {
37 Some(Box::new(crate::sync::credit_card::create_engine(store)))
38 }
39 _ => unreachable!("can't provide unknown engine: {}", engine_id),
42 },
43 }
44}
45
46pub struct Store {
48 pub(crate) db: Mutex<AutofillDb>,
49}
50
51impl Store {
52 #[handle_error(Error)]
53 pub fn new(db_path: impl AsRef<Path>) -> ApiResult<Self> {
54 Ok(Self {
55 db: Mutex::new(AutofillDb::new(db_path)?),
56 })
57 }
58
59 #[cfg(test)]
61 pub fn new_memory() -> Self {
62 Self {
63 db: Mutex::new(crate::db::test::new_mem_db()),
64 }
65 }
66
67 #[handle_error(Error)]
69 pub fn new_shared_memory(db_name: &str) -> ApiResult<Self> {
70 Ok(Self {
71 db: Mutex::new(AutofillDb::new_memory(db_name)?),
72 })
73 }
74
75 #[handle_error(Error)]
76 pub fn add_credit_card(&self, fields: UpdatableCreditCardFields) -> ApiResult<CreditCard> {
77 let credit_card = credit_cards::add_credit_card(&self.db.lock().unwrap().writer, fields)?;
78 Ok(credit_card.into())
79 }
80
81 #[handle_error(Error)]
82 pub fn get_credit_card(&self, guid: String) -> ApiResult<CreditCard> {
83 let credit_card =
84 credit_cards::get_credit_card(&self.db.lock().unwrap().writer, &Guid::new(&guid))?;
85 Ok(credit_card.into())
86 }
87
88 #[handle_error(Error)]
89 pub fn get_all_credit_cards(&self) -> ApiResult<Vec<CreditCard>> {
90 let credit_cards = credit_cards::get_all_credit_cards(&self.db.lock().unwrap().writer)?
91 .into_iter()
92 .map(|x| x.into())
93 .collect();
94 Ok(credit_cards)
95 }
96
97 #[handle_error(Error)]
98 pub fn count_all_credit_cards(&self) -> ApiResult<i64> {
99 let count = credit_cards::count_all_credit_cards(&self.db.lock().unwrap().writer)?;
100 Ok(count)
101 }
102
103 #[handle_error(Error)]
104 pub fn update_credit_card(
105 &self,
106 guid: String,
107 credit_card: UpdatableCreditCardFields,
108 ) -> ApiResult<()> {
109 credit_cards::update_credit_card(
110 &self.db.lock().unwrap().writer,
111 &Guid::new(&guid),
112 &credit_card,
113 )
114 }
115
116 #[handle_error(Error)]
117 pub fn delete_credit_card(&self, guid: String) -> ApiResult<bool> {
118 credit_cards::delete_credit_card(&self.db.lock().unwrap().writer, &Guid::new(&guid))
119 }
120
121 #[handle_error(Error)]
122 pub fn touch_credit_card(&self, guid: String) -> ApiResult<()> {
123 credit_cards::touch(&self.db.lock().unwrap().writer, &Guid::new(&guid))
124 }
125
126 #[handle_error(Error)]
127 pub fn add_address(&self, new_address: UpdatableAddressFields) -> ApiResult<Address> {
128 Ok(addresses::add_address(&self.db.lock().unwrap().writer, new_address)?.into())
129 }
130
131 #[handle_error(Error)]
132 pub fn get_address(&self, guid: String) -> ApiResult<Address> {
133 Ok(addresses::get_address(&self.db.lock().unwrap().writer, &Guid::new(&guid))?.into())
134 }
135
136 #[handle_error(Error)]
137 pub fn get_all_addresses(&self) -> ApiResult<Vec<Address>> {
138 let addresses = addresses::get_all_addresses(&self.db.lock().unwrap().writer)?
139 .into_iter()
140 .map(|x| x.into())
141 .collect();
142 Ok(addresses)
143 }
144
145 #[handle_error(Error)]
146 pub fn count_all_addresses(&self) -> ApiResult<i64> {
147 let count = addresses::count_all_addresses(&self.db.lock().unwrap().writer)?;
148 Ok(count)
149 }
150
151 #[handle_error(Error)]
152 pub fn update_address(&self, guid: String, address: UpdatableAddressFields) -> ApiResult<()> {
153 addresses::update_address(&self.db.lock().unwrap().writer, &Guid::new(&guid), &address)
154 }
155
156 #[handle_error(Error)]
157 pub fn delete_address(&self, guid: String) -> ApiResult<bool> {
158 addresses::delete_address(&self.db.lock().unwrap().writer, &Guid::new(&guid))
159 }
160
161 #[handle_error(Error)]
162 pub fn touch_address(&self, guid: String) -> ApiResult<()> {
163 addresses::touch(&self.db.lock().unwrap().writer, &Guid::new(&guid))
164 }
165
166 #[handle_error(Error)]
167 pub fn scrub_encrypted_data(self: Arc<Self>) -> ApiResult<()> {
168 credit_cards::scrub_encrypted_credit_card_data(&self.db.lock().unwrap().writer)?;
171 crate::sync::credit_card::create_engine(self).reset_local_sync_data()?;
174 Ok(())
175 }
176
177 #[handle_error(Error)]
178 pub fn scrub_undecryptable_credit_card_data_for_remote_replacement(
179 self: Arc<Self>,
180 local_encryption_key: String,
181 ) -> ApiResult<CreditCardsDeletionMetrics> {
182 let db = &self.db.lock().unwrap().writer;
183 let deletion_stats =
184 credit_cards::scrub_undecryptable_credit_card_data_for_remote_replacement(
185 db,
186 local_encryption_key,
187 )?;
188
189 crate::sync::credit_card::create_engine(self.clone())
194 .reset_local_sync_data_for_verification(db)?;
195 Ok(deletion_stats)
196 }
197
198 #[handle_error(Error)]
199 pub fn run_maintenance(&self) -> ApiResult<()> {
200 let conn = self.db.lock().unwrap();
201 run_maintenance(&conn)?;
202 Ok(())
203 }
204
205 pub fn register_with_sync_manager(self: Arc<Self>) {
211 let mut state = STORE_FOR_MANAGER.lock().unwrap();
212 *state = Arc::downgrade(&self);
213 }
214
215 pub fn create_credit_cards_sync_engine(self: Arc<Self>) -> Box<dyn SyncEngine> {
222 Box::new(crate::sync::credit_card::create_engine(self))
223 }
224
225 pub fn create_addresses_sync_engine(self: Arc<Self>) -> Box<dyn SyncEngine> {
226 Box::new(crate::sync::address::create_engine(self))
227 }
228}
229
230pub(crate) fn put_meta(conn: &Connection, key: &str, value: &dyn ToSql) -> Result<()> {
231 conn.execute_cached(
232 "REPLACE INTO moz_meta (key, value) VALUES (:key, :value)",
233 &[(":key", &key as &dyn ToSql), (":value", value)],
234 )?;
235 Ok(())
236}
237
238pub(crate) fn get_meta<T: FromSql>(conn: &Connection, key: &str) -> Result<Option<T>> {
239 let res = conn.try_query_one(
240 "SELECT value FROM moz_meta WHERE key = :key",
241 &[(":key", &key)],
242 true,
243 )?;
244 Ok(res)
245}
246
247pub(crate) fn delete_meta(conn: &Connection, key: &str) -> Result<()> {
248 conn.execute_cached("DELETE FROM moz_meta WHERE key = :key", &[(":key", &key)])?;
249 Ok(())
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255 use crate::db::test::new_mem_db;
256 use crate::encryption::EncryptorDecryptor;
257 use nss::ensure_initialized;
258
259 #[test]
260 fn test_autofill_meta() -> Result<()> {
261 let db = new_mem_db();
262 let test_key = "TEST KEY A";
263 let test_value = "TEST VALUE A";
264 let test_key2 = "TEST KEY B";
265 let test_value2 = "TEST VALUE B";
266
267 put_meta(&db, test_key, &test_value)?;
268 put_meta(&db, test_key2, &test_value2)?;
269
270 let retrieved_value: String = get_meta(&db, test_key)?.expect("test value");
271 let retrieved_value2: String = get_meta(&db, test_key2)?.expect("test value 2");
272
273 assert_eq!(retrieved_value, test_value);
274 assert_eq!(retrieved_value2, test_value2);
275
276 let test_value3 = "TEST VALUE C";
278 put_meta(&db, test_key, &test_value3)?;
279
280 let retrieved_value3: String = get_meta(&db, test_key)?.expect("test value 3");
281
282 assert_eq!(retrieved_value3, test_value3);
283
284 delete_meta(&db, test_key)?;
286 let retrieved_value4: Option<String> = get_meta(&db, test_key)?;
287 assert!(retrieved_value4.is_none());
288
289 db.writer.execute("DELETE FROM moz_meta", [])?;
290
291 Ok(())
292 }
293
294 #[test]
295 fn test_sync_manager_registration() {
296 let store = Arc::new(Store::new_shared_memory("sync-mgr-test").unwrap());
297 assert_eq!(Arc::strong_count(&store), 1);
298 assert_eq!(Arc::weak_count(&store), 0);
299 Arc::clone(&store).register_with_sync_manager();
300 assert_eq!(Arc::strong_count(&store), 1);
301 assert_eq!(Arc::weak_count(&store), 1);
302 let registered = STORE_FOR_MANAGER
303 .lock()
304 .unwrap()
305 .upgrade()
306 .expect("should upgrade");
307 assert!(Arc::ptr_eq(&store, ®istered));
308 drop(registered);
309 assert_eq!(Arc::strong_count(&store), 1);
311 assert_eq!(Arc::weak_count(&store), 1);
312 drop(store);
314 assert!(STORE_FOR_MANAGER.lock().unwrap().upgrade().is_none());
315 }
316
317 #[test]
318 fn test_scrub_undecryptable_credit_card_data_for_remote_replacement() {
319 ensure_initialized();
320 let store = Arc::new(Store::new_shared_memory("sync-mgr-test").expect("create store"));
321 let key = EncryptorDecryptor::create_key().expect("create key");
322 let encdec = EncryptorDecryptor::new(&key).expect("create EncryptorDecryptor");
323
324 store
325 .add_credit_card(UpdatableCreditCardFields {
326 cc_name: "john deer".to_string(),
327 cc_number_enc: encdec
328 .encrypt("567812345678123456781")
329 .expect("encrypt cc number"),
330 cc_number_last_4: "6781".to_string(),
331 cc_exp_month: 10,
332 cc_exp_year: 2025,
333 cc_type: "mastercard".to_string(),
334 })
335 .expect("add credit card to database");
336
337 store
338 .scrub_undecryptable_credit_card_data_for_remote_replacement(key)
339 .expect("scrub credit card record");
340 }
341}