--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -9,16 +9,17 @@
* fields, using UTF-8 encoding. With indentation and computed fields applied,
* the schema would look like this:
*
* {
* version: 1,
* addresses: [
* {
* guid, // 12 characters
+ * version, // schema version in integer
*
* // address fields
* given-name,
* additional-name,
* family-name,
* organization, // Company
* street-address, // (Multiline)
* address-level2, // City/Town
@@ -40,16 +41,17 @@
* timeLastUsed, // in ms
* timeLastModified, // in ms
* timesUsed
* }
* ],
* creditCards: [
* {
* guid, // 12 characters
+ * version, // schema version in integer
*
* // credit card fields
* cc-name,
* cc-number-encrypted,
* cc-number-masked, // e.g. ************1234
* cc-exp-month,
* cc-exp-year, // 2-digit year will be converted to 4 digits
* // upon saving
@@ -90,17 +92,19 @@ XPCOMUtils.defineLazyModuleGetter(this,
"resource://formautofill/FormAutofillNameUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
-const SCHEMA_VERSION = 1;
+const STORAGE_SCHEMA_VERSION = 1;
+const ADDRESS_SCHEMA_VERSION = 1;
+const CREDIT_CARD_SCHEMA_VERSION = 1;
const VALID_PROFILE_FIELDS = [
"given-name",
"additional-name",
"family-name",
"organization",
"street-address",
"address-level2",
@@ -116,16 +120,17 @@ const VALID_CREDIT_CARD_FIELDS = [
"cc-number-encrypted",
"cc-number-masked",
"cc-exp-month",
"cc-exp-year",
];
const INTERNAL_FIELDS = [
"guid",
+ "version",
"timeCreated",
"timeLastUsed",
"timeLastModified",
"timesUsed",
];
/**
* Class that manipulates records in a specified collection.
@@ -139,34 +144,37 @@ class AutofillRecords {
* Creates an AutofillRecords.
*
* @param {JSONFile} store
* An instance of JSONFile.
* @param {string} collectionName
* A key of "store.data".
* @param {Array.<string>} validFields
* A list containing non-metadata field names.
+ * @param {number} schemaVersion
+ * The schema version for the new record.
*/
- constructor(store, collectionName, validFields) {
+ constructor(store, collectionName, validFields, schemaVersion) {
FormAutofillUtils.defineLazyLogGetter(this, "AutofillRecords:" + collectionName);
this.VALID_FIELDS = validFields;
this._store = store;
this._collectionName = collectionName;
+ this._schemaVersion = schemaVersion;
}
/**
* Gets the schema version number.
*
* @returns {number}
* The current schema version number.
*/
get version() {
- return SCHEMA_VERSION;
+ return this._schemaVersion;
}
/**
* Adds a new record.
*
* @param {Object} record
* The new record for saving.
*/
@@ -177,16 +185,17 @@ class AutofillRecords {
this._normalizeRecord(recordToSave);
let guid;
while (!guid || this._findByGUID(guid)) {
guid = gUUIDGenerator.generateUUID().toString()
.replace(/[{}-]/g, "").substring(0, 12);
}
recordToSave.guid = guid;
+ recordToSave.version = this.version;
// Metadata
let now = Date.now();
recordToSave.timeCreated = now;
recordToSave.timeLastModified = now;
recordToSave.timeLastUsed = 0;
recordToSave.timesUsed = 0;
@@ -366,17 +375,17 @@ class AutofillRecords {
_recordReadProcessor(record, config) {}
// An interface to be inherited.
_recordWriteProcessor(record) {}
}
class Addresses extends AutofillRecords {
constructor(store) {
- super(store, "addresses", VALID_PROFILE_FIELDS);
+ super(store, "addresses", VALID_PROFILE_FIELDS, ADDRESS_SCHEMA_VERSION);
}
_recordReadProcessor(profile, {noComputedFields} = {}) {
if (noComputedFields) {
return;
}
// Compute name
@@ -441,17 +450,17 @@ class Addresses extends AutofillRecords
profile["street-address"] = addressLines.join("\n");
}
}
}
}
class CreditCards extends AutofillRecords {
constructor(store) {
- super(store, "creditCards", VALID_CREDIT_CARD_FIELDS);
+ super(store, "creditCards", VALID_CREDIT_CARD_FIELDS, CREDIT_CARD_SCHEMA_VERSION);
}
_recordReadProcessor(creditCard, {noComputedFields} = {}) {
if (noComputedFields) {
return;
}
// Compute split names
@@ -533,16 +542,20 @@ class CreditCards extends AutofillRecord
function ProfileStorage(path) {
this._path = path;
this._initializePromise = null;
this.INTERNAL_FIELDS = INTERNAL_FIELDS;
}
ProfileStorage.prototype = {
+ get version() {
+ return STORAGE_SCHEMA_VERSION;
+ },
+
get addresses() {
if (!this._addresses) {
this._store.ensureDataReady();
this._addresses = new Addresses(this._store);
}
return this._addresses;
},
@@ -568,17 +581,17 @@ ProfileStorage.prototype = {
dataPostProcessor: this._dataPostProcessor.bind(this),
});
this._initializePromise = this._store.load();
}
return this._initializePromise;
},
_dataPostProcessor(data) {
- data.version = SCHEMA_VERSION;
+ data.version = this.version;
if (!data.addresses) {
data.addresses = [];
}
if (!data.creditCards) {
data.creditCards = [];
}
return data;
},
--- a/browser/extensions/formautofill/test/unit/test_addressRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_addressRecords.js
@@ -171,16 +171,17 @@ add_task(async function test_add() {
let addresses = profileStorage.addresses.getAll();
do_check_eq(addresses.length, 2);
do_check_record_matches(addresses[0], TEST_ADDRESS_1);
do_check_record_matches(addresses[1], TEST_ADDRESS_2);
do_check_neq(addresses[0].guid, undefined);
+ do_check_eq(addresses[0].version, 1);
do_check_neq(addresses[0].timeCreated, undefined);
do_check_eq(addresses[0].timeLastModified, addresses[0].timeCreated);
do_check_eq(addresses[0].timeLastUsed, 0);
do_check_eq(addresses[0].timesUsed, 0);
Assert.throws(() => profileStorage.addresses.add(TEST_ADDRESS_WITH_INVALID_FIELD),
/"invalidField" is not a valid field\./);
});
--- a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
@@ -183,16 +183,17 @@ add_task(async function test_add() {
let creditCards = profileStorage.creditCards.getAll();
do_check_eq(creditCards.length, 2);
do_check_credit_card_matches(creditCards[0], TEST_CREDIT_CARD_1);
do_check_credit_card_matches(creditCards[1], TEST_CREDIT_CARD_2);
do_check_neq(creditCards[0].guid, undefined);
+ do_check_eq(creditCards[0].version, 1);
do_check_neq(creditCards[0].timeCreated, undefined);
do_check_eq(creditCards[0].timeLastModified, creditCards[0].timeCreated);
do_check_eq(creditCards[0].timeLastUsed, 0);
do_check_eq(creditCards[0].timesUsed, 0);
Assert.throws(() => profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_FIELD),
/"invalidField" is not a valid field\./);
});