From 4915cb3676cbe1052c5070bfde13417a17144e3a Mon Sep 17 00:00:00 2001 From: Dimi Date: Tue, 3 Jan 2023 08:11:54 +0000 Subject: [PATCH] Bug 1667257 - Detect credit card type by examining IIN part of credit card number r=sgalich Differential Revision: https://phabricator.services.mozilla.com/D164904 --- .../formautofill/content/autofillEditForms.js | 20 ---- .../formautofill/content/editCreditCard.xhtml | 5 - .../skin/shared/editCreditCard.css | 6 +- .../test/browser/creditCard/browser.ini | 2 + .../browser_creditCard_doorhanger.js | 4 +- ...r_creditCard_submission_autodetect_type.js | 110 ++++++++++++++++++ .../browser_creditCard_telemetry.js | 3 - .../browser_editCreditCardDialog.js | 55 --------- .../browser_manageCreditCardsDialog.js | 7 +- .../formautofill/test/browser/head.js | 5 - ...st_basic_creditcard_autocomplete_form.html | 2 - .../test/unit/test_creditCardRecords.js | 25 +--- .../test/unit/test_migrateRecords.js | 8 +- .../formautofill/test/unit/test_reconcile.js | 64 +++++----- .../formautofill/FormAutofillParent.jsm | 15 +-- .../formautofill/FormAutofillStorageBase.jsm | 48 ++++---- toolkit/modules/CreditCard.sys.mjs | 4 + 17 files changed, 193 insertions(+), 190 deletions(-) create mode 100644 browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_submission_autodetect_type.js diff --git a/browser/extensions/formautofill/content/autofillEditForms.js b/browser/extensions/formautofill/content/autofillEditForms.js index b8054edff2b7..88a9364e88e9 100644 --- a/browser/extensions/formautofill/content/autofillEditForms.js +++ b/browser/extensions/formautofill/content/autofillEditForms.js @@ -514,7 +514,6 @@ class EditCreditCard extends EditAutofillForm { ), month: this._elements.form.querySelector("#cc-exp-month"), year: this._elements.form.querySelector("#cc-exp-year"), - ccType: this._elements.form.querySelector("#cc-type"), billingAddress: this._elements.form.querySelector("#billingAddressGUID"), billingAddressRow: this._elements.form.querySelector( ".billingAddressRow" @@ -531,8 +530,6 @@ class EditCreditCard extends EditAutofillForm { this._addresses = addresses; this.generateBillingAddressOptions(preserveFieldValues); if (!preserveFieldValues) { - // Re-populating the networks will reset the selected option. - this.populateNetworks(); // Re-generating the months will reset the selected option. this.generateMonths(); // Re-generating the years will reset the selected option. @@ -591,23 +588,6 @@ class EditCreditCard extends EditAutofillForm { } } - populateNetworks() { - // Clear the list - this._elements.ccType.textContent = ""; - let frag = document.createDocumentFragment(); - // include an empty first option - frag.appendChild(new Option("", "")); - - let supportedNetworks = FormAutofillUtils.getCreditCardNetworks(); - for (let id of supportedNetworks) { - const option = new Option(undefined, id); - // autofill-card-network-amex, ..., autofill-card-network-visa - option.dataset.l10nId = `autofill-card-network-${id}`; - frag.appendChild(option); - } - this._elements.ccType.appendChild(frag); - } - generateBillingAddressOptions(preserveFieldValues) { let billingAddressGUID; if (preserveFieldValues && this._elements.billingAddress.value) { diff --git a/browser/extensions/formautofill/content/editCreditCard.xhtml b/browser/extensions/formautofill/content/editCreditCard.xhtml index c31c55e1a792..a0d8879fdca9 100644 --- a/browser/extensions/formautofill/content/editCreditCard.xhtml +++ b/browser/extensions/formautofill/content/editCreditCard.xhtml @@ -44,11 +44,6 @@ - diff --git a/browser/extensions/formautofill/skin/shared/editCreditCard.css b/browser/extensions/formautofill/skin/shared/editCreditCard.css index 9c701af609cf..00dde3b5b55d 100644 --- a/browser/extensions/formautofill/skin/shared/editCreditCard.css +++ b/browser/extensions/formautofill/skin/shared/editCreditCard.css @@ -6,7 +6,7 @@ display: grid; grid-template-areas: "cc-number cc-exp-month cc-exp-year" - "cc-name cc-type cc-csc" + "cc-name cc-csc ." "billingAddressGUID billingAddressGUID billingAddressGUID"; grid-template-columns: 4fr 2fr 2fr; grid-row-gap: var(--grid-column-row-gap); @@ -40,10 +40,6 @@ grid-area: cc-name; } -#cc-type-container { - grid-area: cc-type; -} - #cc-csc-container { grid-area: cc-csc; } diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser.ini b/browser/extensions/formautofill/test/browser/creditCard/browser.ini index b2c7fe947725..b1d169b9f129 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser.ini +++ b/browser/extensions/formautofill/test/browser/creditCard/browser.ini @@ -21,6 +21,8 @@ skip-if = ((os == "mac") || (os == 'linux') || (os == 'win')) skip-if = ((!debug && os == "mac") || (os == 'linux') || (os == 'win')) [browser_creditCard_heuristics.js] skip-if = apple_silicon && !debug # Bug 1714221 +[browser_creditCard_submission_autodetect_type.js] +skip-if = apple_silicon && !debug [browser_creditCard_submission_normalized.js] skip-if = apple_silicon && !debug [browser_editCreditCardDialog.js] diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_doorhanger.js b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_doorhanger.js index a519a92b22a8..fe019148c966 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_doorhanger.js +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_doorhanger.js @@ -57,7 +57,7 @@ add_task(async function test_submit_creditCard_saved() { focusSelector: "#cc-name", newValues: { "#cc-name": "User 1", - "#cc-number": "5038146897157463", + "#cc-number": "5577000055770004", "#cc-exp-month": "12", "#cc-exp-year": "2017", "#cc-type": "mastercard", @@ -918,7 +918,6 @@ add_task(async function test_submit_third_party_creditCard_logo() { add_task(async function test_update_third_party_creditCard_logo() { const amexCard = { "cc-number": "374542158116607", - "cc-type": "amex", "cc-name": "John Doe", }; @@ -1070,7 +1069,6 @@ add_task(async function test_save_panel_spaces_in_cc_number_logo() { add_task(async function test_update_panel_with_spaces_in_cc_number_logo() { const amexCard = { "cc-number": "374 54215 8116607", - "cc-type": "amex", "cc-name": "John Doe", }; diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_submission_autodetect_type.js b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_submission_autodetect_type.js new file mode 100644 index 000000000000..9609a18939e1 --- /dev/null +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_submission_autodetect_type.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_autodetect_credit_not_set() { + await SpecialPowers.pushPrefEnv({ + set: [[CREDITCARDS_USED_STATUS_PREF, 0]], + }); + const testCard = { + "cc-name": "John Doe", + "cc-number": "4012888888881881", + "cc-exp-month": "06", + "cc-exp-year": "2044", + }; + const expectedData = { + ...testCard, + ...{ "cc-type": "visa" }, + }; + let onChanged = waitForStorageChangedEvents("add"); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: CREDITCARD_FORM_URL }, + async function(browser) { + let promiseShown = waitForPopupShown(); + await focusUpdateSubmitForm(browser, { + focusSelector: "#cc-name", + newValues: { + "#cc-name": testCard["cc-name"], + "#cc-number": testCard["cc-number"], + "#cc-exp-month": testCard["cc-exp-month"], + "#cc-exp-year": testCard["cc-exp-year"], + "#cc-type": testCard["cc-type"], + }, + }); + + await promiseShown; + await clickDoorhangerButton(MAIN_BUTTON); + } + ); + + await onChanged; + + let creditCards = await getCreditCards(); + let savedCreditCard = creditCards[0]; + let decryptedNumber = await OSKeyStore.decrypt( + savedCreditCard["cc-number-encrypted"] + ); + savedCreditCard["cc-number"] = decryptedNumber; + for (let key in testCard) { + let expected = expectedData[key]; + let actual = savedCreditCard[key]; + Assert.equal(expected, actual, `${key} should match`); + } + await removeAllRecords(); +}); + +add_task(async function test_autodetect_credit_overwrite() { + await SpecialPowers.pushPrefEnv({ + set: [[CREDITCARDS_USED_STATUS_PREF, 0]], + }); + const testCard = { + "cc-name": "John Doe", + "cc-number": "4012888888881881", + "cc-exp-month": "06", + "cc-exp-year": "2044", + "cc-type": "master", // Wrong credit card type + }; + const expectedData = { + ...testCard, + ...{ "cc-type": "visa" }, + }; + let onChanged = waitForStorageChangedEvents("add"); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: CREDITCARD_FORM_URL }, + async function(browser) { + let promiseShown = waitForPopupShown(); + await focusUpdateSubmitForm(browser, { + focusSelector: "#cc-name", + newValues: { + "#cc-name": testCard["cc-name"], + "#cc-number": testCard["cc-number"], + "#cc-exp-month": testCard["cc-exp-month"], + "#cc-exp-year": testCard["cc-exp-year"], + "#cc-type": testCard["cc-type"], + }, + }); + + await promiseShown; + await clickDoorhangerButton(MAIN_BUTTON); + } + ); + + await onChanged; + + let creditCards = await getCreditCards(); + let savedCreditCard = creditCards[0]; + let decryptedNumber = await OSKeyStore.decrypt( + savedCreditCard["cc-number-encrypted"] + ); + savedCreditCard["cc-number"] = decryptedNumber; + for (let key in testCard) { + let expected = expectedData[key]; + let actual = savedCreditCard[key]; + Assert.equal(expected, actual, `${key} should match`); + } + + await removeAllRecords(); +}); diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js index 0ae0b430caa9..7415c3d7b9bf 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js @@ -663,8 +663,6 @@ add_task(async function test_saveCreditCard() { EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey(TEST_CREDIT_CARD_1["cc-name"], {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey(TEST_CREDIT_CARD_1["cc-type"], {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); info("saving credit card"); EventUtils.synthesizeKey("VK_RETURN", {}, win); @@ -693,7 +691,6 @@ add_task(async function test_editCreditCard() { EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_RIGHT", {}, win); EventUtils.synthesizeKey("test", {}, win); win.document.querySelector("#save").click(); diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js b/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js index 8659ea7daa49..97fb7f9f1abe 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js @@ -49,8 +49,6 @@ add_task(async function test_saveCreditCard() { EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey(TEST_CREDIT_CARD_1["cc-name"], {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey(TEST_CREDIT_CARD_1["cc-type"], {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); info("saving credit card"); EventUtils.synthesizeKey("VK_RETURN", {}, win); @@ -87,9 +85,6 @@ add_task(async function test_saveCreditCardWithMaxYear() { EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey(TEST_CREDIT_CARD_2["cc-name"], {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey(TEST_CREDIT_CARD_1["cc-type"], {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); info("saving credit card"); EventUtils.synthesizeKey("VK_RETURN", {}, win); }); @@ -133,8 +128,6 @@ add_task(async function test_saveCreditCardWithBillingAddress() { EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey(TEST_CREDIT_CARD["cc-name"], {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey(TEST_CREDIT_CARD["cc-type"], {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); EventUtils.synthesizeKey(billingAddress["given-name"], {}, win); EventUtils.synthesizeKey("VK_TAB", {}, win); info("saving credit card"); @@ -271,54 +264,6 @@ add_task(async function test_addInvalidCreditCard() { is(creditCards.length, 0, "Credit card storage is empty"); }); -add_task(async function test_editCardWithInvalidNetwork() { - const TEST_CREDIT_CARD = Object.assign({}, TEST_CREDIT_CARD_2, { - "cc-type": "asiv", - }); - await setStorage(TEST_CREDIT_CARD); - - let creditCards = await getCreditCards(); - is(creditCards.length, 1, "one credit card in storage"); - is( - creditCards[0]["cc-type"], - TEST_CREDIT_CARD["cc-type"], - "Check saved cc-type" - ); - await testDialog( - EDIT_CREDIT_CARD_DIALOG_URL, - win => { - EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_TAB", {}, win); - EventUtils.synthesizeKey("VK_RIGHT", {}, win); - EventUtils.synthesizeKey("test", {}, win); - win.document.querySelector("#save").click(); - }, - { - record: creditCards[0], - } - ); - ok(true, "Edit credit card dialog is closed"); - creditCards = await getCreditCards(); - - is(creditCards.length, 1, "only one credit card is in storage"); - is( - creditCards[0]["cc-name"], - TEST_CREDIT_CARD["cc-name"] + "test", - "cc name changed" - ); - is( - creditCards[0]["cc-type"], - "visa", - "unknown cc-type removed and next autodetected to visa upon manual save" - ); - await removeCreditCards([creditCards[0].guid]); - - creditCards = await getCreditCards(); - is(creditCards.length, 0, "Credit card storage is empty"); -}); - add_task(async function test_editInvalidCreditCardNumber() { await setStorage(TEST_ADDRESS_4); let addresses = await getAddresses(); diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_manageCreditCardsDialog.js b/browser/extensions/formautofill/test/browser/creditCard/browser_manageCreditCardsDialog.js index c79bac5c9dc0..627221e28d7b 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_manageCreditCardsDialog.js +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_manageCreditCardsDialog.js @@ -189,10 +189,7 @@ add_task(async function test_showCreditCardIcons() { set: [["privacy.reduceTimerPrecision", false]], }); await setStorage(TEST_CREDIT_CARD_1); - let unknownCard = Object.assign({}, TEST_CREDIT_CARD_3, { - "cc-type": "gringotts", - }); - await setStorage(unknownCard); + await setStorage(TEST_CREDIT_CARD_3); let win = window.openDialog( MANAGE_CREDIT_CARDS_DIALOG_URL, @@ -216,7 +213,7 @@ add_task(async function test_showCreditCardIcons() { is( option0.getAttribute("cc-type"), - "gringotts", + "mastercard", "Option has the expected cc-type" ); is( diff --git a/browser/extensions/formautofill/test/browser/head.js b/browser/extensions/formautofill/test/browser/head.js index 3a0a58d8f475..2422a28a0fc3 100644 --- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -148,7 +148,6 @@ const TEST_CREDIT_CARD_1 = { "cc-number": "4111111111111111", "cc-exp-month": 4, "cc-exp-year": new Date().getFullYear(), - "cc-type": "visa", }; const TEST_CREDIT_CARD_2 = { @@ -156,25 +155,21 @@ const TEST_CREDIT_CARD_2 = { "cc-number": "4929001587121045", "cc-exp-month": 12, "cc-exp-year": new Date().getFullYear() + 10, - "cc-type": "visa", }; const TEST_CREDIT_CARD_3 = { "cc-number": "5103059495477870", "cc-exp-month": 1, "cc-exp-year": 2000, - "cc-type": "mastercard", }; const TEST_CREDIT_CARD_4 = { "cc-number": "5105105105105100", - "cc-type": "mastercard", }; const TEST_CREDIT_CARD_5 = { "cc-name": "Chris P. Bacon", "cc-number": "4012888888881881", - "cc-type": "visa", }; const MAIN_BUTTON = "button"; diff --git a/browser/extensions/formautofill/test/mochitest/creditCard/test_basic_creditcard_autocomplete_form.html b/browser/extensions/formautofill/test/mochitest/creditCard/test_basic_creditcard_autocomplete_form.html index b362f2388a85..0764bef0eb95 100644 --- a/browser/extensions/formautofill/test/mochitest/creditCard/test_basic_creditcard_autocomplete_form.html +++ b/browser/extensions/formautofill/test/mochitest/creditCard/test_basic_creditcard_autocomplete_form.html @@ -20,13 +20,11 @@ const MOCK_STORAGE = [{ "cc-number": "4929001587121045", "cc-exp-month": 4, "cc-exp-year": 2017, - "cc-type": "visa", }, { "cc-name": "Timothy Berners-Lee", "cc-number": "5103059495477870", "cc-exp-month": 12, "cc-exp-year": 2022, - "cc-type": "mastercard", }]; const reducedMockRecord = { diff --git a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js index a20c51b85785..b65364c81557 100644 --- a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js +++ b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js @@ -12,10 +12,14 @@ const { CreditCard } = ChromeUtils.importESModule( ); let FormAutofillStorage; +let CREDIT_CARD_SCHEMA_VERSION; add_setup(async () => { ({ FormAutofillStorage } = ChromeUtils.import( "resource://autofill/FormAutofillStorage.jsm" )); + ({ CREDIT_CARD_SCHEMA_VERSION } = ChromeUtils.import( + "resource://autofill/FormAutofillStorageBase.jsm" + )); }); const TEST_STORE_FILE_NAME = "test-credit-card.json"; @@ -26,7 +30,6 @@ const TEST_CREDIT_CARD_1 = { "cc-number": "4929001587121045", "cc-exp-month": 4, "cc-exp-year": 2017, - "cc-type": "visa", }; const TEST_CREDIT_CARD_2 = { @@ -34,20 +37,17 @@ const TEST_CREDIT_CARD_2 = { "cc-number": "5103059495477870", "cc-exp-month": 12, "cc-exp-year": 2022, - "cc-type": "mastercard", }; const TEST_CREDIT_CARD_3 = { "cc-number": "3589993783099582", "cc-exp-month": 1, "cc-exp-year": 2000, - "cc-type": "amex", }; const TEST_CREDIT_CARD_4 = { "cc-name": "Foo Bar", "cc-number": "3589993783099582", - "cc-type": "amex", }; const TEST_CREDIT_CARD_WITH_BILLING_ADDRESS = { @@ -61,7 +61,6 @@ const TEST_CREDIT_CARD_WITH_EMPTY_FIELD = { "cc-name": "", "cc-number": "344060747836806", "cc-exp-month": 1, - "cc-type": "", }; const TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD = { @@ -96,14 +95,6 @@ const TEST_CREDIT_CARD_WITH_SPACES_BETWEEN_DIGITS = { "cc-number": "5103 0594 9547 7870", }; -const TEST_CREDIT_CARD_WITH_INVALID_NETWORK = { - "cc-name": "John Doe", - "cc-number": "4929001587121045", - "cc-exp-month": 4, - "cc-exp-year": 2017, - "cc-type": "asiv", -}; - const TEST_CREDIT_CARD_EMPTY_AFTER_NORMALIZE = { "cc-exp-month": 13, }; @@ -332,7 +323,7 @@ add_task(async function test_add() { do_check_credit_card_matches(creditCards[1], TEST_CREDIT_CARD_2); Assert.notEqual(creditCards[0].guid, undefined); - Assert.equal(creditCards[0].version, 3); + Assert.equal(creditCards[0].version, CREDIT_CARD_SCHEMA_VERSION); Assert.notEqual(creditCards[0].timeCreated, undefined); Assert.equal(creditCards[0].timeLastModified, creditCards[0].timeCreated); Assert.equal(creditCards[0].timeLastUsed, 0); @@ -543,8 +534,6 @@ add_task(async function test_validate() { await profileStorage.creditCards.add( TEST_CREDIT_CARD_WITH_SPACES_BETWEEN_DIGITS ); - await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_NETWORK); - let creditCards = await profileStorage.creditCards.getAll(); Assert.equal(creditCards[0]["cc-exp-month"], undefined); @@ -562,10 +551,6 @@ add_task(async function test_validate() { ); Assert.equal(creditCards[2]["cc-number"].length, 16); - - // dont enforce validity on the card network when storing a record, - // to avoid data loss when syncing records between different clients with different rules - Assert.equal(creditCards[3]["cc-type"], "asiv"); }); add_task(async function test_notifyUsed() { diff --git a/browser/extensions/formautofill/test/unit/test_migrateRecords.js b/browser/extensions/formautofill/test/unit/test_migrateRecords.js index 0983b4af987b..b3107e6ffa2d 100644 --- a/browser/extensions/formautofill/test/unit/test_migrateRecords.js +++ b/browser/extensions/formautofill/test/unit/test_migrateRecords.js @@ -13,8 +13,12 @@ add_setup(async () => { const TEST_STORE_FILE_NAME = "test-profile.json"; -const ADDRESS_SCHEMA_VERSION = 1; -const CREDIT_CARD_SCHEMA_VERSION = 3; +const { ADDRESS_SCHEMA_VERSION } = ChromeUtils.import( + "resource://autofill/FormAutofillStorageBase.jsm" +); +const { CREDIT_CARD_SCHEMA_VERSION } = ChromeUtils.import( + "resource://autofill/FormAutofillStorageBase.jsm" +); const ADDRESS_TESTCASES = [ { diff --git a/browser/extensions/formautofill/test/unit/test_reconcile.js b/browser/extensions/formautofill/test/unit/test_reconcile.js index 319a03d3cc90..4f8de87b6c29 100644 --- a/browser/extensions/formautofill/test/unit/test_reconcile.js +++ b/browser/extensions/formautofill/test/unit/test_reconcile.js @@ -1,7 +1,9 @@ "use strict"; const TEST_STORE_FILE_NAME = "test-profile.json"; -const CURRENT_CC_VERSION = 3; +const { CREDIT_CARD_SCHEMA_VERSION } = ChromeUtils.import( + "resource://autofill/FormAutofillStorageBase.jsm" +); // NOTE: a guide to reading these test-cases: // parent: What the local record looked like the last time we wrote the @@ -502,7 +504,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ parent: { // So when we last wrote the record to the server, it had these values. guid: "2bbd2d8fbc6b", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -519,7 +521,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ // we can deduce the record hasn't actually been changed remotely so we // can safely ignore the incoming record and write our local changes. guid: "2bbd2d8fbc6b", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -533,7 +535,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Remote change", parent: { guid: "e3680e9f890d", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -545,7 +547,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "e3680e9f890d", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4929001587121045", }, @@ -560,7 +562,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "New local field", parent: { guid: "0cba738b1be0", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -573,7 +575,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "0cba738b1be0", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -588,7 +590,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "New remote field", parent: { guid: "be3ef97f8285", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -600,7 +602,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "be3ef97f8285", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -616,7 +618,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Deleted field locally", parent: { guid: "9627322248ec", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -629,7 +631,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "9627322248ec", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -644,7 +646,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Deleted field remotely", parent: { guid: "7d7509f3eeb2", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -658,7 +660,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "7d7509f3eeb2", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -673,7 +675,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ parent: { // The last time we wrote this to the server, "cc-exp-month" was 12. guid: "e087a06dfc57", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -689,7 +691,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ remote: { // Remotely, we've changed "cc-exp-month" to 1. guid: "e087a06dfc57", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 1, @@ -705,7 +707,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Multiple local changes", parent: { guid: "340a078c596f", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -722,7 +724,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "340a078c596f", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-year": 2000, @@ -741,7 +743,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Same change to local and remote", parent: { guid: "0b3a72a1bea2", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -753,7 +755,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "0b3a72a1bea2", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4929001587121045", }, @@ -768,7 +770,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ parent: { // This is what we last wrote to the sync server. guid: "62068784d089", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -782,7 +784,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ remote: { // An incoming record has a different cc-number than any of the above! guid: "62068784d089", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4929001587121045", }, @@ -803,7 +805,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Conflicting changes to multiple fields", parent: { guid: "244dbb692e94", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -817,7 +819,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "244dbb692e94", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4929001587121045", "cc-exp-month": 3, @@ -838,7 +840,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Field deleted locally, changed remotely", parent: { guid: "6fc45e03d19a", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -851,7 +853,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "6fc45e03d19a", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 3, @@ -871,7 +873,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ description: "Field changed locally, deleted remotely", parent: { guid: "fff9fa27fa18", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", "cc-exp-month": 12, @@ -885,7 +887,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "fff9fa27fa18", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", }, @@ -908,7 +910,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ "Created, last modified time reconciliation without local changes", parent: { guid: "5113f329c42f", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", timeCreated: 1234, @@ -919,7 +921,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ local: [], remote: { guid: "5113f329c42f", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", timeCreated: 1200, @@ -944,7 +946,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ "Created, last modified time reconciliation with local changes", parent: { guid: "791e5608b80a", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", timeCreated: 1234, @@ -960,7 +962,7 @@ const CREDIT_CARD_RECONCILE_TESTCASES = [ ], remote: { guid: "791e5608b80a", - version: CURRENT_CC_VERSION, + version: CREDIT_CARD_SCHEMA_VERSION, "cc-name": "John Doe", "cc-number": "4111111111111111", timeCreated: 1300, diff --git a/toolkit/components/formautofill/FormAutofillParent.jsm b/toolkit/components/formautofill/FormAutofillParent.jsm index 936ede44dded..3f33f11d0cac 100644 --- a/toolkit/components/formautofill/FormAutofillParent.jsm +++ b/toolkit/components/formautofill/FormAutofillParent.jsm @@ -44,7 +44,6 @@ const { FormAutofillUtils } = ChromeUtils.import( const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { - CreditCard: "resource://gre/modules/CreditCard.sys.mjs", OSKeyStore: "resource://gre/modules/OSKeyStore.sys.mjs", }); @@ -615,15 +614,11 @@ class FormAutofillParent extends JSWindowActorParent { } }; - // Remove invalid cc-type values - if ( - creditCard.record["cc-type"] && - !lazy.CreditCard.isValidNetwork(creditCard.record["cc-type"]) - ) { - // Let's reset the credit card to empty, and then network auto-detect will - // pick it up. - creditCard.record["cc-type"] = ""; - } + // Remove cc-type values + // Let's reset the credit card to empty, and then network auto-detect will + // pick it up. + //creditCard.record["cc-type"] = ""; + delete creditCard.record["cc-type"]; // If `guid` is present, the form has been autofilled. if (creditCard.guid) { diff --git a/toolkit/components/formautofill/FormAutofillStorageBase.jsm b/toolkit/components/formautofill/FormAutofillStorageBase.jsm index 8c3a960b3aa0..2f19c29ef5e9 100644 --- a/toolkit/components/formautofill/FormAutofillStorageBase.jsm +++ b/toolkit/components/formautofill/FormAutofillStorageBase.jsm @@ -67,10 +67,10 @@ * cc-exp-month, * cc-exp-year, // 2-digit year will be converted to 4 digits * // upon saving - * cc-type, // Optional card network id (instrument type) * * // computed fields (These fields are computed based on the above fields * // and are not allowed to be modified directly.) + * cc-type, // Optional card network id (instrument type) * cc-given-name, * cc-additional-name, * cc-family-name, @@ -128,6 +128,8 @@ const EXPORTED_SYMBOLS = [ "FormAutofillStorageBase", "CreditCardsBase", "AddressesBase", + "ADDRESS_SCHEMA_VERSION", + "CREDIT_CARD_SCHEMA_VERSION", ]; const { XPCOMUtils } = ChromeUtils.importESModule( @@ -158,7 +160,11 @@ const CryptoHash = Components.Constructor( const STORAGE_SCHEMA_VERSION = 1; const ADDRESS_SCHEMA_VERSION = 1; -const CREDIT_CARD_SCHEMA_VERSION = 3; + +// Version 2: Bug 1486954 - Encrypt `cc-number` +// Version 3: Bug 1639795 - Update keystore name +// Version 4: Bug 1667257 - Do not store `cc-type` field +const CREDIT_CARD_SCHEMA_VERSION = 4; const VALID_ADDRESS_FIELDS = [ "given-name", @@ -201,10 +207,10 @@ const VALID_CREDIT_CARD_FIELDS = [ "cc-number", "cc-exp-month", "cc-exp-year", - "cc-type", ]; const VALID_CREDIT_CARD_COMPUTED_FIELDS = [ + "cc-type", "cc-given-name", "cc-additional-name", "cc-family-name", @@ -1700,11 +1706,9 @@ class CreditCardsBase extends AutofillRecords { return hasNewComputedFields; } - if ("cc-number" in creditCard && !("cc-type" in creditCard)) { - let type = lazy.CreditCard.getType(creditCard["cc-number"]); - if (type) { - creditCard["cc-type"] = type; - } + let type = lazy.CreditCard.getType(creditCard["cc-number"]); + if (type) { + creditCard["cc-type"] = type; } // Compute split names @@ -1742,16 +1746,11 @@ class CreditCardsBase extends AutofillRecords { } async _computeMigratedRecord(creditCard) { - if (creditCard["cc-number-encrypted"]) { - switch (creditCard.version) { - case 1: - case 2: { - // We cannot decrypt the data, so silently remove the record for - // the user. - if (creditCard.deleted) { - break; - } - + if (creditCard.version <= 2) { + if (creditCard["cc-number-encrypted"]) { + // We cannot decrypt the data, so silently remove the record for + // the user. + if (!creditCard.deleted) { this.log.warn( "Removing version", creditCard.version, @@ -1772,15 +1771,16 @@ class CreditCardsBase extends AutofillRecords { creditCard._sync = existingSync; existingSync.changeCounter++; } - break; } - - default: - throw new Error( - "Unknown credit card version to migrate: " + creditCard.version - ); } } + + if (creditCard.version <= 3) { + if (creditCard["cc-type"]) { + delete creditCard["cc-type"]; + } + } + return super._computeMigratedRecord(creditCard); } diff --git a/toolkit/modules/CreditCard.sys.mjs b/toolkit/modules/CreditCard.sys.mjs index 781ce3e89478..40dd83731813 100644 --- a/toolkit/modules/CreditCard.sys.mjs +++ b/toolkit/modules/CreditCard.sys.mjs @@ -236,6 +236,10 @@ export class CreditCard { * @returns {string|null} */ static getType(ccNumber) { + if (!ccNumber) { + return null; + } + for (let i = 0; i < CREDIT_CARD_IIN.length; i++) { const range = CREDIT_CARD_IIN[i]; if (typeof range.len == "number") {