Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
/* global structuredClone */
const PROFILE = {
id: "Default",
name: "Default",
};
const PAYMENT_METHODS = [
{
name_on_card: "Name Name",
card_number: "4532962432748929", // Visa
expiration_month: 3,
expiration_year: 2027,
},
{
name_on_card: "Name Name Name",
card_number: "5359908373796416", // Mastercard
expiration_month: 5,
expiration_year: 2028,
},
{
name_on_card: "Name",
card_number: "346624461807588", // AMEX
expiration_month: 4,
expiration_year: 2026,
},
];
let OSKeyStoreTestUtils;
add_setup(async function os_key_store_setup() {
({ OSKeyStoreTestUtils } = ChromeUtils.importESModule(
));
OSKeyStoreTestUtils.setup();
registerCleanupFunction(async function cleanup() {
await OSKeyStoreTestUtils.cleanup();
});
});
let rootDir = do_get_file("chromefiles/", true);
function checkCardsAreEqual(importedCard, testCard, id) {
const CC_NUMBER_RE = /^(\*+)(.{4})$/;
Assert.equal(
importedCard["cc-name"],
testCard.name_on_card,
"The two logins ID " + id + " have the same name on card"
);
let matches = CC_NUMBER_RE.exec(importedCard["cc-number"]);
Assert.notEqual(matches, null);
Assert.equal(importedCard["cc-number"].length, testCard.card_number.length);
Assert.equal(testCard.card_number.endsWith(matches[2]), true);
Assert.notEqual(importedCard["cc-number-encrypted"], "");
Assert.equal(
importedCard["cc-exp-month"],
testCard.expiration_month,
"The two logins ID " + id + " have the same expiration month"
);
Assert.equal(
importedCard["cc-exp-year"],
testCard.expiration_year,
"The two logins ID " + id + " have the same expiration year"
);
}
add_task(async function setup_fakePaths() {
let pathId;
if (AppConstants.platform == "macosx") {
pathId = "ULibDir";
} else if (AppConstants.platform == "win") {
pathId = "LocalAppData";
} else {
pathId = "Home";
}
registerFakePath(pathId, rootDir);
});
add_task(async function test_credit_cards() {
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
todo_check_true(
OSKeyStoreTestUtils.canTestOSKeyStoreLogin(),
"Cannot test OS key store login on official builds."
);
return;
}
let loginCrypto;
let profilePathSegments;
let mockMacOSKeychain = {
passphrase: "bW96aWxsYWZpcmVmb3g=",
serviceName: "TESTING Chrome Safe Storage",
accountName: "TESTING Chrome",
};
if (AppConstants.platform == "macosx") {
let { ChromeMacOSLoginCrypto } = ChromeUtils.importESModule(
"resource:///modules/ChromeMacOSLoginCrypto.sys.mjs"
);
loginCrypto = new ChromeMacOSLoginCrypto(
mockMacOSKeychain.serviceName,
mockMacOSKeychain.accountName,
mockMacOSKeychain.passphrase
);
profilePathSegments = [
"Application Support",
"Google",
"Chrome",
"Default",
];
} else if (AppConstants.platform == "win") {
let { ChromeWindowsLoginCrypto } = ChromeUtils.importESModule(
"resource:///modules/ChromeWindowsLoginCrypto.sys.mjs"
);
loginCrypto = new ChromeWindowsLoginCrypto("Chrome");
profilePathSegments = ["Google", "Chrome", "User Data", "Default"];
} else {
throw new Error("Not implemented");
}
let target = rootDir.clone();
let defaultFolderPath = PathUtils.join(target.path, ...profilePathSegments);
let webDataPath = PathUtils.join(defaultFolderPath, "Web Data");
let localStatePath = defaultFolderPath.replace("Default", "");
await IOUtils.makeDirectory(defaultFolderPath, {
createAncestor: true,
ignoreExisting: true,
});
// Copy Web Data database into Default profile
const sourcePathWebData = do_get_file(
"AppData/Local/Google/Chrome/User Data/Default/Web Data"
).path;
await IOUtils.copy(sourcePathWebData, webDataPath);
const sourcePathLocalState = do_get_file(
"AppData/Local/Google/Chrome/User Data/Local State"
).path;
await IOUtils.copy(sourcePathLocalState, localStatePath);
let dbConn = await Sqlite.openConnection({ path: webDataPath });
for (let card of PAYMENT_METHODS) {
let encryptedCardNumber = await loginCrypto.encryptData(card.card_number);
let cardNumberEncryptedValue = new Uint8Array(
loginCrypto.stringToArray(encryptedCardNumber)
);
let cardCopy = structuredClone(card);
cardCopy.card_number_encrypted = cardNumberEncryptedValue;
delete cardCopy.card_number;
await dbConn.execute(
`INSERT INTO credit_cards
(name_on_card, card_number_encrypted, expiration_month, expiration_year)
VALUES (:name_on_card, :card_number_encrypted, :expiration_month, :expiration_year)
`,
cardCopy
);
}
await dbConn.close();
let migrator = await MigrationUtils.getMigrator("chrome");
if (AppConstants.platform == "macosx") {
Object.assign(migrator, {
_keychainServiceName: mockMacOSKeychain.serviceName,
_keychainAccountName: mockMacOSKeychain.accountName,
_keychainMockPassphrase: mockMacOSKeychain.passphrase,
});
}
Assert.ok(
await migrator.isSourceAvailable(),
"Sanity check the source exists"
);
Services.prefs.setBoolPref(
"browser.migrate.chrome.payment_methods.enabled",
false
);
Assert.ok(
!(
(await migrator.getMigrateData(PROFILE)) &
MigrationUtils.resourceTypes.PAYMENT_METHODS
),
"Should be able to disable migrating payment methods"
);
// Clear the cached resources now so that a re-check for payment methods
// will look again.
delete migrator._resourcesByProfile[PROFILE.id];
Services.prefs.setBoolPref(
"browser.migrate.chrome.payment_methods.enabled",
true
);
Assert.ok(
(await migrator.getMigrateData(PROFILE)) &
MigrationUtils.resourceTypes.PAYMENT_METHODS,
"Should be able to enable migrating payment methods"
);
let { formAutofillStorage } = ChromeUtils.importESModule(
"resource://autofill/FormAutofillStorage.sys.mjs"
);
await formAutofillStorage.initialize();
await promiseMigration(
migrator,
MigrationUtils.resourceTypes.PAYMENT_METHODS,
PROFILE
);
let cards = await formAutofillStorage.creditCards.getAll();
Assert.equal(
cards.length,
PAYMENT_METHODS.length,
"Check there are still the same number of credit cards after re-importing the data"
);
Assert.equal(
cards.length,
MigrationUtils._importQuantities.cards,
"Check telemetry matches the actual import."
);
for (let i = 0; i < PAYMENT_METHODS.length; i++) {
checkCardsAreEqual(cards[i], PAYMENT_METHODS[i], i + 1);
}
});