autofill/db/models/
credit_card.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2* License, v. 2.0. If a copy of the MPL was not distributed with this
3* file, You can obtain one at http://mozilla.org/MPL/2.0/.
4*/
5
6use super::Metadata;
7use rusqlite::Row;
8use sync_guid::Guid;
9use types::Timestamp;
10
11#[derive(Debug, Clone, Default)]
12pub struct UpdatableCreditCardFields {
13    pub cc_name: String,
14    pub cc_number_enc: String,
15    pub cc_number_last_4: String,
16    pub cc_exp_month: i64,
17    pub cc_exp_year: i64,
18    // Credit card types are a fixed set of strings as defined in the link below
19    // (https://searchfox.org/mozilla-central/rev/7ef5cefd0468b8f509efe38e0212de2398f4c8b3/toolkit/modules/CreditCard.jsm#9-22)
20    pub cc_type: String,
21}
22
23/// Metadata fields managed internally by the library: the guid, timestamps and
24/// local sync state. These are automatically set on `add_credit_card` and
25/// updated on operations like `touch` and `update_credit_card`. Not included in
26/// `UpdatableCreditCardFields`; use `add_credit_card_with_meta` when importing
27/// records that already have metadata.
28#[derive(Debug, Clone, Default)]
29pub struct CreditCardMeta {
30    pub guid: String,
31    pub time_created: i64,
32    pub time_last_used: Option<i64>,
33    pub time_last_modified: i64,
34    pub times_used: i64,
35    /// Local changes not yet uploaded; 0 means it matches what was last synced.
36    pub sync_change_counter: i64,
37}
38
39/// A tombstone for a record deleted locally but not yet uploaded, supplied to
40/// `add_many_credit_card_tombstones` when migrating from another store.
41#[derive(Debug, Clone, Default)]
42pub struct CreditCardTombstone {
43    pub guid: String,
44    pub time_deleted: i64,
45}
46
47/// Per-record result of `add_many_credit_card_tombstones`.
48#[derive(Debug)]
49pub enum CreditCardBulkTombstoneResultEntry {
50    Success { guid: String },
51    Error { message: String },
52}
53
54/// A credit card together with its metadata, passed to
55/// `add_credit_card_with_meta` and `update_credit_card_with_meta` when importing
56/// a record from another store.
57#[derive(Debug, Clone, Default)]
58pub struct UpdatableCreditCardFieldsWithMeta {
59    pub fields: UpdatableCreditCardFields,
60    pub meta: CreditCardMeta,
61}
62
63/// A bulk insert result entry, returned per input record by
64/// `add_many_credit_cards_with_meta` so that one record failing does not abort
65/// the batch. Note that although the success case is much larger than the error
66/// case, this is negligible in real life, as we expect a very small
67/// success/error ratio.
68#[allow(clippy::large_enum_variant)]
69#[derive(Debug)]
70pub enum CreditCardBulkResultEntry {
71    Success { credit_card: CreditCard },
72    Error { message: String },
73}
74
75#[derive(Debug, Clone, Default)]
76pub struct CreditCard {
77    pub guid: String,
78    pub cc_name: String,
79    pub cc_number_enc: String,
80    pub cc_number_last_4: String,
81    pub cc_exp_month: i64,
82    pub cc_exp_year: i64,
83
84    // Credit card types are a fixed set of strings as defined in the link below
85    // (https://searchfox.org/mozilla-central/rev/7ef5cefd0468b8f509efe38e0212de2398f4c8b3/toolkit/modules/CreditCard.jsm#9-22)
86    pub cc_type: String,
87
88    // The metadata
89    pub time_created: i64,
90    pub time_last_used: Option<i64>,
91    pub time_last_modified: i64,
92    pub times_used: i64,
93}
94
95// This is used to "externalize" a credit-card, suitable for handing back to
96// consumers.
97impl From<InternalCreditCard> for CreditCard {
98    fn from(icc: InternalCreditCard) -> Self {
99        CreditCard {
100            guid: icc.guid.to_string(),
101            cc_name: icc.cc_name,
102            cc_number_enc: icc.cc_number_enc,
103            cc_number_last_4: icc.cc_number_last_4,
104            cc_exp_month: icc.cc_exp_month,
105            cc_exp_year: icc.cc_exp_year,
106            cc_type: icc.cc_type,
107            // note we can't use u64 in uniffi
108            time_created: u64::from(icc.metadata.time_created) as i64,
109            time_last_used: if icc.metadata.time_last_used.0 == 0 {
110                None
111            } else {
112                Some(icc.metadata.time_last_used.0 as i64)
113            },
114            time_last_modified: u64::from(icc.metadata.time_last_modified) as i64,
115            times_used: icc.metadata.times_used,
116        }
117    }
118}
119
120// NOTE: No `PartialEq` here because the same card number will encrypt to a
121// different value each time it is encrypted, making it meaningless to compare.
122#[derive(Debug, Clone, Default)]
123pub struct InternalCreditCard {
124    pub guid: Guid,
125    pub cc_name: String,
126    pub cc_number_enc: String,
127    pub cc_number_last_4: String,
128    pub cc_exp_month: i64,
129    pub cc_exp_year: i64,
130    // Credit card types are a fixed set of strings as defined in the link below
131    // (https://searchfox.org/mozilla-central/rev/7ef5cefd0468b8f509efe38e0212de2398f4c8b3/toolkit/modules/CreditCard.jsm#9-22)
132    pub cc_type: String,
133    pub metadata: Metadata,
134}
135
136impl InternalCreditCard {
137    pub fn from_row(row: &Row<'_>) -> Result<InternalCreditCard, rusqlite::Error> {
138        Ok(Self {
139            guid: Guid::from_string(row.get("guid")?),
140            cc_name: row.get("cc_name")?,
141            cc_number_enc: row.get("cc_number_enc")?,
142            cc_number_last_4: row.get("cc_number_last_4")?,
143            cc_exp_month: row.get("cc_exp_month")?,
144            cc_exp_year: row.get("cc_exp_year")?,
145            cc_type: row.get("cc_type")?,
146            metadata: Metadata {
147                time_created: row.get::<_, Timestamp>("time_created")?.sanitized(),
148                time_last_used: row.get::<_, Timestamp>("time_last_used")?.sanitized(),
149                time_last_modified: row.get::<_, Timestamp>("time_last_modified")?.sanitized(),
150                times_used: row.get("times_used")?,
151                sync_change_counter: row.get("sync_change_counter")?,
152            },
153        })
154    }
155
156    pub fn has_scrubbed_data(&self) -> bool {
157        self.cc_number_enc.is_empty()
158    }
159}