зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1812235 - Rollback credit card record version from 4 to 3 r=markh,sgalich
Mobile clients reject syncing when credit card record version is not 3, so this patch reverts the credit card record version back to 3 (with `cc-type` field). The auto-detect network type behavior implemented in bug 1667257 still applies. The changes made in this commit are: 1. Save the cc-type to storage to comply with the expectation of mobile clients. (This is the behavior for v3 credit record) 2. When a v4 record is found, rollback to v3 and make sure `_sync.changeCounter` is set so we upload the downgraded record to the sync server Differential Revision: https://phabricator.services.mozilla.com/D167814
This commit is contained in:
Родитель
2e5eede2fe
Коммит
eb1ab82505
|
@ -322,3 +322,53 @@ add_task(async function test_migrateEncryptedCreditCardNumber() {
|
||||||
Assert.ok(v1record.deleted);
|
Assert.ok(v1record.deleted);
|
||||||
Assert.ok(v2record.deleted);
|
Assert.ok(v2record.deleted);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(async function test_migrateDeprecatedCreditCardV4() {
|
||||||
|
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||||
|
|
||||||
|
let profileStorage = new FormAutofillStorage(path);
|
||||||
|
await profileStorage.initialize();
|
||||||
|
|
||||||
|
let records = [
|
||||||
|
{
|
||||||
|
guid: "test-guid1",
|
||||||
|
version: CREDIT_CARD_SCHEMA_VERSION,
|
||||||
|
"cc-name": "Alice",
|
||||||
|
_sync: {
|
||||||
|
changeCounter: 0,
|
||||||
|
lastSyncedFields: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
guid: "test-guid2",
|
||||||
|
version: 4,
|
||||||
|
"cc-name": "Timothy",
|
||||||
|
_sync: {
|
||||||
|
changeCounter: 0,
|
||||||
|
lastSyncedFields: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
guid: "test-guid3",
|
||||||
|
version: 4,
|
||||||
|
"cc-name": "Bob",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
profileStorage._store.data.creditCards = records;
|
||||||
|
for (let idx = 0; idx < records.length; idx++) {
|
||||||
|
await profileStorage.creditCards._migrateRecord(records[idx], idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
profileStorage.creditCards.pullSyncChanges();
|
||||||
|
|
||||||
|
// Record that has already synced before, do not sync again
|
||||||
|
equal(getSyncChangeCounter(profileStorage.creditCards, records[0].guid), 0);
|
||||||
|
|
||||||
|
// alaways force sync v4 record
|
||||||
|
equal(records[1].version, CREDIT_CARD_SCHEMA_VERSION);
|
||||||
|
equal(getSyncChangeCounter(profileStorage.creditCards, records[1].guid), 1);
|
||||||
|
|
||||||
|
equal(records[2].version, CREDIT_CARD_SCHEMA_VERSION);
|
||||||
|
equal(getSyncChangeCounter(profileStorage.creditCards, records[2].guid), 1);
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
/**
|
||||||
|
* Tests sync functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* import-globals-from ../../../../../services/sync/tests/unit/head_appinfo.js */
|
||||||
|
/* import-globals-from ../../../../../services/common/tests/unit/head_helpers.js */
|
||||||
|
/* import-globals-from ../../../../../services/sync/tests/unit/head_helpers.js */
|
||||||
|
/* import-globals-from ../../../../../services/sync/tests/unit/head_http_server.js */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Service } = ChromeUtils.import("resource://services-sync/service.js");
|
||||||
|
|
||||||
|
const { CreditCardsEngine } = ChromeUtils.import(
|
||||||
|
"resource://autofill/FormAutofillSync.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.setCharPref("extensions.formautofill.loglevel", "Trace");
|
||||||
|
initTestLogging("Trace");
|
||||||
|
|
||||||
|
const TEST_STORE_FILE_NAME = "test-profile.json";
|
||||||
|
|
||||||
|
const TEST_CREDIT_CARD_1 = {
|
||||||
|
guid: "86d961c7717a",
|
||||||
|
"cc-name": "John Doe",
|
||||||
|
"cc-number": "4111111111111111",
|
||||||
|
"cc-exp-month": 4,
|
||||||
|
"cc-exp-year": new Date().getFullYear(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEST_CREDIT_CARD_2 = {
|
||||||
|
guid: "cf57a7ac3539",
|
||||||
|
"cc-name": "Timothy Berners-Lee",
|
||||||
|
"cc-number": "4929001587121045",
|
||||||
|
"cc-exp-month": 12,
|
||||||
|
"cc-exp-year": new Date().getFullYear() + 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
function expectProfiles(profiles, expected) {
|
||||||
|
expected.sort((a, b) => a.guid.localeCompare(b.guid));
|
||||||
|
profiles.sort((a, b) => a.guid.localeCompare(b.guid));
|
||||||
|
try {
|
||||||
|
deepEqual(
|
||||||
|
profiles.map(p => p.guid),
|
||||||
|
expected.map(p => p.guid)
|
||||||
|
);
|
||||||
|
for (let i = 0; i < expected.length; i++) {
|
||||||
|
let thisExpected = expected[i];
|
||||||
|
let thisGot = profiles[i];
|
||||||
|
// always check "deleted".
|
||||||
|
equal(thisExpected.deleted, thisGot.deleted);
|
||||||
|
ok(objectMatches(thisGot, thisExpected));
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
info("Comparing expected profiles:");
|
||||||
|
info(JSON.stringify(expected, undefined, 2));
|
||||||
|
info("against actual profiles:");
|
||||||
|
info(JSON.stringify(profiles, undefined, 2));
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function expectServerProfiles(collection, expected) {
|
||||||
|
const profiles = collection
|
||||||
|
.payloads()
|
||||||
|
.map(payload => Object.assign({ guid: payload.id }, payload.entry));
|
||||||
|
expectProfiles(profiles, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function expectLocalProfiles(profileStorage, expected) {
|
||||||
|
const profiles = await profileStorage.creditCards.getAll({
|
||||||
|
rawData: true,
|
||||||
|
includeDeleted: true,
|
||||||
|
});
|
||||||
|
expectProfiles(profiles, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setup() {
|
||||||
|
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||||
|
// should always start with no profiles.
|
||||||
|
Assert.equal(
|
||||||
|
(await profileStorage.creditCards.getAll({ includeDeleted: true })).length,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.setCharPref(
|
||||||
|
"services.sync.log.logger.engine.CreditCards",
|
||||||
|
"Trace"
|
||||||
|
);
|
||||||
|
let engine = new CreditCardsEngine(Service);
|
||||||
|
await engine.initialize();
|
||||||
|
// Avoid accidental automatic sync due to our own changes
|
||||||
|
Service.scheduler.syncThreshold = 10000000;
|
||||||
|
let syncID = await engine.resetLocalSyncID();
|
||||||
|
let server = serverForUsers(
|
||||||
|
{ foo: "password" },
|
||||||
|
{
|
||||||
|
meta: {
|
||||||
|
global: {
|
||||||
|
engines: { creditcards: { version: engine.version, syncID } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
creditcards: {},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Service.engineManager._engines.creditcards = engine;
|
||||||
|
engine.enabled = true;
|
||||||
|
engine._store._storage = profileStorage.creditCards;
|
||||||
|
|
||||||
|
generateNewKeys(Service.collectionKeys);
|
||||||
|
|
||||||
|
await SyncTestingInfrastructure(server);
|
||||||
|
|
||||||
|
let collection = server.user("foo").collection("creditcards");
|
||||||
|
|
||||||
|
return { profileStorage, server, collection, engine };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cleanup(server) {
|
||||||
|
let promiseStartOver = promiseOneObserver("weave:service:start-over:finish");
|
||||||
|
await Service.startOver();
|
||||||
|
await promiseStartOver;
|
||||||
|
await promiseStopServer(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTestRecords(profileStorage, version) {
|
||||||
|
return [
|
||||||
|
Object.assign({ version }, TEST_CREDIT_CARD_1),
|
||||||
|
Object.assign({ version }, TEST_CREDIT_CARD_2),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupServerRecords(server, records) {
|
||||||
|
for (const record of records) {
|
||||||
|
server.insertWBO(
|
||||||
|
"foo",
|
||||||
|
"creditcards",
|
||||||
|
new ServerWBO(
|
||||||
|
record.guid,
|
||||||
|
encryptPayload({
|
||||||
|
id: record.guid,
|
||||||
|
entry: Object.assign({}, record),
|
||||||
|
}),
|
||||||
|
Date.now() / 1000
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We want to setup old records and run init() to migrate records.
|
||||||
|
* However, We don't have an easy way to setup an older version record with
|
||||||
|
* init() function now.
|
||||||
|
* So as a workaround, we simulate the behavior by directly setting data and then
|
||||||
|
* run migration.
|
||||||
|
*/
|
||||||
|
async function setupLocalProfilesAndRunMigration(profileStorage, records) {
|
||||||
|
for (const record of records) {
|
||||||
|
profileStorage._store.data.creditCards.push(Object.assign({}, record));
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
profileStorage.creditCards._data.map(async (record, index) =>
|
||||||
|
profileStorage.creditCards._migrateRecord(record, index)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// local v3, server v4
|
||||||
|
add_task(async function test_local_v3_server_v4() {
|
||||||
|
let { collection, profileStorage, server, engine } = await setup();
|
||||||
|
|
||||||
|
const V3_RECORDS = getTestRecords(profileStorage, 3);
|
||||||
|
const V4_RECORDS = getTestRecords(profileStorage, 4);
|
||||||
|
|
||||||
|
await setupLocalProfilesAndRunMigration(profileStorage, V3_RECORDS);
|
||||||
|
setupServerRecords(server, V4_RECORDS);
|
||||||
|
|
||||||
|
await engine.setLastSync(0);
|
||||||
|
await engine.sync();
|
||||||
|
|
||||||
|
await expectServerProfiles(collection, V3_RECORDS);
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await cleanup(server);
|
||||||
|
});
|
||||||
|
|
||||||
|
// local v4, server empty
|
||||||
|
add_task(async function test_local_v4_server_empty() {
|
||||||
|
let { collection, profileStorage, server, engine } = await setup();
|
||||||
|
const V3_RECORDS = getTestRecords(profileStorage, 3);
|
||||||
|
const V4_RECORDS = getTestRecords(profileStorage, 4);
|
||||||
|
|
||||||
|
await setupLocalProfilesAndRunMigration(profileStorage, V4_RECORDS);
|
||||||
|
|
||||||
|
await engine.setLastSync(0);
|
||||||
|
await engine.sync();
|
||||||
|
|
||||||
|
await expectServerProfiles(collection, V3_RECORDS);
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await cleanup(server);
|
||||||
|
});
|
||||||
|
|
||||||
|
// local v4, server v3
|
||||||
|
add_task(async function test_local_v4_server_v3() {
|
||||||
|
let { collection, profileStorage, server, engine } = await setup();
|
||||||
|
const V3_RECORDS = getTestRecords(profileStorage, 3);
|
||||||
|
const V4_RECORDS = getTestRecords(profileStorage, 4);
|
||||||
|
|
||||||
|
await setupLocalProfilesAndRunMigration(profileStorage, V4_RECORDS);
|
||||||
|
setupServerRecords(server, V3_RECORDS);
|
||||||
|
|
||||||
|
// local should be v3 before syncing.
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await engine.setLastSync(0);
|
||||||
|
await engine.sync();
|
||||||
|
|
||||||
|
await expectServerProfiles(collection, V3_RECORDS);
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await cleanup(server);
|
||||||
|
});
|
||||||
|
|
||||||
|
// local v4, server v4
|
||||||
|
add_task(async function test_local_v4_server_v4() {
|
||||||
|
let { collection, profileStorage, server, engine } = await setup();
|
||||||
|
const V3_RECORDS = getTestRecords(profileStorage, 3);
|
||||||
|
const V4_RECORDS = getTestRecords(profileStorage, 4);
|
||||||
|
|
||||||
|
await setupLocalProfilesAndRunMigration(profileStorage, V4_RECORDS);
|
||||||
|
setupServerRecords(server, V4_RECORDS);
|
||||||
|
|
||||||
|
// local should be v3 before syncing and then we ignore
|
||||||
|
// incoming v4 from server
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await engine.setLastSync(0);
|
||||||
|
await engine.sync();
|
||||||
|
|
||||||
|
await expectServerProfiles(collection, V3_RECORDS);
|
||||||
|
await expectLocalProfiles(profileStorage, V3_RECORDS);
|
||||||
|
|
||||||
|
await cleanup(server);
|
||||||
|
});
|
|
@ -69,3 +69,8 @@ skip-if =
|
||||||
[test_sync.js]
|
[test_sync.js]
|
||||||
head = head.js ../../../../../services/sync/tests/unit/head_appinfo.js ../../../../../services/common/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_http_server.js
|
head = head.js ../../../../../services/sync/tests/unit/head_appinfo.js ../../../../../services/common/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_http_server.js
|
||||||
skip-if = tsan # Times out, bug 1612707
|
skip-if = tsan # Times out, bug 1612707
|
||||||
|
[test_sync_deprecate_credit_card_v4.js]
|
||||||
|
head = head.js ../../../../../services/sync/tests/unit/head_appinfo.js ../../../../../services/common/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_helpers.js ../../../../../services/sync/tests/unit/head_http_server.js
|
||||||
|
skip-if =
|
||||||
|
tsan # Times out, bug 1612707
|
||||||
|
apple_silicon # bug 1729554
|
||||||
|
|
|
@ -67,10 +67,10 @@
|
||||||
* cc-exp-month,
|
* cc-exp-month,
|
||||||
* cc-exp-year, // 2-digit year will be converted to 4 digits
|
* cc-exp-year, // 2-digit year will be converted to 4 digits
|
||||||
* // upon saving
|
* // upon saving
|
||||||
|
* cc-type, // Optional card network id (instrument type)
|
||||||
*
|
*
|
||||||
* // computed fields (These fields are computed based on the above fields
|
* // computed fields (These fields are computed based on the above fields
|
||||||
* // and are not allowed to be modified directly.)
|
* // and are not allowed to be modified directly.)
|
||||||
* cc-type, // Optional card network id (instrument type)
|
|
||||||
* cc-given-name,
|
* cc-given-name,
|
||||||
* cc-additional-name,
|
* cc-additional-name,
|
||||||
* cc-family-name,
|
* cc-family-name,
|
||||||
|
@ -160,12 +160,20 @@ const CryptoHash = Components.Constructor(
|
||||||
);
|
);
|
||||||
|
|
||||||
const STORAGE_SCHEMA_VERSION = 1;
|
const STORAGE_SCHEMA_VERSION = 1;
|
||||||
|
|
||||||
|
// NOTE: It's likely this number can never change.
|
||||||
|
// Please talk to the sync team before changing this!
|
||||||
|
// (And if it did ever change, it must never be "4" due to the reconcile hacks
|
||||||
|
// below which repairs credit-cards with version=4)
|
||||||
const ADDRESS_SCHEMA_VERSION = 1;
|
const ADDRESS_SCHEMA_VERSION = 1;
|
||||||
|
|
||||||
// Version 2: Bug 1486954 - Encrypt `cc-number`
|
// Version 2: Bug 1486954 - Encrypt `cc-number`
|
||||||
// Version 3: Bug 1639795 - Update keystore name
|
// Version 3: Bug 1639795 - Update keystore name
|
||||||
// Version 4: Bug 1667257 - Do not store `cc-type` field
|
// Version 4: (deprecated!!! See Bug 1812235): Bug 1667257 - Do not store `cc-type` field
|
||||||
const CREDIT_CARD_SCHEMA_VERSION = 4;
|
// Next version should be 5
|
||||||
|
// NOTE: It's likely this number can never change.
|
||||||
|
// Please talk to the sync team before changing this!
|
||||||
|
const CREDIT_CARD_SCHEMA_VERSION = 3;
|
||||||
|
|
||||||
const VALID_ADDRESS_FIELDS = [
|
const VALID_ADDRESS_FIELDS = [
|
||||||
"given-name",
|
"given-name",
|
||||||
|
@ -208,10 +216,10 @@ const VALID_CREDIT_CARD_FIELDS = [
|
||||||
"cc-number",
|
"cc-number",
|
||||||
"cc-exp-month",
|
"cc-exp-month",
|
||||||
"cc-exp-year",
|
"cc-exp-year",
|
||||||
|
"cc-type",
|
||||||
];
|
];
|
||||||
|
|
||||||
const VALID_CREDIT_CARD_COMPUTED_FIELDS = [
|
const VALID_CREDIT_CARD_COMPUTED_FIELDS = [
|
||||||
"cc-type",
|
|
||||||
"cc-given-name",
|
"cc-given-name",
|
||||||
"cc-additional-name",
|
"cc-additional-name",
|
||||||
"cc-family-name",
|
"cc-family-name",
|
||||||
|
@ -971,6 +979,30 @@ class AutofillRecords {
|
||||||
|
|
||||||
let forkedGUID = null;
|
let forkedGUID = null;
|
||||||
|
|
||||||
|
// NOTE: This implies a credit-card - so it's critical ADDRESS_SCHEMA_VERSION
|
||||||
|
// never equals 4 while this code exists!
|
||||||
|
let requiresForceUpdate =
|
||||||
|
localRecord.version != remoteRecord.version && remoteRecord.version == 4;
|
||||||
|
|
||||||
|
if (requiresForceUpdate) {
|
||||||
|
// Another desktop device that is still using version=4 has created or
|
||||||
|
// modified a remote record. Here we downgrade it to version=3 so we can
|
||||||
|
// treat it normally, then cause it to be re-uploaded so other desktop
|
||||||
|
// or mobile devices can still see it.
|
||||||
|
// That device still using version=4 *will* again see it, and again
|
||||||
|
// upgrade it, but thankfully that 3->4 migration doesn't force a reupload
|
||||||
|
// of all records, or we'd be going back and forward on every sync.
|
||||||
|
// Once that version=4 device gets updated to roll back to version=3, it
|
||||||
|
// will then yet again re-upload it, this time with version=3, but the
|
||||||
|
// content will be the same here, so everything should work out in the end.
|
||||||
|
//
|
||||||
|
// If we just ignored this incoming record, it would remain on the server
|
||||||
|
// with version=4. If the device that wrote that went away (ie, never
|
||||||
|
// synced again) nothing would ever repair it back to 3, which would
|
||||||
|
// be bad because mobile would remain broken until the user edited the
|
||||||
|
// card somewhere.
|
||||||
|
remoteRecord = await this._computeMigratedRecord(remoteRecord);
|
||||||
|
}
|
||||||
if (sync.changeCounter === 0) {
|
if (sync.changeCounter === 0) {
|
||||||
// Local not modified. Replace local with remote.
|
// Local not modified. Replace local with remote.
|
||||||
await this._replaceRecordAt(localIndex, remoteRecord, {
|
await this._replaceRecordAt(localIndex, remoteRecord, {
|
||||||
|
@ -1003,6 +1035,18 @@ class AutofillRecords {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requiresForceUpdate) {
|
||||||
|
// The incoming record was version=4 and we want to re-upload it as version=3.
|
||||||
|
// We need to reach directly into self._data[] so we can poke at the
|
||||||
|
// sync metadata directly.
|
||||||
|
let indexToUpdate = this._findIndexByGUID(remoteRecord.guid);
|
||||||
|
let toUpdate = this._data[indexToUpdate];
|
||||||
|
this._getSyncMetaData(toUpdate, true).changeCounter += 1;
|
||||||
|
this.log.info(
|
||||||
|
`Flagging record ${toUpdate.guid} for re-upload after record version downgrade`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this._store.saveSoon();
|
this._store.saveSoon();
|
||||||
Services.obs.notifyObservers(
|
Services.obs.notifyObservers(
|
||||||
{
|
{
|
||||||
|
@ -1314,7 +1358,7 @@ class AutofillRecords {
|
||||||
record.version = 0;
|
record.version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record.version < this.version) {
|
if (this._isMigrationNeeded(record.version)) {
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
|
|
||||||
record = await this._computeMigratedRecord(record);
|
record = await this._computeMigratedRecord(record);
|
||||||
|
@ -1405,6 +1449,10 @@ class AutofillRecords {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isMigrationNeeded(recordVersion) {
|
||||||
|
return recordVersion < this.version;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip the computed fields based on the record version.
|
* Strip the computed fields based on the record version.
|
||||||
*
|
*
|
||||||
|
@ -1759,6 +1807,13 @@ class CreditCardsBase extends AutofillRecords {
|
||||||
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
|
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isMigrationNeeded(recordVersion) {
|
||||||
|
return (
|
||||||
|
// version 4 is deprecated and is rolled back to version 3
|
||||||
|
recordVersion == 4 || recordVersion < this.version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async _computeMigratedRecord(creditCard) {
|
async _computeMigratedRecord(creditCard) {
|
||||||
if (creditCard.version <= 2) {
|
if (creditCard.version <= 2) {
|
||||||
if (creditCard["cc-number-encrypted"]) {
|
if (creditCard["cc-number-encrypted"]) {
|
||||||
|
@ -1789,9 +1844,15 @@ class CreditCardsBase extends AutofillRecords {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creditCard.version <= 3) {
|
// Do not remove the migration code until we're sure no users have version 4
|
||||||
if (creditCard["cc-type"]) {
|
// credit card records (created in Fx110 or Fx111)
|
||||||
delete creditCard["cc-type"];
|
if (creditCard.version == 4) {
|
||||||
|
// Version 4 is deprecated, so downgrade or upgrade to the current version
|
||||||
|
// Since the only change made in version 4 is deleting `cc-type` field, so
|
||||||
|
// nothing else need to be done here expect flagging sync needed
|
||||||
|
let existingSync = this._getSyncMetaData(creditCard);
|
||||||
|
if (existingSync) {
|
||||||
|
existingSync.changeCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1885,7 +1946,11 @@ class CreditCardsBase extends AutofillRecords {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record.version < this.version) {
|
if (record.version == 4) {
|
||||||
|
// Version 4 is deprecated, we need to force downloading it from sync
|
||||||
|
// and let migration do the work to downgrade it back to the current version.
|
||||||
|
return true;
|
||||||
|
} else if (record.version < this.version) {
|
||||||
switch (record.version) {
|
switch (record.version) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче