tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_Chrome_credit_cards.js (7246B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* global structuredClone */
      7 
      8 const PROFILE = {
      9  id: "Default",
     10  name: "Default",
     11 };
     12 
     13 const PAYMENT_METHODS = [
     14  {
     15    name_on_card: "Name Name",
     16    card_number: "4532962432748929", // Visa
     17    expiration_month: 3,
     18    expiration_year: 2027,
     19  },
     20  {
     21    name_on_card: "Name Name Name",
     22    card_number: "5359908373796416", // Mastercard
     23    expiration_month: 5,
     24    expiration_year: 2028,
     25  },
     26  {
     27    name_on_card: "Name",
     28    card_number: "346624461807588", // AMEX
     29    expiration_month: 4,
     30    expiration_year: 2026,
     31  },
     32 ];
     33 
     34 let OSKeyStoreTestUtils;
     35 add_setup(async function os_key_store_setup() {
     36  ({ OSKeyStoreTestUtils } = ChromeUtils.importESModule(
     37    "resource://testing-common/OSKeyStoreTestUtils.sys.mjs"
     38  ));
     39  OSKeyStoreTestUtils.setup();
     40  registerCleanupFunction(async function cleanup() {
     41    await OSKeyStoreTestUtils.cleanup();
     42  });
     43 });
     44 
     45 let rootDir = do_get_file("chromefiles/", true);
     46 
     47 function checkCardsAreEqual(importedCard, testCard, id) {
     48  const CC_NUMBER_RE = /^(\*+)(.{4})$/;
     49 
     50  Assert.equal(
     51    importedCard["cc-name"],
     52    testCard.name_on_card,
     53    "The two logins ID " + id + " have the same name on card"
     54  );
     55 
     56  let matches = CC_NUMBER_RE.exec(importedCard["cc-number"]);
     57  Assert.notEqual(matches, null);
     58  Assert.equal(importedCard["cc-number"].length, testCard.card_number.length);
     59  Assert.equal(testCard.card_number.endsWith(matches[2]), true);
     60  Assert.notEqual(importedCard["cc-number-encrypted"], "");
     61 
     62  Assert.equal(
     63    importedCard["cc-exp-month"],
     64    testCard.expiration_month,
     65    "The two logins ID " + id + " have the same expiration month"
     66  );
     67  Assert.equal(
     68    importedCard["cc-exp-year"],
     69    testCard.expiration_year,
     70    "The two logins ID " + id + " have the same expiration year"
     71  );
     72 }
     73 
     74 add_task(async function setup_fakePaths() {
     75  let pathId;
     76  if (AppConstants.platform == "macosx") {
     77    pathId = "ULibDir";
     78  } else if (AppConstants.platform == "win") {
     79    pathId = "LocalAppData";
     80  } else {
     81    pathId = "Home";
     82  }
     83  registerFakePath(pathId, rootDir);
     84 });
     85 
     86 add_task(async function test_credit_cards() {
     87  if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
     88    todo_check_true(
     89      OSKeyStoreTestUtils.canTestOSKeyStoreLogin(),
     90      "Cannot test OS key store login on official builds."
     91    );
     92    return;
     93  }
     94 
     95  let loginCrypto;
     96  let profilePathSegments;
     97 
     98  let mockMacOSKeychain = {
     99    passphrase: "bW96aWxsYWZpcmVmb3g=",
    100    serviceName: "TESTING Chrome Safe Storage",
    101    accountName: "TESTING Chrome",
    102  };
    103  if (AppConstants.platform == "macosx") {
    104    let { ChromeMacOSLoginCrypto } = ChromeUtils.importESModule(
    105      "resource:///modules/ChromeMacOSLoginCrypto.sys.mjs"
    106    );
    107    loginCrypto = new ChromeMacOSLoginCrypto(
    108      mockMacOSKeychain.serviceName,
    109      mockMacOSKeychain.accountName,
    110      mockMacOSKeychain.passphrase
    111    );
    112    profilePathSegments = [
    113      "Application Support",
    114      "Google",
    115      "Chrome",
    116      "Default",
    117    ];
    118  } else if (AppConstants.platform == "win") {
    119    // We no longer support importing payment methods from Chrome on Windows,
    120    // but we can still do it for some other Chrome-based browsers like Canary.
    121    let { ChromeWindowsLoginCrypto } = ChromeUtils.importESModule(
    122      "resource:///modules/ChromeWindowsLoginCrypto.sys.mjs"
    123    );
    124    loginCrypto = new ChromeWindowsLoginCrypto("Chrome Beta");
    125    profilePathSegments = ["Google", "Chrome Beta", "User Data", "Default"];
    126  } else {
    127    throw new Error("Not implemented");
    128  }
    129 
    130  let target = rootDir.clone();
    131  let defaultFolderPath = PathUtils.join(target.path, ...profilePathSegments);
    132  let webDataPath = PathUtils.join(defaultFolderPath, "Web Data");
    133  let localStatePath = defaultFolderPath.replace("Default", "");
    134 
    135  await IOUtils.makeDirectory(defaultFolderPath, {
    136    createAncestor: true,
    137    ignoreExisting: true,
    138  });
    139 
    140  // Copy Web Data database into Default profile
    141  const sourcePathWebData = do_get_file(
    142    "AppData/Local/Google/Chrome/User Data/Default/Web Data"
    143  ).path;
    144  await IOUtils.copy(sourcePathWebData, webDataPath);
    145 
    146  const sourcePathLocalState = do_get_file(
    147    "AppData/Local/Google/Chrome/User Data/Local State"
    148  ).path;
    149  await IOUtils.copy(sourcePathLocalState, localStatePath);
    150 
    151  let dbConn = await Sqlite.openConnection({ path: webDataPath });
    152 
    153  for (let card of PAYMENT_METHODS) {
    154    let encryptedCardNumber = await loginCrypto.encryptData(card.card_number);
    155    let cardNumberEncryptedValue = new Uint8Array(
    156      loginCrypto.stringToArray(encryptedCardNumber)
    157    );
    158 
    159    let cardCopy = structuredClone(card);
    160 
    161    cardCopy.card_number_encrypted = cardNumberEncryptedValue;
    162    delete cardCopy.card_number;
    163 
    164    await dbConn.execute(
    165      `INSERT INTO credit_cards
    166                           (name_on_card, card_number_encrypted, expiration_month, expiration_year)
    167                           VALUES (:name_on_card, :card_number_encrypted, :expiration_month, :expiration_year)
    168                          `,
    169      cardCopy
    170    );
    171  }
    172 
    173  await dbConn.close();
    174 
    175  // We no longer support importing payment methods from Chrome on Windows,
    176  // but we can still do it for other Chrome-based browsers like Chrome Beta.
    177  let migratorKey = AppConstants.platform == "win" ? "chrome-beta" : "chrome";
    178  let migrator = await MigrationUtils.getMigrator(migratorKey);
    179 
    180  if (AppConstants.platform == "macosx") {
    181    Object.assign(migrator, {
    182      _keychainServiceName: mockMacOSKeychain.serviceName,
    183      _keychainAccountName: mockMacOSKeychain.accountName,
    184      _keychainMockPassphrase: mockMacOSKeychain.passphrase,
    185    });
    186  }
    187  Assert.ok(
    188    await migrator.isSourceAvailable(),
    189    "Sanity check the source exists"
    190  );
    191 
    192  Services.prefs.setBoolPref(
    193    "browser.migrate.chrome.payment_methods.enabled",
    194    false
    195  );
    196  Assert.ok(
    197    !(
    198      (await migrator.getMigrateData(PROFILE)) &
    199      MigrationUtils.resourceTypes.PAYMENT_METHODS
    200    ),
    201    "Should be able to disable migrating payment methods"
    202  );
    203  // Clear the cached resources now so that a re-check for payment methods
    204  // will look again.
    205  delete migrator._resourcesByProfile[PROFILE.id];
    206 
    207  Services.prefs.setBoolPref(
    208    "browser.migrate.chrome.payment_methods.enabled",
    209    true
    210  );
    211 
    212  Assert.ok(
    213    (await migrator.getMigrateData(PROFILE)) &
    214      MigrationUtils.resourceTypes.PAYMENT_METHODS,
    215    "Should be able to enable migrating payment methods"
    216  );
    217 
    218  let { formAutofillStorage } = ChromeUtils.importESModule(
    219    "resource://autofill/FormAutofillStorage.sys.mjs"
    220  );
    221  await formAutofillStorage.initialize();
    222 
    223  await promiseMigration(
    224    migrator,
    225    MigrationUtils.resourceTypes.PAYMENT_METHODS,
    226    PROFILE
    227  );
    228 
    229  let cards = await formAutofillStorage.creditCards.getAll();
    230 
    231  Assert.equal(
    232    cards.length,
    233    PAYMENT_METHODS.length,
    234    "Check there are still the same number of credit cards after re-importing the data"
    235  );
    236  Assert.equal(
    237    cards.length,
    238    MigrationUtils._importQuantities.cards,
    239    "Check telemetry matches the actual import."
    240  );
    241 
    242  for (let i = 0; i < PAYMENT_METHODS.length; i++) {
    243    checkCardsAreEqual(cards[i], PAYMENT_METHODS[i], i + 1);
    244  }
    245 });