Skip to main content

bitwarden_importers/importers/onepassword/convert/
card.rs

1//! The Credit Card category.
2
3use bitwarden_exporters::Card;
4
5use super::{claimed::Claimed, value::month_year};
6use crate::importers::onepassword::access::wire::{VaultItemDetails, VaultItemSectionField};
7
8/// Reads a payment card. Every slot is optional, so an item that fills none of them still becomes
9/// a card rather than losing its category.
10pub(super) fn card(details: &VaultItemDetails) -> (Card, Claimed) {
11    let mut claimed = Claimed::default();
12    let (exp_month, exp_year) = claimed.take(details, "expiry", expiry).unzip();
13
14    let card = Card {
15        cardholder_name: claimed.take_text(details, "cardholder"),
16        exp_month,
17        exp_year,
18        code: claimed.take_text(details, "cvv"),
19        // An unrecognized card type stays a custom field rather than reaching the vault as a brand
20        // Bitwarden does not know.
21        brand: claimed.take(details, "type", |field| {
22            card_brand(field.value.as_ref()?.as_str()?)
23        }),
24        number: claimed.take_text(details, "ccnum"),
25    };
26
27    (card, claimed)
28}
29
30/// Splits 1Password's `202811` into the month and year Bitwarden keeps apart. The month drops its
31/// leading zero, the form the rest of the vault uses.
32fn expiry(field: &VaultItemSectionField) -> Option<(String, String)> {
33    let (year, month) = month_year(field.value.as_ref()?.as_i64()?)?;
34    Some((month.to_string(), year.to_string()))
35}
36
37/// Maps a 1Password card type onto a Bitwarden brand. 1Password writes its own ids, so `mc` and
38/// `diners` have to be spelled out rather than passed through.
39pub(super) fn card_brand(kind: &str) -> Option<String> {
40    let brand = match kind.to_lowercase().replace(' ', "").as_str() {
41        "visa" => "Visa",
42        "mc" | "mastercard" => "Mastercard",
43        "amex" | "americanexpress" => "Amex",
44        "discover" => "Discover",
45        "diners" | "dinersclub" => "Diners Club",
46        "jcb" => "JCB",
47        "maestro" => "Maestro",
48        "unionpay" => "UnionPay",
49        "rupay" => "RuPay",
50        _ => return None,
51    };
52
53    Some(brand.to_string())
54}