mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 22:35:43 +00:00
Backed out changeset 56aa054d4cc0 (bug 1399367) for browser/extensions/formautofill/test/unit/test_activeStatus.js failures. CLOSED TREE
This commit is contained in:
parent
6e8f3beb98
commit
0ee540d6b5
@ -63,16 +63,16 @@ class TempCollection {
|
||||
return this._data[guid];
|
||||
}
|
||||
|
||||
async update(guid, record, preserveOldProperties) {
|
||||
update(guid, record, preserveOldProperties) {
|
||||
let recordToSave = Object.assign(preserveOldProperties ? this._data[guid] : {}, record);
|
||||
await this._formAutofillCollection.computeFields(recordToSave);
|
||||
this._formAutofillCollection.computeFields(recordToSave);
|
||||
return (this._data[guid] = recordToSave);
|
||||
}
|
||||
|
||||
async add(record) {
|
||||
add(record) {
|
||||
let guid = "temp-" + Math.abs(Math.random() * 0xffffffff|0);
|
||||
let recordToSave = Object.assign({guid}, record);
|
||||
await this._formAutofillCollection.computeFields(recordToSave);
|
||||
this._formAutofillCollection.computeFields(recordToSave);
|
||||
this._data[guid] = recordToSave;
|
||||
return guid;
|
||||
}
|
||||
@ -95,12 +95,14 @@ var paymentDialogWrapper = {
|
||||
]),
|
||||
|
||||
/**
|
||||
* Note: This method is async because formAutofillStorage plans to become async.
|
||||
*
|
||||
* @param {string} guid
|
||||
* @returns {object} containing only the requested payer values.
|
||||
*/
|
||||
async _convertProfileAddressToPayerData(guid) {
|
||||
let addressData = this.temporaryStore.addresses.get(guid) ||
|
||||
await formAutofillStorage.addresses.get(guid);
|
||||
formAutofillStorage.addresses.get(guid);
|
||||
if (!addressData) {
|
||||
throw new Error(`Payer address not found: ${guid}`);
|
||||
}
|
||||
@ -121,12 +123,14 @@ var paymentDialogWrapper = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Note: This method is async because formAutofillStorage plans to become async.
|
||||
*
|
||||
* @param {string} guid
|
||||
* @returns {nsIPaymentAddress}
|
||||
*/
|
||||
async _convertProfileAddressToPaymentAddress(guid) {
|
||||
let addressData = this.temporaryStore.addresses.get(guid) ||
|
||||
await formAutofillStorage.addresses.get(guid);
|
||||
formAutofillStorage.addresses.get(guid);
|
||||
if (!addressData) {
|
||||
throw new Error(`Shipping address not found: ${guid}`);
|
||||
}
|
||||
@ -154,7 +158,7 @@ var paymentDialogWrapper = {
|
||||
*/
|
||||
async _convertProfileBasicCardToPaymentMethodData(guid, cardSecurityCode) {
|
||||
let cardData = this.temporaryStore.creditCards.get(guid) ||
|
||||
await formAutofillStorage.creditCards.get(guid);
|
||||
formAutofillStorage.creditCards.get(guid);
|
||||
if (!cardData) {
|
||||
throw new Error(`Basic card not found in storage: ${guid}`);
|
||||
}
|
||||
@ -317,17 +321,17 @@ var paymentDialogWrapper = {
|
||||
return component.createInstance(componentInterface);
|
||||
},
|
||||
|
||||
async fetchSavedAddresses() {
|
||||
fetchSavedAddresses() {
|
||||
let savedAddresses = {};
|
||||
for (let address of await formAutofillStorage.addresses.getAll()) {
|
||||
for (let address of formAutofillStorage.addresses.getAll()) {
|
||||
savedAddresses[address.guid] = address;
|
||||
}
|
||||
return savedAddresses;
|
||||
},
|
||||
|
||||
async fetchSavedPaymentCards() {
|
||||
fetchSavedPaymentCards() {
|
||||
let savedBasicCards = {};
|
||||
for (let card of await formAutofillStorage.creditCards.getAll()) {
|
||||
for (let card of formAutofillStorage.creditCards.getAll()) {
|
||||
savedBasicCards[card.guid] = card;
|
||||
// Filter out the encrypted card number since the dialog content is
|
||||
// considered untrusted and runs in a content process.
|
||||
@ -341,13 +345,10 @@ var paymentDialogWrapper = {
|
||||
return savedBasicCards;
|
||||
},
|
||||
|
||||
async onAutofillStorageChange() {
|
||||
let [savedAddresses, savedBasicCards] =
|
||||
await Promise.all([this.fetchSavedAddresses(), this.fetchSavedPaymentCards()]);
|
||||
|
||||
onAutofillStorageChange() {
|
||||
this.sendMessageToContent("updateState", {
|
||||
savedAddresses,
|
||||
savedBasicCards,
|
||||
savedAddresses: this.fetchSavedAddresses(),
|
||||
savedBasicCards: this.fetchSavedPaymentCards(),
|
||||
});
|
||||
},
|
||||
|
||||
@ -445,24 +446,21 @@ var paymentDialogWrapper = {
|
||||
return obj;
|
||||
},
|
||||
|
||||
async initializeFrame() {
|
||||
Services.obs.addObserver(this, "formautofill-storage-changed", true);
|
||||
|
||||
initializeFrame() {
|
||||
let requestSerialized = this._serializeRequest(this.request);
|
||||
let chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(chromeWindow);
|
||||
|
||||
let [savedAddresses, savedBasicCards] =
|
||||
await Promise.all([this.fetchSavedAddresses(), this.fetchSavedPaymentCards()]);
|
||||
|
||||
this.sendMessageToContent("showPaymentRequest", {
|
||||
request: requestSerialized,
|
||||
savedAddresses,
|
||||
savedAddresses: this.fetchSavedAddresses(),
|
||||
tempAddresses: this.temporaryStore.addresses.getAll(),
|
||||
savedBasicCards,
|
||||
savedBasicCards: this.fetchSavedPaymentCards(),
|
||||
tempBasicCards: this.temporaryStore.creditCards.getAll(),
|
||||
isPrivate,
|
||||
});
|
||||
|
||||
Services.obs.addObserver(this, "formautofill-storage-changed", true);
|
||||
},
|
||||
|
||||
debugFrame() {
|
||||
@ -567,6 +565,16 @@ var paymentDialogWrapper = {
|
||||
stateChange: {},
|
||||
};
|
||||
try {
|
||||
if (collectionName == "creditCards" && !guid && !record.isTemporary) {
|
||||
// We need to be logged in so we can encrypt the credit card number and
|
||||
// that's only supported when we're adding a new record.
|
||||
// TODO: "MasterPassword.ensureLoggedIn" can be removed after the storage
|
||||
// APIs are refactored to be async functions (bug 1399367).
|
||||
if (!await MasterPassword.ensureLoggedIn()) {
|
||||
throw new Error("User canceled master password entry");
|
||||
}
|
||||
}
|
||||
|
||||
let isTemporary = record.isTemporary;
|
||||
let collection = isTemporary ? this.temporaryStore[collectionName] :
|
||||
formAutofillStorage[collectionName];
|
||||
|
@ -10,7 +10,7 @@ async function setup() {
|
||||
[PTU.Addresses.TimBL], [PTU.BasicCards.JohnDoe]);
|
||||
|
||||
info("associating the card with the billing address");
|
||||
await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
|
||||
formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
|
||||
billingAddressGUID: prefilledGuids.address1GUID,
|
||||
}, true);
|
||||
|
||||
|
@ -5,7 +5,7 @@ async function setup() {
|
||||
let prefilledGuids = await addSampleAddressesAndBasicCard();
|
||||
|
||||
info("associating the card with the billing address");
|
||||
await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
|
||||
formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
|
||||
billingAddressGUID: prefilledGuids.address1GUID,
|
||||
}, true);
|
||||
}
|
||||
@ -321,7 +321,7 @@ add_task(async function test_address_edit() {
|
||||
info("initial addressOptions: " + JSON.stringify(addressOptions));
|
||||
selectedIndex = addressOptions.selectedOptionIndex;
|
||||
let selectedAddressGuid = addressOptions.options[selectedIndex].guid;
|
||||
let selectedAddress = await formAutofillStorage.addresses.get(selectedAddressGuid);
|
||||
let selectedAddress = formAutofillStorage.addresses.get(selectedAddressGuid);
|
||||
|
||||
is(selectedIndex, 0, "First address should be selected");
|
||||
ok(selectedAddress, "Selected address does exist in the address collection");
|
||||
@ -339,7 +339,7 @@ add_task(async function test_address_edit() {
|
||||
let newSelectedAddressGuid = addressOptions.options[selectedIndex].guid;
|
||||
|
||||
is(newSelectedAddressGuid, selectedAddressGuid, "Selected guid hasnt changed");
|
||||
selectedAddress = await formAutofillStorage.addresses.get(selectedAddressGuid);
|
||||
selectedAddress = formAutofillStorage.addresses.get(selectedAddressGuid);
|
||||
|
||||
is(selectedIndex, 0, "First address should be selected");
|
||||
is(selectedAddress.country, "CA", "Expected changed country value");
|
||||
|
@ -8,12 +8,12 @@ const details = PTU.Details.total60USD;
|
||||
add_task(async function test_initial_state() {
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
let address1GUID = await formAutofillStorage.addresses.add(PTU.Addresses.TimBL);
|
||||
let address1GUID = formAutofillStorage.addresses.add(PTU.Addresses.TimBL);
|
||||
await onChanged;
|
||||
|
||||
onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
let card1GUID = await formAutofillStorage.creditCards.add(PTU.BasicCards.JohnDoe);
|
||||
let card1GUID = formAutofillStorage.creditCards.add(PTU.BasicCards.JohnDoe);
|
||||
await onChanged;
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
@ -56,7 +56,7 @@ add_task(async function test_initial_state() {
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
info("adding an address");
|
||||
let address2GUID = await formAutofillStorage.addresses.add(PTU.Addresses.TimBL2);
|
||||
let address2GUID = formAutofillStorage.addresses.add(PTU.Addresses.TimBL2);
|
||||
await onChanged;
|
||||
|
||||
await spawnPaymentDialogTask(frame, async function checkAdd({
|
||||
@ -65,17 +65,11 @@ add_task(async function test_initial_state() {
|
||||
card1GUID,
|
||||
}) {
|
||||
info("checkAdd");
|
||||
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
let contentWin = Cu.waiveXrays(content);
|
||||
let {
|
||||
savedAddresses,
|
||||
savedBasicCards,
|
||||
} = await PTU.DialogContentUtils.waitForState(
|
||||
content,
|
||||
state => !!state.savedAddresses[address2GUID]
|
||||
);
|
||||
} = contentWin.document.querySelector("payment-dialog").requestStore.getState();
|
||||
|
||||
let addressGUIDs = Object.keys(savedAddresses);
|
||||
is(addressGUIDs.length, 2, "Now two savedAddresses");
|
||||
@ -97,7 +91,7 @@ add_task(async function test_initial_state() {
|
||||
onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "update");
|
||||
info("updating the credit expiration");
|
||||
await formAutofillStorage.creditCards.update(card1GUID, {
|
||||
formAutofillStorage.creditCards.update(card1GUID, {
|
||||
"cc-exp-month": 6,
|
||||
"cc-exp-year": 2029,
|
||||
}, true);
|
||||
@ -109,17 +103,11 @@ add_task(async function test_initial_state() {
|
||||
card1GUID,
|
||||
}) {
|
||||
info("checkUpdate");
|
||||
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
let contentWin = Cu.waiveXrays(content);
|
||||
let {
|
||||
savedAddresses,
|
||||
savedBasicCards,
|
||||
} = await PTU.DialogContentUtils.waitForState(
|
||||
content,
|
||||
state => !!state.savedAddresses[address2GUID]
|
||||
);
|
||||
} = contentWin.document.querySelector("payment-dialog").requestStore.getState();
|
||||
|
||||
let addressGUIDs = Object.keys(savedAddresses);
|
||||
is(addressGUIDs.length, 2, "Still two savedAddresses");
|
||||
@ -151,17 +139,11 @@ add_task(async function test_initial_state() {
|
||||
card1GUID,
|
||||
}) {
|
||||
info("checkRemove");
|
||||
|
||||
let {
|
||||
PaymentTestUtils: PTU,
|
||||
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
|
||||
let contentWin = Cu.waiveXrays(content);
|
||||
let {
|
||||
savedAddresses,
|
||||
savedBasicCards,
|
||||
} = await PTU.DialogContentUtils.waitForState(
|
||||
content,
|
||||
state => !!state.savedAddresses[address2GUID]
|
||||
);
|
||||
} = contentWin.document.querySelector("payment-dialog").requestStore.getState();
|
||||
|
||||
is(Object.keys(savedAddresses).length, 1, "Now one savedAddresses");
|
||||
is(savedAddresses[address2GUID].name, "Timothy Johann Berners-Lee", "Check full name");
|
||||
|
@ -46,7 +46,7 @@ add_task(async function test_show_completePayment() {
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "update");
|
||||
info("associating the card with the billing address");
|
||||
await formAutofillStorage.creditCards.update(card1GUID, {
|
||||
formAutofillStorage.creditCards.update(card1GUID, {
|
||||
billingAddressGUID: address1GUID,
|
||||
}, true);
|
||||
await onChanged;
|
||||
|
@ -142,7 +142,7 @@ function spawnTaskInNewDialog(requestId, contentTaskFn, args = null) {
|
||||
async function addAddressRecord(address) {
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
let guid = await formAutofillStorage.addresses.add(address);
|
||||
let guid = formAutofillStorage.addresses.add(address);
|
||||
await onChanged;
|
||||
return guid;
|
||||
}
|
||||
@ -150,7 +150,7 @@ async function addAddressRecord(address) {
|
||||
async function addCardRecord(card) {
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
let guid = await formAutofillStorage.creditCards.add(card);
|
||||
let guid = formAutofillStorage.creditCards.add(card);
|
||||
await onChanged;
|
||||
return guid;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "logLevel", "extensions.formautofill
|
||||
// This helper avoids both of those problems by never touching the
|
||||
// console object unless debug logging is enabled.
|
||||
function debug() {
|
||||
if (logLevel.toLowerCase() == "debug") {
|
||||
if (logLevel == "debug") {
|
||||
this.log.debug(...arguments);
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,6 @@ FormAutofillParent.prototype = {
|
||||
* Update the status and trigger _onStatusChanged, if necessary.
|
||||
*/
|
||||
_updateStatus() {
|
||||
log.debug("_updateStatus");
|
||||
let wasActive = this._active;
|
||||
this._active = this._computeStatus();
|
||||
if (this._active !== wasActive) {
|
||||
@ -209,27 +208,29 @@ FormAutofillParent.prototype = {
|
||||
async receiveMessage({name, data, target}) {
|
||||
switch (name) {
|
||||
case "FormAutofill:InitStorage": {
|
||||
await this.formAutofillStorage.initialize();
|
||||
this.formAutofillStorage.initialize();
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:GetRecords": {
|
||||
await this._getRecords(data, target);
|
||||
this._getRecords(data, target);
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:SaveAddress": {
|
||||
if (data.guid) {
|
||||
await this.formAutofillStorage.addresses.update(data.guid, data.address);
|
||||
this.formAutofillStorage.addresses.update(data.guid, data.address);
|
||||
} else {
|
||||
await this.formAutofillStorage.addresses.add(data.address);
|
||||
this.formAutofillStorage.addresses.add(data.address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:SaveCreditCard": {
|
||||
// TODO: "MasterPassword.ensureLoggedIn" can be removed after the storage
|
||||
// APIs are refactored to be async functions (bug 1399367).
|
||||
if (!await MasterPassword.ensureLoggedIn()) {
|
||||
log.warn("User canceled master password entry");
|
||||
return;
|
||||
}
|
||||
await this.formAutofillStorage.creditCards.add(data.creditcard);
|
||||
this.formAutofillStorage.creditCards.add(data.creditcard);
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:RemoveAddresses": {
|
||||
@ -241,7 +242,7 @@ FormAutofillParent.prototype = {
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:OnFormSubmit": {
|
||||
await this._onFormSubmit(data, target);
|
||||
this._onFormSubmit(data, target);
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:OpenPreferences": {
|
||||
@ -311,7 +312,7 @@ FormAutofillParent.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let recordsInCollection = await collection.getAll();
|
||||
let recordsInCollection = collection.getAll();
|
||||
if (!info || !info.fieldName || !recordsInCollection.length) {
|
||||
target.sendAsyncMessage("FormAutofill:Records", recordsInCollection);
|
||||
return;
|
||||
@ -355,43 +356,60 @@ FormAutofillParent.prototype = {
|
||||
|
||||
_updateSavedFieldNames() {
|
||||
log.debug("_updateSavedFieldNames");
|
||||
if (!Services.ppmm.initialProcessData.autofillSavedFieldNames) {
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames = new Set();
|
||||
} else {
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames.clear();
|
||||
}
|
||||
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames =
|
||||
new Set([...this.formAutofillStorage.addresses.getSavedFieldNames(),
|
||||
...this.formAutofillStorage.creditCards.getSavedFieldNames()]);
|
||||
["addresses", "creditCards"].forEach(c => {
|
||||
this.formAutofillStorage[c].getAll().forEach((record) => {
|
||||
Object.keys(record).forEach((fieldName) => {
|
||||
if (!record[fieldName]) {
|
||||
return;
|
||||
}
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames.add(fieldName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Remove the internal guid and metadata fields.
|
||||
this.formAutofillStorage.INTERNAL_FIELDS.forEach((fieldName) => {
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames.delete(fieldName);
|
||||
});
|
||||
|
||||
Services.ppmm.broadcastAsyncMessage("FormAutofill:savedFieldNames",
|
||||
Services.ppmm.initialProcessData.autofillSavedFieldNames);
|
||||
this._updateStatus();
|
||||
},
|
||||
|
||||
async _onAddressSubmit(address, target, timeStartedFillingMS) {
|
||||
_onAddressSubmit(address, target, timeStartedFillingMS) {
|
||||
let showDoorhanger = null;
|
||||
if (address.guid) {
|
||||
// Avoid updating the fields that users don't modify.
|
||||
let originalAddress = await this.formAutofillStorage.addresses.get(address.guid);
|
||||
let originalAddress = this.formAutofillStorage.addresses.get(address.guid);
|
||||
for (let field in address.record) {
|
||||
if (address.untouchedFields.includes(field) && originalAddress[field]) {
|
||||
address.record[field] = originalAddress[field];
|
||||
}
|
||||
}
|
||||
|
||||
if (!await this.formAutofillStorage.addresses.mergeIfPossible(address.guid, address.record, true)) {
|
||||
if (!this.formAutofillStorage.addresses.mergeIfPossible(address.guid, address.record, true)) {
|
||||
this._recordFormFillingTime("address", "autofill-update", timeStartedFillingMS);
|
||||
|
||||
showDoorhanger = async () => {
|
||||
const description = FormAutofillUtils.getAddressLabel(address.record);
|
||||
const state = await FormAutofillDoorhanger.show(target, "updateAddress", description);
|
||||
let changedGUIDs = await this.formAutofillStorage.addresses.mergeToStorage(address.record, true);
|
||||
let changedGUIDs = this.formAutofillStorage.addresses.mergeToStorage(address.record, true);
|
||||
switch (state) {
|
||||
case "create":
|
||||
if (!changedGUIDs.length) {
|
||||
changedGUIDs.push(await this.formAutofillStorage.addresses.add(address.record));
|
||||
changedGUIDs.push(this.formAutofillStorage.addresses.add(address.record));
|
||||
}
|
||||
break;
|
||||
case "update":
|
||||
if (!changedGUIDs.length) {
|
||||
await this.formAutofillStorage.addresses.update(address.guid, address.record, true);
|
||||
this.formAutofillStorage.addresses.update(address.guid, address.record, true);
|
||||
changedGUIDs.push(address.guid);
|
||||
} else {
|
||||
this.formAutofillStorage.addresses.remove(address.guid);
|
||||
@ -409,9 +427,9 @@ FormAutofillParent.prototype = {
|
||||
Services.telemetry.scalarAdd("formautofill.addresses.fill_type_autofill", 1);
|
||||
}
|
||||
} else {
|
||||
let changedGUIDs = await this.formAutofillStorage.addresses.mergeToStorage(address.record);
|
||||
let changedGUIDs = this.formAutofillStorage.addresses.mergeToStorage(address.record);
|
||||
if (!changedGUIDs.length) {
|
||||
changedGUIDs.push(await this.formAutofillStorage.addresses.add(address.record));
|
||||
changedGUIDs.push(this.formAutofillStorage.addresses.add(address.record));
|
||||
}
|
||||
changedGUIDs.forEach(guid => this.formAutofillStorage.addresses.notifyUsed(guid));
|
||||
this._recordFormFillingTime("address", "manual", timeStartedFillingMS);
|
||||
@ -437,7 +455,7 @@ FormAutofillParent.prototype = {
|
||||
return showDoorhanger;
|
||||
},
|
||||
|
||||
async _onCreditCardSubmit(creditCard, target, timeStartedFillingMS) {
|
||||
_onCreditCardSubmit(creditCard, target, timeStartedFillingMS) {
|
||||
// Updates the used status for shield/heartbeat to recognize users who have
|
||||
// used Credit Card Autofill.
|
||||
let setUsedStatus = status => {
|
||||
@ -458,7 +476,7 @@ FormAutofillParent.prototype = {
|
||||
// Indicate that the user has used Credit Card Autofill to fill in a form.
|
||||
setUsedStatus(3);
|
||||
|
||||
let originalCCData = await this.formAutofillStorage.creditCards.get(creditCard.guid);
|
||||
let originalCCData = this.formAutofillStorage.creditCards.get(creditCard.guid);
|
||||
let recordUnchanged = true;
|
||||
for (let field in creditCard.record) {
|
||||
if (creditCard.record[field] === "" && !originalCCData[field]) {
|
||||
@ -496,7 +514,7 @@ FormAutofillParent.prototype = {
|
||||
}
|
||||
|
||||
// Early return if it's a duplicate data
|
||||
let dupGuid = await this.formAutofillStorage.creditCards.getDuplicateGuid(creditCard.record);
|
||||
let dupGuid = this.formAutofillStorage.creditCards.getDuplicateGuid(creditCard.record);
|
||||
if (dupGuid) {
|
||||
this.formAutofillStorage.creditCards.notifyUsed(dupGuid);
|
||||
return false;
|
||||
@ -530,6 +548,8 @@ FormAutofillParent.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: "MasterPassword.ensureLoggedIn" can be removed after the storage
|
||||
// APIs are refactored to be async functions (bug 1399367).
|
||||
if (!await MasterPassword.ensureLoggedIn()) {
|
||||
log.warn("User canceled master password entry");
|
||||
return;
|
||||
@ -538,15 +558,15 @@ FormAutofillParent.prototype = {
|
||||
let changedGUIDs = [];
|
||||
if (creditCard.guid) {
|
||||
if (state == "update") {
|
||||
await this.formAutofillStorage.creditCards.update(creditCard.guid, creditCard.record, true);
|
||||
this.formAutofillStorage.creditCards.update(creditCard.guid, creditCard.record, true);
|
||||
changedGUIDs.push(creditCard.guid);
|
||||
} else if ("create") {
|
||||
changedGUIDs.push(await this.formAutofillStorage.creditCards.add(creditCard.record));
|
||||
changedGUIDs.push(this.formAutofillStorage.creditCards.add(creditCard.record));
|
||||
}
|
||||
} else {
|
||||
changedGUIDs.push(...await this.formAutofillStorage.creditCards.mergeToStorage(creditCard.record));
|
||||
changedGUIDs.push(...this.formAutofillStorage.creditCards.mergeToStorage(creditCard.record));
|
||||
if (!changedGUIDs.length) {
|
||||
changedGUIDs.push(await this.formAutofillStorage.creditCards.add(creditCard.record));
|
||||
changedGUIDs.push(this.formAutofillStorage.creditCards.add(creditCard.record));
|
||||
}
|
||||
}
|
||||
changedGUIDs.forEach(guid => this.formAutofillStorage.creditCards.notifyUsed(guid));
|
||||
@ -568,8 +588,8 @@ FormAutofillParent.prototype = {
|
||||
// Transmit the telemetry immediately in the meantime form submitted, and handle these pending
|
||||
// doorhangers at a later.
|
||||
await Promise.all([
|
||||
await Promise.all(address.map(addrRecord => this._onAddressSubmit(addrRecord, target, timeStartedFillingMS))),
|
||||
await Promise.all(creditCard.map(ccRecord => this._onCreditCardSubmit(ccRecord, target, timeStartedFillingMS))),
|
||||
address.map(addrRecord => this._onAddressSubmit(addrRecord, target, timeStartedFillingMS)),
|
||||
creditCard.map(ccRecord => this._onCreditCardSubmit(ccRecord, target, timeStartedFillingMS)),
|
||||
].map(pendingDoorhangers => {
|
||||
return pendingDoorhangers.filter(pendingDoorhanger => !!pendingDoorhanger &&
|
||||
typeof pendingDoorhanger == "function");
|
||||
|
@ -262,13 +262,10 @@ class AutofillRecords {
|
||||
this._collectionName = collectionName;
|
||||
this._schemaVersion = schemaVersion;
|
||||
|
||||
Promise.all(this._data.map(record => this._migrateRecord(record)))
|
||||
.then(hasChangesArr => {
|
||||
let dataHasChanges = hasChangesArr.find(hasChanges => hasChanges);
|
||||
if (dataHasChanges) {
|
||||
this._store.saveSoon();
|
||||
}
|
||||
});
|
||||
let hasChanges = (result, record) => this._migrateRecord(record) || result;
|
||||
if (this._data.reduce(hasChanges, false)) {
|
||||
this._store.saveSoon();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,10 +305,10 @@ class AutofillRecords {
|
||||
* The new record for saving.
|
||||
* @param {boolean} [options.sourceSync = false]
|
||||
* Did sync generate this addition?
|
||||
* @returns {Promise<string>}
|
||||
* @returns {string}
|
||||
* The GUID of the newly added item..
|
||||
*/
|
||||
async add(record, {sourceSync = false} = {}) {
|
||||
add(record, {sourceSync = false} = {}) {
|
||||
this.log.debug("add:", record);
|
||||
|
||||
let recordToSave = this._clone(record);
|
||||
@ -351,7 +348,7 @@ class AutofillRecords {
|
||||
return this._saveRecord(recordToSave, {sourceSync});
|
||||
}
|
||||
|
||||
async _saveRecord(record, {sourceSync = false} = {}) {
|
||||
_saveRecord(record, {sourceSync = false} = {}) {
|
||||
if (!record.guid) {
|
||||
throw new Error("Record missing GUID");
|
||||
}
|
||||
@ -369,7 +366,7 @@ class AutofillRecords {
|
||||
} else {
|
||||
this._ensureMatchingVersion(record);
|
||||
recordToSave = record;
|
||||
await this.computeFields(recordToSave);
|
||||
this.computeFields(recordToSave);
|
||||
}
|
||||
|
||||
if (sourceSync) {
|
||||
@ -405,10 +402,10 @@ class AutofillRecords {
|
||||
* Indicates which record to update.
|
||||
* @param {Object} record
|
||||
* The new record used to overwrite the old one.
|
||||
* @param {Promise<boolean>} [preserveOldProperties = false]
|
||||
* @param {boolean} [preserveOldProperties = false]
|
||||
* Preserve old record's properties if they don't exist in new record.
|
||||
*/
|
||||
async update(guid, record, preserveOldProperties = false) {
|
||||
update(guid, record, preserveOldProperties = false) {
|
||||
this.log.debug("update:", guid, record);
|
||||
|
||||
let recordFoundIndex = this._findIndexByGUID(guid);
|
||||
@ -418,7 +415,7 @@ class AutofillRecords {
|
||||
|
||||
// Clone the record before modifying it to avoid exposing incomplete changes.
|
||||
let recordFound = this._clone(this._data[recordFoundIndex]);
|
||||
await this._stripComputedFields(recordFound);
|
||||
this._stripComputedFields(recordFound);
|
||||
|
||||
let recordToUpdate = this._clone(record);
|
||||
this._normalizeRecord(recordToUpdate, true);
|
||||
@ -460,7 +457,7 @@ class AutofillRecords {
|
||||
syncMetadata.changeCounter += 1;
|
||||
}
|
||||
|
||||
await this.computeFields(recordFound);
|
||||
this.computeFields(recordFound);
|
||||
this._data[recordFoundIndex] = recordFound;
|
||||
|
||||
this._store.saveSoon();
|
||||
@ -554,10 +551,10 @@ class AutofillRecords {
|
||||
* @param {boolean} [options.rawData = false]
|
||||
* Returns a raw record without modifications and the computed fields
|
||||
* (this includes private fields)
|
||||
* @returns {Promise<Object>}
|
||||
* @returns {Object}
|
||||
* A clone of the record.
|
||||
*/
|
||||
async get(guid, {rawData = false} = {}) {
|
||||
get(guid, {rawData = false} = {}) {
|
||||
this.log.debug("get:", guid, rawData);
|
||||
|
||||
let recordFound = this._findByGUID(guid);
|
||||
@ -568,7 +565,7 @@ class AutofillRecords {
|
||||
// The record is cloned to avoid accidental modifications from outside.
|
||||
let clonedRecord = this._cloneAndCleanUp(recordFound);
|
||||
if (rawData) {
|
||||
await this._stripComputedFields(clonedRecord);
|
||||
this._stripComputedFields(clonedRecord);
|
||||
} else {
|
||||
this._recordReadProcessor(clonedRecord);
|
||||
}
|
||||
@ -582,53 +579,25 @@ class AutofillRecords {
|
||||
* Returns raw records without modifications and the computed fields.
|
||||
* @param {boolean} [options.includeDeleted = false]
|
||||
* Also return any tombstone records.
|
||||
* @returns {Promise<Array.<Object>>}
|
||||
* @returns {Array.<Object>}
|
||||
* An array containing clones of all records.
|
||||
*/
|
||||
async getAll({rawData = false, includeDeleted = false} = {}) {
|
||||
getAll({rawData = false, includeDeleted = false} = {}) {
|
||||
this.log.debug("getAll", rawData, includeDeleted);
|
||||
|
||||
let records = this._data.filter(r => !r.deleted || includeDeleted);
|
||||
// Records are cloned to avoid accidental modifications from outside.
|
||||
let clonedRecords = records.map(r => this._cloneAndCleanUp(r));
|
||||
await Promise.all(clonedRecords.map(async record => {
|
||||
clonedRecords.forEach(record => {
|
||||
if (rawData) {
|
||||
await this._stripComputedFields(record);
|
||||
this._stripComputedFields(record);
|
||||
} else {
|
||||
this._recordReadProcessor(record);
|
||||
}
|
||||
}));
|
||||
});
|
||||
return clonedRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all saved field names in the collection. This method
|
||||
* has to be sync because its caller _updateSavedFieldNames() needs
|
||||
* to dispatch content message synchronously.
|
||||
*
|
||||
* @returns {Set} Set containing saved field names.
|
||||
*/
|
||||
getSavedFieldNames() {
|
||||
this.log.debug("getSavedFieldNames");
|
||||
|
||||
let records = this._data.filter(r => !r.deleted);
|
||||
records
|
||||
.map(record => this._cloneAndCleanUp(record))
|
||||
.forEach(record => this._recordReadProcessor(record));
|
||||
|
||||
let fieldNames = new Set();
|
||||
for (let record of records) {
|
||||
for (let fieldName of Object.keys(record)) {
|
||||
if (INTERNAL_FIELDS.includes(fieldName) || !record[fieldName]) {
|
||||
continue;
|
||||
}
|
||||
fieldNames.add(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions intended to be used in the support of Sync.
|
||||
*/
|
||||
@ -755,7 +724,7 @@ class AutofillRecords {
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {Object} remoteRecord
|
||||
* @param {Promise<boolean>} [options.keepSyncMetadata = false]
|
||||
* @param {boolean} [options.keepSyncMetadata = false]
|
||||
* Should we copy Sync metadata? This is true if `remoteRecord` is a
|
||||
* merged record with local changes that we need to upload. Passing
|
||||
* `keepSyncMetadata` retains the record's change counter and
|
||||
@ -763,11 +732,11 @@ class AutofillRecords {
|
||||
* the sync is interrupted after the record is merged, but before
|
||||
* it's uploaded.
|
||||
*/
|
||||
async _replaceRecordAt(index, remoteRecord, {keepSyncMetadata = false} = {}) {
|
||||
_replaceRecordAt(index, remoteRecord, {keepSyncMetadata = false} = {}) {
|
||||
let localRecord = this._data[index];
|
||||
let newRecord = this._clone(remoteRecord);
|
||||
|
||||
await this._stripComputedFields(newRecord);
|
||||
this._stripComputedFields(newRecord);
|
||||
|
||||
this._data[index] = newRecord;
|
||||
|
||||
@ -801,7 +770,7 @@ class AutofillRecords {
|
||||
}
|
||||
}
|
||||
|
||||
await this.computeFields(newRecord);
|
||||
this.computeFields(newRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -813,7 +782,7 @@ class AutofillRecords {
|
||||
* @returns {string}
|
||||
* A clone of the local record with a new GUID.
|
||||
*/
|
||||
async _forkLocalRecord(strippedLocalRecord) {
|
||||
_forkLocalRecord(strippedLocalRecord) {
|
||||
let forkedLocalRecord = this._cloneAndCleanUp(strippedLocalRecord);
|
||||
forkedLocalRecord.guid = this._generateGUID();
|
||||
|
||||
@ -823,7 +792,7 @@ class AutofillRecords {
|
||||
// uploaded.
|
||||
this._getSyncMetaData(forkedLocalRecord, true);
|
||||
|
||||
await this.computeFields(forkedLocalRecord);
|
||||
this.computeFields(forkedLocalRecord);
|
||||
this._data.push(forkedLocalRecord);
|
||||
|
||||
return forkedLocalRecord;
|
||||
@ -838,13 +807,13 @@ class AutofillRecords {
|
||||
* must have a matching local record with the same GUID. Use
|
||||
* `add` to insert remote records that don't exist locally, and
|
||||
* `remove` to apply remote tombstones.
|
||||
* @returns {Promise<Object>}
|
||||
* @returns {Object}
|
||||
* A `{forkedGUID}` tuple. `forkedGUID` is `null` if the merge
|
||||
* succeeded without conflicts, or a new GUID referencing the
|
||||
* existing locally modified record if the conflicts could not be
|
||||
* resolved.
|
||||
*/
|
||||
async reconcile(remoteRecord) {
|
||||
reconcile(remoteRecord) {
|
||||
this._ensureMatchingVersion(remoteRecord);
|
||||
if (remoteRecord.deleted) {
|
||||
throw new Error(`Can't reconcile tombstone ${remoteRecord.guid}`);
|
||||
@ -862,26 +831,26 @@ class AutofillRecords {
|
||||
|
||||
if (sync.changeCounter === 0) {
|
||||
// Local not modified. Replace local with remote.
|
||||
await this._replaceRecordAt(localIndex, remoteRecord, {
|
||||
this._replaceRecordAt(localIndex, remoteRecord, {
|
||||
keepSyncMetadata: false,
|
||||
});
|
||||
} else {
|
||||
let strippedLocalRecord = this._clone(localRecord);
|
||||
await this._stripComputedFields(strippedLocalRecord);
|
||||
this._stripComputedFields(strippedLocalRecord);
|
||||
|
||||
let mergedRecord = this._mergeSyncedRecords(strippedLocalRecord, remoteRecord);
|
||||
if (mergedRecord) {
|
||||
// Local and remote modified, but we were able to merge. Replace the
|
||||
// local record with the merged record.
|
||||
await this._replaceRecordAt(localIndex, mergedRecord, {
|
||||
this._replaceRecordAt(localIndex, mergedRecord, {
|
||||
keepSyncMetadata: true,
|
||||
});
|
||||
} else {
|
||||
// Merge conflict. Fork the local record, then replace the original
|
||||
// with the merged record.
|
||||
let forkedLocalRecord = await this._forkLocalRecord(strippedLocalRecord);
|
||||
let forkedLocalRecord = this._forkLocalRecord(strippedLocalRecord);
|
||||
forkedGUID = forkedLocalRecord.guid;
|
||||
await this._replaceRecordAt(localIndex, remoteRecord, {
|
||||
this._replaceRecordAt(localIndex, remoteRecord, {
|
||||
keepSyncMetadata: false,
|
||||
});
|
||||
}
|
||||
@ -1078,11 +1047,11 @@ class AutofillRecords {
|
||||
*
|
||||
* @param {Object} remoteRecord
|
||||
* The remote record.
|
||||
* @returns {Promise<string|null>}
|
||||
* @returns {string|null}
|
||||
* The GUID of the matching local record, or `null` if no records
|
||||
* match.
|
||||
*/
|
||||
async findDuplicateGUID(remoteRecord) {
|
||||
findDuplicateGUID(remoteRecord) {
|
||||
if (!remoteRecord.guid) {
|
||||
throw new Error("Record missing GUID");
|
||||
}
|
||||
@ -1108,7 +1077,7 @@ class AutofillRecords {
|
||||
|
||||
// Ignore computed fields when matching records as they aren't synced at all.
|
||||
let strippedLocalRecord = this._clone(localRecord);
|
||||
await this._stripComputedFields(strippedLocalRecord);
|
||||
this._stripComputedFields(strippedLocalRecord);
|
||||
|
||||
let keys = new Set(Object.keys(remoteRecord));
|
||||
for (let key of Object.keys(strippedLocalRecord)) {
|
||||
@ -1174,7 +1143,7 @@ class AutofillRecords {
|
||||
});
|
||||
}
|
||||
|
||||
async _migrateRecord(record) {
|
||||
_migrateRecord(record) {
|
||||
let hasChanges = false;
|
||||
|
||||
if (record.deleted) {
|
||||
@ -1193,10 +1162,10 @@ class AutofillRecords {
|
||||
record.version = this.version;
|
||||
|
||||
// Force to recompute fields if we upgrade the schema.
|
||||
await this._stripComputedFields(record);
|
||||
this._stripComputedFields(record);
|
||||
}
|
||||
|
||||
hasChanges |= await this.computeFields(record);
|
||||
hasChanges |= this.computeFields(record);
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
@ -1231,10 +1200,10 @@ class AutofillRecords {
|
||||
* @returns {Array.<string>}
|
||||
* Return an array of the merged GUID string.
|
||||
*/
|
||||
async mergeToStorage(targetRecord, strict = false) {
|
||||
mergeToStorage(targetRecord, strict = false) {
|
||||
let mergedGUIDs = [];
|
||||
for (let record of this._data) {
|
||||
if (!record.deleted && await this.mergeIfPossible(record.guid, targetRecord, strict)) {
|
||||
if (!record.deleted && this.mergeIfPossible(record.guid, targetRecord, strict)) {
|
||||
mergedGUIDs.push(record.guid);
|
||||
}
|
||||
}
|
||||
@ -1254,7 +1223,7 @@ class AutofillRecords {
|
||||
}}, "formautofill-storage-changed", "removeAll");
|
||||
}
|
||||
|
||||
async _stripComputedFields(record) {
|
||||
_stripComputedFields(record) {
|
||||
this.VALID_COMPUTED_FIELDS.forEach(field => delete record[field]);
|
||||
}
|
||||
|
||||
@ -1262,7 +1231,7 @@ class AutofillRecords {
|
||||
_recordReadProcessor(record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
async computeFields(record) {}
|
||||
computeFields(record) {}
|
||||
|
||||
/**
|
||||
* An interface to be inherited to mutate the argument to normalize it.
|
||||
@ -1288,7 +1257,7 @@ class AutofillRecords {
|
||||
_validateFields(record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
async mergeIfPossible(guid, record, strict) {}
|
||||
mergeIfPossible(guid, record, strict) {}
|
||||
}
|
||||
|
||||
class Addresses extends AutofillRecords {
|
||||
@ -1303,7 +1272,7 @@ class Addresses extends AutofillRecords {
|
||||
}
|
||||
}
|
||||
|
||||
async computeFields(address) {
|
||||
computeFields(address) {
|
||||
// NOTE: Remember to bump the schema version number if any of the existing
|
||||
// computing algorithm changes. (No need to bump when just adding new
|
||||
// computed fields.)
|
||||
@ -1491,10 +1460,10 @@ class Addresses extends AutofillRecords {
|
||||
* @param {boolean} strict
|
||||
* In strict merge mode, we'll treat the subset record with empty field
|
||||
* as unable to be merged, but mergeable if in non-strict mode.
|
||||
* @returns {Promise<boolean>}
|
||||
* @returns {boolean}
|
||||
* Return true if address is merged into target with specific guid or false if not.
|
||||
*/
|
||||
async mergeIfPossible(guid, address, strict) {
|
||||
mergeIfPossible(guid, address, strict) {
|
||||
this.log.debug("mergeIfPossible:", guid, address);
|
||||
|
||||
let addressFound = this._findByGUID(guid);
|
||||
@ -1554,7 +1523,7 @@ class Addresses extends AutofillRecords {
|
||||
return true;
|
||||
}
|
||||
|
||||
await this.update(guid, addressToMerge, true);
|
||||
this.update(guid, addressToMerge, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1564,7 +1533,7 @@ class CreditCards extends AutofillRecords {
|
||||
super(store, "creditCards", VALID_CREDIT_CARD_FIELDS, VALID_CREDIT_CARD_COMPUTED_FIELDS, CREDIT_CARD_SCHEMA_VERSION);
|
||||
}
|
||||
|
||||
async computeFields(creditCard) {
|
||||
computeFields(creditCard) {
|
||||
// NOTE: Remember to bump the schema version number if any of the existing
|
||||
// computing algorithm changes. (No need to bump when just adding new
|
||||
// computed fields.)
|
||||
@ -1602,7 +1571,7 @@ class CreditCards extends AutofillRecords {
|
||||
if ("cc-number" in creditCard) {
|
||||
let ccNumber = creditCard["cc-number"];
|
||||
creditCard["cc-number"] = CreditCard.getLongMaskedNumber(ccNumber);
|
||||
creditCard["cc-number-encrypted"] = await MasterPassword.encrypt(ccNumber);
|
||||
creditCard["cc-number-encrypted"] = MasterPassword.encryptSync(ccNumber);
|
||||
} else {
|
||||
creditCard["cc-number-encrypted"] = "";
|
||||
}
|
||||
@ -1611,11 +1580,11 @@ class CreditCards extends AutofillRecords {
|
||||
return hasNewComputedFields;
|
||||
}
|
||||
|
||||
async _stripComputedFields(creditCard) {
|
||||
_stripComputedFields(creditCard) {
|
||||
if (creditCard["cc-number-encrypted"]) {
|
||||
creditCard["cc-number"] = await MasterPassword.decrypt(creditCard["cc-number-encrypted"]);
|
||||
creditCard["cc-number"] = MasterPassword.decryptSync(creditCard["cc-number-encrypted"]);
|
||||
}
|
||||
await super._stripComputedFields(creditCard);
|
||||
super._stripComputedFields(creditCard);
|
||||
}
|
||||
|
||||
_normalizeFields(creditCard) {
|
||||
@ -1678,14 +1647,14 @@ class CreditCards extends AutofillRecords {
|
||||
* Normalize the given record and return the first matched guid if storage has the same record.
|
||||
* @param {Object} targetCreditCard
|
||||
* The credit card for duplication checking.
|
||||
* @returns {Promise<string|null>}
|
||||
* @returns {string|null}
|
||||
* Return the first guid if storage has the same credit card and null otherwise.
|
||||
*/
|
||||
async getDuplicateGuid(targetCreditCard) {
|
||||
getDuplicateGuid(targetCreditCard) {
|
||||
let clonedTargetCreditCard = this._clone(targetCreditCard);
|
||||
this._normalizeRecord(clonedTargetCreditCard);
|
||||
for (let creditCard of this._data) {
|
||||
let isDuplicate = await Promise.all(this.VALID_FIELDS.map(async field => {
|
||||
let isDuplicate = this.VALID_FIELDS.every(field => {
|
||||
if (!clonedTargetCreditCard[field]) {
|
||||
return !creditCard[field];
|
||||
}
|
||||
@ -1695,10 +1664,10 @@ class CreditCards extends AutofillRecords {
|
||||
// enabled because we don't want to leak the credit card number.
|
||||
return CreditCard.getLongMaskedNumber(clonedTargetCreditCard[field]) == creditCard[field];
|
||||
}
|
||||
return (clonedTargetCreditCard[field] == await MasterPassword.decrypt(creditCard["cc-number-encrypted"]));
|
||||
return clonedTargetCreditCard[field] == MasterPassword.decryptSync(creditCard["cc-number-encrypted"]);
|
||||
}
|
||||
return clonedTargetCreditCard[field] == creditCard[field];
|
||||
})).then(fieldResults => fieldResults.every(result => result));
|
||||
});
|
||||
if (isDuplicate) {
|
||||
return creditCard.guid;
|
||||
}
|
||||
@ -1717,11 +1686,11 @@ class CreditCards extends AutofillRecords {
|
||||
* @returns {boolean}
|
||||
* Return true if credit card is merged into target with specific guid or false if not.
|
||||
*/
|
||||
async mergeIfPossible(guid, creditCard) {
|
||||
mergeIfPossible(guid, creditCard) {
|
||||
this.log.debug("mergeIfPossible:", guid, creditCard);
|
||||
|
||||
// Query raw data for comparing the decrypted credit card number
|
||||
let creditCardFound = await this.get(guid, {rawData: true});
|
||||
let creditCardFound = this.get(guid, {rawData: true});
|
||||
if (!creditCardFound) {
|
||||
throw new Error("No matching credit card.");
|
||||
}
|
||||
@ -1758,7 +1727,7 @@ class CreditCards extends AutofillRecords {
|
||||
return true;
|
||||
}
|
||||
|
||||
await this.update(guid, creditCardToMerge, true);
|
||||
this.update(guid, creditCardToMerge, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ FormAutofillStore.prototype = {
|
||||
|
||||
async getAllIDs() {
|
||||
let result = {};
|
||||
for (let {guid} of await this.storage.getAll({includeDeleted: true})) {
|
||||
for (let {guid} of this.storage.getAll({includeDeleted: true})) {
|
||||
result[guid] = true;
|
||||
}
|
||||
return result;
|
||||
@ -103,7 +103,7 @@ FormAutofillStore.prototype = {
|
||||
// Note: this function intentionally returns false in cases where we only have
|
||||
// a (local) tombstone - and formAutofillStorage.get() filters them for us.
|
||||
async itemExists(id) {
|
||||
return Boolean(await this.storage.get(id));
|
||||
return Boolean(this.storage.get(id));
|
||||
},
|
||||
|
||||
async applyIncoming(remoteRecord) {
|
||||
@ -120,7 +120,7 @@ FormAutofillStore.prototype = {
|
||||
}
|
||||
|
||||
// No matching local record. Try to dedupe a NEW local record.
|
||||
let localDupeID = await this.storage.findDuplicateGUID(remoteRecord.toEntry());
|
||||
let localDupeID = this.storage.findDuplicateGUID(remoteRecord.toEntry());
|
||||
if (localDupeID) {
|
||||
this._log.trace(`Deduping local record ${localDupeID} to remote`, remoteRecord);
|
||||
// Change the local GUID to match the incoming record, then apply the
|
||||
@ -135,13 +135,13 @@ FormAutofillStore.prototype = {
|
||||
// handles for us.)
|
||||
this._log.trace("Add record", remoteRecord);
|
||||
let entry = remoteRecord.toEntry();
|
||||
await this.storage.add(entry, {sourceSync: true});
|
||||
this.storage.add(entry, {sourceSync: true});
|
||||
},
|
||||
|
||||
async createRecord(id, collection) {
|
||||
this._log.trace("Create record", id);
|
||||
let record = new AutofillRecord(collection, id);
|
||||
let entry = await this.storage.get(id, {
|
||||
let entry = this.storage.get(id, {
|
||||
rawData: true,
|
||||
});
|
||||
if (entry) {
|
||||
@ -158,10 +158,10 @@ FormAutofillStore.prototype = {
|
||||
this._log.trace("Updating record", record);
|
||||
|
||||
let entry = record.toEntry();
|
||||
let {forkedGUID} = await this.storage.reconcile(entry);
|
||||
let {forkedGUID} = this.storage.reconcile(entry);
|
||||
if (this._log.level <= Log.Level.Debug) {
|
||||
let forkedRecord = forkedGUID ? await this.storage.get(forkedGUID) : null;
|
||||
let reconciledRecord = await this.storage.get(record.id);
|
||||
let forkedRecord = forkedGUID ? this.storage.get(forkedGUID) : null;
|
||||
let reconciledRecord = this.storage.get(record.id);
|
||||
this._log.debug("Updated local record", {
|
||||
forked: sanitizeStorageObject(forkedRecord),
|
||||
updated: sanitizeStorageObject(reconciledRecord),
|
||||
|
@ -108,6 +108,25 @@ var MasterPassword = {
|
||||
return cryptoSDR.decrypt(cipherText);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decrypts cipherText synchronously. "ensureLoggedIn()" needs to be called
|
||||
* outside in case another dialog is showing.
|
||||
*
|
||||
* NOTE: This method will be removed soon once the FormAutofillStorage APIs are
|
||||
* refactored to be async functions (bug 1399367). Please use async
|
||||
* version instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @param {string} cipherText Encrypted string including the algorithm details.
|
||||
* @returns {string} The decrypted string.
|
||||
*/
|
||||
decryptSync(cipherText) {
|
||||
if (this.isUIBusy) {
|
||||
throw Components.Exception("\"ensureLoggedIn()\" should be called first", Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
return cryptoSDR.decrypt(cipherText);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encrypts a string and returns cipher text containing algorithm information used for decryption.
|
||||
*
|
||||
@ -122,6 +141,25 @@ var MasterPassword = {
|
||||
return cryptoSDR.encrypt(plainText);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encrypts plainText synchronously. "ensureLoggedIn()" needs to be called
|
||||
* outside in case another dialog is showing.
|
||||
*
|
||||
* NOTE: This method will be removed soon once the FormAutofillStorage APIs are
|
||||
* refactored to be async functions (bug 1399367). Please use async
|
||||
* version instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @param {string} plainText A plain string to be encrypted.
|
||||
* @returns {string} The encrypted cipher string.
|
||||
*/
|
||||
encryptSync(plainText) {
|
||||
if (this.isUIBusy) {
|
||||
throw Components.Exception("\"ensureLoggedIn()\" should be called first", Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
return cryptoSDR.encrypt(plainText);
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolve when master password dialogs are closed, immediately if none are open.
|
||||
*
|
||||
|
@ -73,37 +73,35 @@
|
||||
<script type="application/javascript"><![CDATA[
|
||||
"use strict";
|
||||
|
||||
(async () => {
|
||||
let {
|
||||
getAddressLabel,
|
||||
isCCNumber,
|
||||
getCreditCardNetworks,
|
||||
} = FormAutofillUtils;
|
||||
let record = window.arguments && window.arguments[0];
|
||||
let addresses = {};
|
||||
for (let address of await formAutofillStorage.addresses.getAll()) {
|
||||
addresses[address.guid] = address;
|
||||
}
|
||||
let {
|
||||
getAddressLabel,
|
||||
isCCNumber,
|
||||
getCreditCardNetworks,
|
||||
} = FormAutofillUtils;
|
||||
let record = window.arguments && window.arguments[0];
|
||||
let addresses = {};
|
||||
for (let address of formAutofillStorage.addresses.getAll()) {
|
||||
addresses[address.guid] = address;
|
||||
}
|
||||
|
||||
/* import-globals-from autofillEditForms.js */
|
||||
let fieldContainer = new EditCreditCard({
|
||||
form: document.getElementById("form"),
|
||||
}, record, addresses,
|
||||
{
|
||||
getAddressLabel: getAddressLabel.bind(FormAutofillUtils),
|
||||
isCCNumber: isCCNumber.bind(FormAutofillUtils),
|
||||
getSupportedNetworks: getCreditCardNetworks.bind(FormAutofillUtils),
|
||||
});
|
||||
/* import-globals-from autofillEditForms.js */
|
||||
let fieldContainer = new EditCreditCard({
|
||||
form: document.getElementById("form"),
|
||||
}, record, addresses,
|
||||
{
|
||||
getAddressLabel: getAddressLabel.bind(FormAutofillUtils),
|
||||
isCCNumber: isCCNumber.bind(FormAutofillUtils),
|
||||
getSupportedNetworks: getCreditCardNetworks.bind(FormAutofillUtils),
|
||||
});
|
||||
|
||||
/* import-globals-from editDialog.js */
|
||||
new EditCreditCardDialog({
|
||||
title: document.querySelector("title"),
|
||||
fieldContainer,
|
||||
controlsContainer: document.getElementById("controls-container"),
|
||||
cancel: document.getElementById("cancel"),
|
||||
save: document.getElementById("save"),
|
||||
}, record);
|
||||
})();
|
||||
/* import-globals-from editDialog.js */
|
||||
new EditCreditCardDialog({
|
||||
title: document.querySelector("title"),
|
||||
fieldContainer,
|
||||
controlsContainer: document.getElementById("controls-container"),
|
||||
cancel: document.getElementById("cancel"),
|
||||
save: document.getElementById("save"),
|
||||
}, record);
|
||||
]]></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,6 +13,8 @@ ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "formAutofillStorage",
|
||||
"resource://formautofill/FormAutofillStorage.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "MasterPassword",
|
||||
"resource://formautofill/MasterPassword.jsm");
|
||||
|
||||
class AutofillEditDialog {
|
||||
constructor(subStorageName, elements, record) {
|
||||
@ -49,9 +51,9 @@ class AutofillEditDialog {
|
||||
async saveRecord(record, guid) {
|
||||
let storage = await this.getStorage();
|
||||
if (guid) {
|
||||
await storage.update(guid, record);
|
||||
storage.update(guid, record);
|
||||
} else {
|
||||
await storage.add(record);
|
||||
storage.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,11 +178,15 @@ class EditCreditCardDialog extends AutofillEditDialog {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.saveRecord(creditCard, this._record ? this._record.guid : null);
|
||||
window.close();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
// TODO: "MasterPassword.ensureLoggedIn" can be removed after the storage
|
||||
// APIs are refactored to be async functions (bug 1399367).
|
||||
if (await MasterPassword.ensureLoggedIn()) {
|
||||
try {
|
||||
await this.saveRecord(creditCard, this._record ? this._record.guid : null);
|
||||
window.close();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class ManageRecords {
|
||||
|
||||
async _loadRecords() {
|
||||
let storage = await this.getStorage();
|
||||
let records = await storage.getAll();
|
||||
let records = storage.getAll();
|
||||
// Sort by last modified time starting with most recent
|
||||
records.sort((a, b) => b.timeLastModified - a.timeLastModified);
|
||||
await this.renderRecordElements(records);
|
||||
|
@ -53,17 +53,17 @@ add_task(async function test_activeStatus_observe() {
|
||||
Assert.equal(formAutofillParent._onStatusChanged.called, true);
|
||||
|
||||
// profile changed => Need to trigger _onStatusChanged
|
||||
await Promise.all(["add", "update", "remove", "reconcile"].map(async event => {
|
||||
["add", "update", "remove", "reconcile"].forEach(event => {
|
||||
formAutofillParent._computeStatus.returns(!formAutofillParent._active);
|
||||
formAutofillParent._onStatusChanged.reset();
|
||||
await formAutofillParent.observe(null, "formautofill-storage-changed", event);
|
||||
formAutofillParent.observe(null, "formautofill-storage-changed", event);
|
||||
Assert.equal(formAutofillParent._onStatusChanged.called, true);
|
||||
}));
|
||||
});
|
||||
|
||||
// profile metadata updated => No need to trigger _onStatusChanged
|
||||
formAutofillParent._computeStatus.returns(!formAutofillParent._active);
|
||||
formAutofillParent._onStatusChanged.reset();
|
||||
await formAutofillParent.observe(null, "formautofill-storage-changed", "notifyUsed");
|
||||
formAutofillParent.observe(null, "formautofill-storage-changed", "notifyUsed");
|
||||
Assert.equal(formAutofillParent._onStatusChanged.called, false);
|
||||
});
|
||||
|
||||
@ -75,7 +75,7 @@ add_task(async function test_activeStatus_computeStatus() {
|
||||
});
|
||||
|
||||
sinon.stub(formAutofillParent.formAutofillStorage.addresses, "getAll");
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns(Promise.all([]));
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns([]);
|
||||
|
||||
// pref is enabled and profile is empty.
|
||||
Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", true);
|
||||
@ -87,8 +87,8 @@ add_task(async function test_activeStatus_computeStatus() {
|
||||
Services.prefs.setBoolPref("extensions.formautofill.creditCards.enabled", false);
|
||||
Assert.equal(formAutofillParent._computeStatus(), false);
|
||||
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns(Promise.all([{"given-name": "John"}]));
|
||||
await formAutofillParent.observe(null, "formautofill-storage-changed", "add");
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns([{"given-name": "John"}]);
|
||||
formAutofillParent.observe(null, "formautofill-storage-changed", "add");
|
||||
// pref is enabled and profile is not empty.
|
||||
Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.formautofill.addresses.enabled", true);
|
||||
|
@ -287,7 +287,7 @@ add_task(async function test_getAll() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
|
||||
Assert.equal(addresses.length, 2);
|
||||
do_check_record_matches(addresses[0], TEST_ADDRESS_1);
|
||||
@ -299,44 +299,44 @@ add_task(async function test_getAll() {
|
||||
Assert.equal(addresses[0]["address-line2"], "MIT Room 32-G524");
|
||||
|
||||
// Test with rawData set.
|
||||
addresses = await profileStorage.addresses.getAll({rawData: true});
|
||||
addresses = profileStorage.addresses.getAll({rawData: true});
|
||||
Assert.equal(addresses[0].name, undefined);
|
||||
Assert.equal(addresses[0]["address-line1"], undefined);
|
||||
Assert.equal(addresses[0]["address-line2"], undefined);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
addresses[0].organization = "test";
|
||||
do_check_record_matches((await profileStorage.addresses.getAll())[0], TEST_ADDRESS_1);
|
||||
do_check_record_matches(profileStorage.addresses.getAll()[0], TEST_ADDRESS_1);
|
||||
});
|
||||
|
||||
add_task(async function test_get() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[0].guid;
|
||||
|
||||
let address = await profileStorage.addresses.get(guid);
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
do_check_record_matches(address, TEST_ADDRESS_1);
|
||||
|
||||
// Test with rawData set.
|
||||
address = await profileStorage.addresses.get(guid, {rawData: true});
|
||||
address = profileStorage.addresses.get(guid, {rawData: true});
|
||||
Assert.equal(address.name, undefined);
|
||||
Assert.equal(address["address-line1"], undefined);
|
||||
Assert.equal(address["address-line2"], undefined);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
address.organization = "test";
|
||||
do_check_record_matches(await profileStorage.addresses.get(guid), TEST_ADDRESS_1);
|
||||
do_check_record_matches(profileStorage.addresses.get(guid), TEST_ADDRESS_1);
|
||||
|
||||
Assert.equal(await profileStorage.addresses.get("INVALID_GUID"), null);
|
||||
Assert.equal(profileStorage.addresses.get("INVALID_GUID"), null);
|
||||
});
|
||||
|
||||
add_task(async function test_add() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
|
||||
Assert.equal(addresses.length, 2);
|
||||
|
||||
@ -351,23 +351,23 @@ add_task(async function test_add() {
|
||||
Assert.equal(addresses[0].timesUsed, 0);
|
||||
|
||||
// Empty string should be deleted before saving.
|
||||
await profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_FIELD);
|
||||
profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_FIELD);
|
||||
let address = profileStorage.addresses._data[2];
|
||||
Assert.equal(address.name, TEST_ADDRESS_WITH_EMPTY_FIELD.name);
|
||||
Assert.equal(address["street-address"], undefined);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
await profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD);
|
||||
profileStorage.addresses.add(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD);
|
||||
address = profileStorage.addresses._data[3];
|
||||
Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.add(TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
Assert.throws(() => profileStorage.addresses.add(TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.add({}),
|
||||
Assert.throws(() => profileStorage.addresses.add({}),
|
||||
/Record contains no valid field\./);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.add(TEST_ADDRESS_EMPTY_AFTER_NORMALIZE),
|
||||
Assert.throws(() => profileStorage.addresses.add(TEST_ADDRESS_EMPTY_AFTER_NORMALIZE),
|
||||
/Record contains no valid field\./);
|
||||
});
|
||||
|
||||
@ -385,7 +385,7 @@ add_task(async function test_update() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
let timeLastModified = addresses[1].timeLastModified;
|
||||
|
||||
@ -399,13 +399,13 @@ add_task(async function test_update() {
|
||||
|
||||
Assert.notEqual(addresses[1].country, undefined);
|
||||
|
||||
await profileStorage.addresses.update(guid, TEST_ADDRESS_3);
|
||||
profileStorage.addresses.update(guid, TEST_ADDRESS_3);
|
||||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage.addresses.pullSyncChanges(); // force sync metadata, which we check below.
|
||||
|
||||
let address = await profileStorage.addresses.get(guid, {rawData: true});
|
||||
let address = profileStorage.addresses.get(guid, {rawData: true});
|
||||
|
||||
Assert.equal(address.country, undefined);
|
||||
Assert.notEqual(address.timeLastModified, timeLastModified);
|
||||
@ -413,13 +413,13 @@ add_task(async function test_update() {
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
|
||||
// Test preserveOldProperties parameter and field with empty string.
|
||||
await profileStorage.addresses.update(guid, TEST_ADDRESS_WITH_EMPTY_FIELD, true);
|
||||
profileStorage.addresses.update(guid, TEST_ADDRESS_WITH_EMPTY_FIELD, true);
|
||||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage.addresses.pullSyncChanges(); // force sync metadata, which we check below.
|
||||
|
||||
address = await profileStorage.addresses.get(guid, {rawData: true});
|
||||
address = profileStorage.addresses.get(guid, {rawData: true});
|
||||
|
||||
Assert.equal(address["given-name"], "Tim");
|
||||
Assert.equal(address["family-name"], "Berners");
|
||||
@ -429,37 +429,42 @@ add_task(async function test_update() {
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 2);
|
||||
|
||||
// Empty string should be deleted while updating.
|
||||
await profileStorage.addresses.update(profileStorage.addresses._data[0].guid, TEST_ADDRESS_WITH_EMPTY_FIELD);
|
||||
profileStorage.addresses.update(profileStorage.addresses._data[0].guid, TEST_ADDRESS_WITH_EMPTY_FIELD);
|
||||
address = profileStorage.addresses._data[0];
|
||||
Assert.equal(address.name, TEST_ADDRESS_WITH_EMPTY_FIELD.name);
|
||||
Assert.equal(address["street-address"], undefined);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
await profileStorage.addresses.update(profileStorage.addresses._data[0].guid, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, false);
|
||||
profileStorage.addresses.update(profileStorage.addresses._data[0].guid, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, false);
|
||||
address = profileStorage.addresses._data[0];
|
||||
Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email);
|
||||
await profileStorage.addresses.update(profileStorage.addresses._data[1].guid, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, true);
|
||||
profileStorage.addresses.update(profileStorage.addresses._data[1].guid, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, true);
|
||||
address = profileStorage.addresses._data[1];
|
||||
Assert.equal(address.email, TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD.email);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.update("INVALID_GUID", TEST_ADDRESS_3),
|
||||
Assert.throws(
|
||||
() => profileStorage.addresses.update("INVALID_GUID", TEST_ADDRESS_3),
|
||||
/No matching record\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.update(guid, TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
Assert.throws(
|
||||
() => profileStorage.addresses.update(guid, TEST_ADDRESS_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.update(guid, {}),
|
||||
Assert.throws(
|
||||
() => profileStorage.addresses.update(guid, {}),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.update(guid, TEST_ADDRESS_EMPTY_AFTER_NORMALIZE),
|
||||
Assert.throws(
|
||||
() => profileStorage.addresses.update(guid, TEST_ADDRESS_EMPTY_AFTER_NORMALIZE),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
|
||||
profileStorage.addresses.update(guid, TEST_ADDRESS_2);
|
||||
await Assert.rejects(profileStorage.addresses.update(guid, TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2),
|
||||
Assert.throws(
|
||||
() => profileStorage.addresses.update(guid, TEST_ADDRESS_EMPTY_AFTER_UPDATE_ADDRESS_2),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
});
|
||||
@ -468,7 +473,7 @@ add_task(async function test_notifyUsed() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
let timeLastUsed = addresses[1].timeLastUsed;
|
||||
let timesUsed = addresses[1].timesUsed;
|
||||
@ -486,7 +491,7 @@ add_task(async function test_notifyUsed() {
|
||||
profileStorage.addresses.notifyUsed(guid);
|
||||
await onChanged;
|
||||
|
||||
let address = await profileStorage.addresses.get(guid);
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
|
||||
Assert.equal(address.timesUsed, timesUsed + 1);
|
||||
Assert.notEqual(address.timeLastUsed, timeLastUsed);
|
||||
@ -503,7 +508,7 @@ add_task(async function test_remove() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
||||
let onChanged = TestUtils.topicObserved(
|
||||
@ -519,11 +524,11 @@ add_task(async function test_remove() {
|
||||
profileStorage.addresses.remove(guid);
|
||||
await onChanged;
|
||||
|
||||
addresses = await profileStorage.addresses.getAll();
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
|
||||
Assert.equal(addresses.length, 1);
|
||||
|
||||
Assert.equal(await profileStorage.addresses.get(guid), null);
|
||||
Assert.equal(profileStorage.addresses.get(guid), null);
|
||||
});
|
||||
|
||||
MERGE_TESTCASES.forEach((testcase) => {
|
||||
@ -531,7 +536,7 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
info("Starting testcase: " + testcase.description);
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[testcase.addressInStorage]);
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[0].guid;
|
||||
let timeLastModified = addresses[0].timeLastModified;
|
||||
|
||||
@ -555,7 +560,7 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
await onMerged;
|
||||
}
|
||||
|
||||
addresses = await profileStorage.addresses.getAll();
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
Assert.equal(addresses.length, 1);
|
||||
do_check_record_matches(addresses[0], testcase.expectedAddress);
|
||||
if (testcase.noNeedToUpdate) {
|
||||
@ -574,7 +579,7 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
|
||||
add_task(async function test_merge_same_address() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [TEST_ADDRESS_1]);
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[0].guid;
|
||||
let timeLastModified = addresses[0].timeLastModified;
|
||||
|
||||
@ -594,7 +599,7 @@ add_task(async function test_merge_unable_merge() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
||||
// Force to create sync metadata.
|
||||
@ -602,15 +607,15 @@ add_task(async function test_merge_unable_merge() {
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
|
||||
// Unable to merge because of conflict
|
||||
Assert.equal(await profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_3), false);
|
||||
Assert.equal(profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_3), false);
|
||||
|
||||
// Unable to merge because no overlap
|
||||
Assert.equal(await profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_4), false);
|
||||
Assert.equal(profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_4), false);
|
||||
|
||||
// Unable to strict merge because subset with empty string
|
||||
let subset = Object.assign({}, TEST_ADDRESS_1);
|
||||
subset.organization = "";
|
||||
Assert.equal(await profileStorage.addresses.mergeIfPossible(guid, subset, true), false);
|
||||
Assert.equal(profileStorage.addresses.mergeIfPossible(guid, subset, true), false);
|
||||
|
||||
// Shouldn't bump the change counter
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
@ -621,15 +626,14 @@ add_task(async function test_mergeToStorage() {
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
// Merge an address to storage
|
||||
let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_2);
|
||||
await profileStorage.addresses.add(anotherAddress);
|
||||
profileStorage.addresses.add(anotherAddress);
|
||||
anotherAddress.email = "timbl@w3.org";
|
||||
Assert.equal((await profileStorage.addresses.mergeToStorage(anotherAddress)).length, 2);
|
||||
|
||||
Assert.equal((await profileStorage.addresses.getAll())[1].email, anotherAddress.email);
|
||||
Assert.equal((await profileStorage.addresses.getAll())[2].email, anotherAddress.email);
|
||||
Assert.equal(profileStorage.addresses.mergeToStorage(anotherAddress).length, 2);
|
||||
Assert.equal(profileStorage.addresses.getAll()[1].email, anotherAddress.email);
|
||||
Assert.equal(profileStorage.addresses.getAll()[2].email, anotherAddress.email);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
Assert.equal((await profileStorage.addresses.mergeToStorage(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD)).length, 3);
|
||||
Assert.equal(profileStorage.addresses.mergeToStorage(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD).length, 3);
|
||||
});
|
||||
|
||||
add_task(async function test_mergeToStorage_strict() {
|
||||
@ -638,9 +642,9 @@ add_task(async function test_mergeToStorage_strict() {
|
||||
// Try to merge a subset with empty string
|
||||
let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_1);
|
||||
anotherAddress.email = "";
|
||||
Assert.equal((await profileStorage.addresses.mergeToStorage(anotherAddress, true)).length, 0);
|
||||
Assert.equal((await profileStorage.addresses.getAll())[0].email, TEST_ADDRESS_1.email);
|
||||
Assert.equal(profileStorage.addresses.mergeToStorage(anotherAddress, true).length, 0);
|
||||
Assert.equal(profileStorage.addresses.getAll()[0].email, TEST_ADDRESS_1.email);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
Assert.equal((await profileStorage.addresses.mergeToStorage(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, true)).length, 1);
|
||||
Assert.equal(profileStorage.addresses.mergeToStorage(TEST_ADDRESS_WITH_EMPTY_COMPUTED_FIELD, true).length, 1);
|
||||
});
|
||||
|
@ -210,9 +210,9 @@ let prepareTestCreditCards = async function(path) {
|
||||
subject.wrappedJSObject.guid &&
|
||||
subject.wrappedJSObject.collectionName == COLLECTION_NAME
|
||||
);
|
||||
Assert.ok(await profileStorage.creditCards.add(TEST_CREDIT_CARD_1));
|
||||
Assert.ok(profileStorage.creditCards.add(TEST_CREDIT_CARD_1));
|
||||
await onChanged;
|
||||
Assert.ok(await profileStorage.creditCards.add(TEST_CREDIT_CARD_2));
|
||||
Assert.ok(profileStorage.creditCards.add(TEST_CREDIT_CARD_2));
|
||||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
};
|
||||
@ -259,7 +259,7 @@ add_task(async function test_getAll() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
|
||||
Assert.equal(creditCards.length, 2);
|
||||
do_check_credit_card_matches(creditCards[0], TEST_CREDIT_CARD_1);
|
||||
@ -271,14 +271,14 @@ add_task(async function test_getAll() {
|
||||
Assert.equal(creditCards[0]["cc-exp"], "2017-04");
|
||||
|
||||
// Test with rawData set.
|
||||
creditCards = await profileStorage.creditCards.getAll({rawData: true});
|
||||
creditCards = profileStorage.creditCards.getAll({rawData: true});
|
||||
Assert.equal(creditCards[0]["cc-given-name"], undefined);
|
||||
Assert.equal(creditCards[0]["cc-family-name"], undefined);
|
||||
Assert.equal(creditCards[0]["cc-exp"], undefined);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
creditCards[0]["cc-name"] = "test";
|
||||
do_check_credit_card_matches((await profileStorage.creditCards.getAll())[0], TEST_CREDIT_CARD_1);
|
||||
do_check_credit_card_matches(profileStorage.creditCards.getAll()[0], TEST_CREDIT_CARD_1);
|
||||
});
|
||||
|
||||
add_task(async function test_get() {
|
||||
@ -288,17 +288,17 @@ add_task(async function test_get() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[0].guid;
|
||||
|
||||
let creditCard = await profileStorage.creditCards.get(guid);
|
||||
let creditCard = profileStorage.creditCards.get(guid);
|
||||
do_check_credit_card_matches(creditCard, TEST_CREDIT_CARD_1);
|
||||
|
||||
// Modifying output shouldn't affect the storage.
|
||||
creditCards[0]["cc-name"] = "test";
|
||||
do_check_credit_card_matches(await profileStorage.creditCards.get(guid), TEST_CREDIT_CARD_1);
|
||||
do_check_credit_card_matches(profileStorage.creditCards.get(guid), TEST_CREDIT_CARD_1);
|
||||
|
||||
Assert.equal(await profileStorage.creditCards.get("INVALID_GUID"), null);
|
||||
Assert.equal(profileStorage.creditCards.get("INVALID_GUID"), null);
|
||||
});
|
||||
|
||||
add_task(async function test_add() {
|
||||
@ -308,7 +308,7 @@ add_task(async function test_add() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
|
||||
Assert.equal(creditCards.length, 2);
|
||||
|
||||
@ -323,25 +323,25 @@ add_task(async function test_add() {
|
||||
Assert.equal(creditCards[0].timesUsed, 0);
|
||||
|
||||
// Empty string should be deleted before saving.
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_EMPTY_FIELD);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_EMPTY_FIELD);
|
||||
let creditCard = profileStorage.creditCards._data[2];
|
||||
Assert.equal(creditCard["cc-exp-month"], TEST_CREDIT_CARD_WITH_EMPTY_FIELD["cc-exp-month"]);
|
||||
Assert.equal(creditCard["cc-name"], undefined);
|
||||
Assert.equal(creditCard.billingAddressGUID, undefined);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD);
|
||||
creditCard = profileStorage.creditCards._data[3];
|
||||
Assert.equal(creditCard["cc-number"],
|
||||
CreditCard.getLongMaskedNumber(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD["cc-number"]));
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_FIELD),
|
||||
Assert.throws(() => profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./);
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.add({}),
|
||||
Assert.throws(() => profileStorage.creditCards.add({}),
|
||||
/Record contains no valid field\./);
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.add(TEST_CREDIT_CARD_EMPTY_AFTER_NORMALIZE),
|
||||
Assert.throws(() => profileStorage.creditCards.add(TEST_CREDIT_CARD_EMPTY_AFTER_NORMALIZE),
|
||||
/Record contains no valid field\./);
|
||||
});
|
||||
|
||||
@ -350,13 +350,13 @@ add_task(async function test_addWithBillingAddress() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
|
||||
Assert.equal(creditCards.length, 0);
|
||||
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_BILLING_ADDRESS);
|
||||
|
||||
creditCards = await profileStorage.creditCards.getAll();
|
||||
creditCards = profileStorage.creditCards.getAll();
|
||||
Assert.equal(creditCards.length, 1);
|
||||
do_check_credit_card_matches(creditCards[0], TEST_CREDIT_CARD_WITH_BILLING_ADDRESS);
|
||||
});
|
||||
@ -378,7 +378,7 @@ add_task(async function test_update() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[1].guid;
|
||||
let timeLastModified = creditCards[1].timeLastModified;
|
||||
|
||||
@ -391,21 +391,21 @@ add_task(async function test_update() {
|
||||
);
|
||||
|
||||
Assert.notEqual(creditCards[1]["cc-name"], undefined);
|
||||
await profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_3);
|
||||
profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_3);
|
||||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCard = await profileStorage.creditCards.get(guid);
|
||||
let creditCard = profileStorage.creditCards.get(guid);
|
||||
|
||||
Assert.equal(creditCard["cc-name"], undefined);
|
||||
Assert.notEqual(creditCard.timeLastModified, timeLastModified);
|
||||
do_check_credit_card_matches(creditCard, TEST_CREDIT_CARD_3);
|
||||
|
||||
// Empty string should be deleted while updating.
|
||||
await profileStorage.creditCards.update(profileStorage.creditCards._data[0].guid, TEST_CREDIT_CARD_WITH_EMPTY_FIELD);
|
||||
profileStorage.creditCards.update(profileStorage.creditCards._data[0].guid, TEST_CREDIT_CARD_WITH_EMPTY_FIELD);
|
||||
creditCard = profileStorage.creditCards._data[0];
|
||||
Assert.equal(creditCard["cc-exp-month"], TEST_CREDIT_CARD_WITH_EMPTY_FIELD["cc-exp-month"]);
|
||||
Assert.equal(creditCard["cc-name"], undefined);
|
||||
@ -413,33 +413,38 @@ add_task(async function test_update() {
|
||||
Assert.equal(creditCard.billingAddressGUID, undefined);
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
await profileStorage.creditCards.update(profileStorage.creditCards._data[0].guid, TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD, false);
|
||||
profileStorage.creditCards.update(profileStorage.creditCards._data[0].guid, TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD, false);
|
||||
creditCard = profileStorage.creditCards._data[0];
|
||||
Assert.equal(creditCard["cc-number"],
|
||||
CreditCard.getLongMaskedNumber(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD["cc-number"]));
|
||||
await profileStorage.creditCards.update(profileStorage.creditCards._data[1].guid, TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD, true);
|
||||
profileStorage.creditCards.update(profileStorage.creditCards._data[1].guid, TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD, true);
|
||||
creditCard = profileStorage.creditCards._data[1];
|
||||
Assert.equal(creditCard["cc-number"],
|
||||
CreditCard.getLongMaskedNumber(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD["cc-number"]));
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.update("INVALID_GUID", TEST_CREDIT_CARD_3),
|
||||
Assert.throws(
|
||||
() => profileStorage.creditCards.update("INVALID_GUID", TEST_CREDIT_CARD_3),
|
||||
/No matching record\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_WITH_INVALID_FIELD),
|
||||
Assert.throws(
|
||||
() => profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_WITH_INVALID_FIELD),
|
||||
/"invalidField" is not a valid field\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.update(guid, {}),
|
||||
Assert.throws(
|
||||
() => profileStorage.creditCards.update(guid, {}),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
|
||||
await Assert.rejects(profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_EMPTY_AFTER_NORMALIZE),
|
||||
Assert.throws(
|
||||
() => profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_EMPTY_AFTER_NORMALIZE),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
|
||||
await profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_1);
|
||||
await Assert.rejects(profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_EMPTY_AFTER_UPDATE_CREDIT_CARD_1),
|
||||
profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_1);
|
||||
Assert.throws(
|
||||
() => profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_EMPTY_AFTER_UPDATE_CREDIT_CARD_1),
|
||||
/Record contains no valid field\./
|
||||
);
|
||||
});
|
||||
@ -450,12 +455,12 @@ add_task(async function test_validate() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_EXPIRY_DATE);
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_2_DIGITS_YEAR);
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_SPACES_BETWEEN_DIGITS);
|
||||
await profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_NETWORK);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_EXPIRY_DATE);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_2_DIGITS_YEAR);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_SPACES_BETWEEN_DIGITS);
|
||||
profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_NETWORK);
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
|
||||
Assert.equal(creditCards[0]["cc-exp-month"], undefined);
|
||||
Assert.equal(creditCards[0]["cc-exp-year"], undefined);
|
||||
@ -481,7 +486,7 @@ add_task(async function test_notifyUsed() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[1].guid;
|
||||
let timeLastUsed = creditCards[1].timeLastUsed;
|
||||
let timesUsed = creditCards[1].timesUsed;
|
||||
@ -501,7 +506,7 @@ add_task(async function test_notifyUsed() {
|
||||
profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCard = await profileStorage.creditCards.get(guid);
|
||||
let creditCard = profileStorage.creditCards.get(guid);
|
||||
|
||||
Assert.equal(creditCard.timesUsed, timesUsed + 1);
|
||||
Assert.notEqual(creditCard.timeLastUsed, timeLastUsed);
|
||||
@ -517,7 +522,7 @@ add_task(async function test_remove() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[1].guid;
|
||||
|
||||
let onChanged = TestUtils.topicObserved(
|
||||
@ -537,11 +542,11 @@ add_task(async function test_remove() {
|
||||
profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
creditCards = await profileStorage.creditCards.getAll();
|
||||
creditCards = profileStorage.creditCards.getAll();
|
||||
|
||||
Assert.equal(creditCards.length, 1);
|
||||
|
||||
Assert.equal(await profileStorage.creditCards.get(guid), null);
|
||||
Assert.equal(profileStorage.creditCards.get(guid), null);
|
||||
});
|
||||
|
||||
MERGE_TESTCASES.forEach((testcase) => {
|
||||
@ -550,7 +555,7 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[testcase.creditCardInStorage],
|
||||
"creditCards");
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[0].guid;
|
||||
let timeLastModified = creditCards[0].timeLastModified;
|
||||
// Merge creditCard and verify the guid in notifyObservers subject
|
||||
@ -564,11 +569,11 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
// Force to create sync metadata.
|
||||
profileStorage.creditCards.pullSyncChanges();
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.creditCards, guid), 1);
|
||||
Assert.ok(await profileStorage.creditCards.mergeIfPossible(guid, testcase.creditCardToMerge));
|
||||
Assert.ok(profileStorage.creditCards.mergeIfPossible(guid, testcase.creditCardToMerge));
|
||||
if (!testcase.noNeedToUpdate) {
|
||||
await onMerged;
|
||||
}
|
||||
creditCards = await profileStorage.creditCards.getAll();
|
||||
creditCards = profileStorage.creditCards.getAll();
|
||||
Assert.equal(creditCards.length, 1);
|
||||
do_check_credit_card_matches(creditCards[0], testcase.expectedCreditCard);
|
||||
if (!testcase.noNeedToUpdate) {
|
||||
@ -589,7 +594,7 @@ add_task(async function test_merge_unable_merge() {
|
||||
[TEST_CREDIT_CARD_1],
|
||||
"creditCards");
|
||||
|
||||
let creditCards = await profileStorage.creditCards.getAll();
|
||||
let creditCards = profileStorage.creditCards.getAll();
|
||||
let guid = creditCards[0].guid;
|
||||
// Force to create sync metadata.
|
||||
profileStorage.creditCards.pullSyncChanges();
|
||||
@ -598,14 +603,14 @@ add_task(async function test_merge_unable_merge() {
|
||||
// Unable to merge because of conflict
|
||||
let anotherCreditCard = profileStorage.creditCards._clone(TEST_CREDIT_CARD_1);
|
||||
anotherCreditCard["cc-name"] = "Foo Bar";
|
||||
Assert.equal(await profileStorage.creditCards.mergeIfPossible(guid, anotherCreditCard), false);
|
||||
Assert.equal(profileStorage.creditCards.mergeIfPossible(guid, anotherCreditCard), false);
|
||||
// The change counter is unchanged.
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.creditCards, guid), 1);
|
||||
|
||||
// Unable to merge because no credit card number
|
||||
anotherCreditCard = profileStorage.creditCards._clone(TEST_CREDIT_CARD_1);
|
||||
anotherCreditCard["cc-number"] = "";
|
||||
Assert.equal(await profileStorage.creditCards.mergeIfPossible(guid, anotherCreditCard), false);
|
||||
Assert.equal(profileStorage.creditCards.mergeIfPossible(guid, anotherCreditCard), false);
|
||||
// The change counter is still unchanged.
|
||||
Assert.equal(getSyncChangeCounter(profileStorage.creditCards, guid), 1);
|
||||
});
|
||||
@ -617,14 +622,14 @@ add_task(async function test_mergeToStorage() {
|
||||
// Merge a creditCard to storage
|
||||
let anotherCreditCard = profileStorage.creditCards._clone(TEST_CREDIT_CARD_3);
|
||||
anotherCreditCard["cc-name"] = "Foo Bar";
|
||||
Assert.equal((await profileStorage.creditCards.mergeToStorage(anotherCreditCard)).length, 2);
|
||||
Assert.equal((await profileStorage.creditCards.getAll())[0]["cc-name"], "Foo Bar");
|
||||
Assert.equal((await profileStorage.creditCards.getAll())[0]["cc-exp"], "2000-01");
|
||||
Assert.equal((await profileStorage.creditCards.getAll())[1]["cc-name"], "Foo Bar");
|
||||
Assert.equal((await profileStorage.creditCards.getAll())[1]["cc-exp"], "2000-01");
|
||||
Assert.equal(profileStorage.creditCards.mergeToStorage(anotherCreditCard).length, 2);
|
||||
Assert.equal(profileStorage.creditCards.getAll()[0]["cc-name"], "Foo Bar");
|
||||
Assert.equal(profileStorage.creditCards.getAll()[0]["cc-exp"], "2000-01");
|
||||
Assert.equal(profileStorage.creditCards.getAll()[1]["cc-name"], "Foo Bar");
|
||||
Assert.equal(profileStorage.creditCards.getAll()[1]["cc-exp"], "2000-01");
|
||||
|
||||
// Empty computed fields shouldn't cause any problem.
|
||||
Assert.equal((await profileStorage.creditCards.mergeToStorage(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD)).length, 0);
|
||||
Assert.equal(profileStorage.creditCards.mergeToStorage(TEST_CREDIT_CARD_WITH_EMPTY_COMPUTED_FIELD).length, 0);
|
||||
});
|
||||
|
||||
add_task(async function test_getDuplicateGuid() {
|
||||
@ -634,20 +639,20 @@ add_task(async function test_getDuplicateGuid() {
|
||||
let guid = profileStorage.creditCards._data[0].guid;
|
||||
|
||||
// Absolutely a duplicate.
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(TEST_CREDIT_CARD_3), guid);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(TEST_CREDIT_CARD_3), guid);
|
||||
|
||||
// Absolutely not a duplicate.
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(TEST_CREDIT_CARD_1), null);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(TEST_CREDIT_CARD_1), null);
|
||||
|
||||
// Subset shouldn't be treated as a duplicate.
|
||||
let record = Object.assign({}, TEST_CREDIT_CARD_3);
|
||||
delete record["cc-exp-month"];
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
|
||||
// Superset shouldn't be treated as a duplicate.
|
||||
record = Object.assign({}, TEST_CREDIT_CARD_3);
|
||||
record["cc-name"] = "John Doe";
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
|
||||
// Numbers with the same last 4 digits shouldn't be treated as a duplicate.
|
||||
record = Object.assign({}, TEST_CREDIT_CARD_3);
|
||||
@ -655,7 +660,7 @@ add_task(async function test_getDuplicateGuid() {
|
||||
// This number differs from TEST_CREDIT_CARD_3 by swapping the order of the
|
||||
// 09 and 90 adjacent digits, which is still a valid credit card number.
|
||||
record["cc-number"] = "358999378390" + last4Digits;
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
|
||||
// ... However, we treat numbers with the same last 4 digits as a duplicate if
|
||||
// the master password is enabled.
|
||||
@ -663,10 +668,10 @@ add_task(async function test_getDuplicateGuid() {
|
||||
let token = tokendb.getInternalKeyToken();
|
||||
token.reset();
|
||||
token.initPassword("password");
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(record), guid);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(record), guid);
|
||||
|
||||
// ... Even though the master password is enabled and the last 4 digits are the
|
||||
// same, an invalid credit card number should never be treated as a duplicate.
|
||||
record["cc-number"] = "************" + last4Digits;
|
||||
Assert.equal(await profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
Assert.equal(profileStorage.creditCards.getDuplicateGuid(record), null);
|
||||
});
|
||||
|
@ -79,7 +79,7 @@ add_task(async function test_getRecords() {
|
||||
|
||||
if (collection) {
|
||||
sinon.stub(collection, "getAll");
|
||||
collection.getAll.returns(Promise.resolve(expectedResult));
|
||||
collection.getAll.returns(expectedResult);
|
||||
}
|
||||
await formAutofillParent._getRecords({collectionName}, target);
|
||||
mock.verify();
|
||||
@ -98,7 +98,7 @@ add_task(async function test_getRecords_addresses() {
|
||||
let mockAddresses = [TEST_ADDRESS_1, TEST_ADDRESS_2];
|
||||
let collection = formAutofillParent.formAutofillStorage.addresses;
|
||||
sinon.stub(collection, "getAll");
|
||||
collection.getAll.returns(Promise.resolve(mockAddresses));
|
||||
collection.getAll.returns(mockAddresses);
|
||||
|
||||
let testCases = [
|
||||
{
|
||||
@ -173,14 +173,13 @@ add_task(async function test_getRecords_creditCards() {
|
||||
await formAutofillParent.init();
|
||||
await formAutofillParent.formAutofillStorage.initialize();
|
||||
let collection = formAutofillParent.formAutofillStorage.creditCards;
|
||||
let encryptedCCRecords = await Promise.all([TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2].map(async record => {
|
||||
let encryptedCCRecords = [TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2].map(record => {
|
||||
let clonedRecord = Object.assign({}, record);
|
||||
clonedRecord["cc-number"] = CreditCard.getLongMaskedNumber(record["cc-number"]);
|
||||
clonedRecord["cc-number-encrypted"] = await MasterPassword.encrypt(record["cc-number"]);
|
||||
clonedRecord["cc-number-encrypted"] = MasterPassword.encryptSync(record["cc-number"]);
|
||||
return clonedRecord;
|
||||
}));
|
||||
sinon.stub(collection, "getAll", () =>
|
||||
Promise.resolve([Object.assign({}, encryptedCCRecords[0]), Object.assign({}, encryptedCCRecords[1])]));
|
||||
});
|
||||
sinon.stub(collection, "getAll", () => [Object.assign({}, encryptedCCRecords[0]), Object.assign({}, encryptedCCRecords[1])]);
|
||||
let CreditCardsWithDecryptedNumber = [
|
||||
Object.assign({}, encryptedCCRecords[0], {"cc-number-decrypted": TEST_CREDIT_CARD_1["cc-number"]}),
|
||||
Object.assign({}, encryptedCCRecords[1], {"cc-number-decrypted": TEST_CREDIT_CARD_2["cc-number"]}),
|
||||
|
@ -246,11 +246,11 @@ add_task(async function test_migrateAddressRecords() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
await Promise.all(ADDRESS_TESTCASES.map(async testcase => {
|
||||
ADDRESS_TESTCASES.forEach(testcase => {
|
||||
info(testcase.description);
|
||||
await profileStorage.addresses._migrateRecord(testcase.record);
|
||||
profileStorage.addresses._migrateRecord(testcase.record);
|
||||
do_check_record_matches(testcase.expectedResult, testcase.record);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_migrateCreditCardRecords() {
|
||||
@ -259,9 +259,9 @@ add_task(async function test_migrateCreditCardRecords() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
await Promise.all(CREDIT_CARD_TESTCASES.map(async testcase => {
|
||||
CREDIT_CARD_TESTCASES.forEach(testcase => {
|
||||
info(testcase.description);
|
||||
await profileStorage.creditCards._migrateRecord(testcase.record);
|
||||
profileStorage.creditCards._migrateRecord(testcase.record);
|
||||
do_check_record_matches(testcase.expectedResult, testcase.record);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@ -920,25 +920,27 @@ add_task(async function test_reconcile_unknown_version() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||
|
||||
// Cross-version reconciliation isn't supported yet. See bug 1377204.
|
||||
await Assert.rejects(profileStorage.addresses.reconcile({
|
||||
"guid": "31d83d2725ec",
|
||||
"version": 2,
|
||||
"given-name": "Mark",
|
||||
"family-name": "Hammond",
|
||||
}), /Got unknown record version/);
|
||||
throws(() => {
|
||||
profileStorage.addresses.reconcile({
|
||||
"guid": "31d83d2725ec",
|
||||
"version": 2,
|
||||
"given-name": "Mark",
|
||||
"family-name": "Hammond",
|
||||
});
|
||||
}, /Got unknown record version/);
|
||||
});
|
||||
|
||||
add_task(async function test_reconcile_idempotent() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||
|
||||
let guid = "de1ba7b094fe";
|
||||
await profileStorage.addresses.add({
|
||||
profileStorage.addresses.add({
|
||||
guid,
|
||||
version: 1,
|
||||
"given-name": "Mark",
|
||||
"family-name": "Hammond",
|
||||
}, {sourceSync: true});
|
||||
await profileStorage.addresses.update(guid, {
|
||||
profileStorage.addresses.update(guid, {
|
||||
"given-name": "Skip",
|
||||
"family-name": "Hammond",
|
||||
"organization": "Mozilla",
|
||||
@ -953,8 +955,8 @@ add_task(async function test_reconcile_idempotent() {
|
||||
};
|
||||
|
||||
{
|
||||
let {forkedGUID} = await profileStorage.addresses.reconcile(remote);
|
||||
let updatedRecord = await profileStorage.addresses.get(guid, {
|
||||
let {forkedGUID} = profileStorage.addresses.reconcile(remote);
|
||||
let updatedRecord = profileStorage.addresses.get(guid, {
|
||||
rawData: true,
|
||||
});
|
||||
|
||||
@ -969,8 +971,8 @@ add_task(async function test_reconcile_idempotent() {
|
||||
}
|
||||
|
||||
{
|
||||
let {forkedGUID} = await profileStorage.addresses.reconcile(remote);
|
||||
let updatedRecord = await profileStorage.addresses.get(guid, {
|
||||
let {forkedGUID} = profileStorage.addresses.reconcile(remote);
|
||||
let updatedRecord = profileStorage.addresses.get(guid, {
|
||||
rawData: true,
|
||||
});
|
||||
|
||||
@ -999,13 +1001,13 @@ add_task(async function test_reconcile_three_way_merge() {
|
||||
for (let test of TESTCASES[collectionName]) {
|
||||
info(test.description);
|
||||
|
||||
await profileStorage[collectionName].add(test.parent, {sourceSync: true});
|
||||
profileStorage[collectionName].add(test.parent, {sourceSync: true});
|
||||
|
||||
for (let updatedRecord of test.local) {
|
||||
await profileStorage[collectionName].update(test.parent.guid, updatedRecord);
|
||||
profileStorage[collectionName].update(test.parent.guid, updatedRecord);
|
||||
}
|
||||
|
||||
let localRecord = await profileStorage[collectionName].get(test.parent.guid, {
|
||||
let localRecord = profileStorage[collectionName].get(test.parent.guid, {
|
||||
rawData: true,
|
||||
});
|
||||
|
||||
@ -1015,13 +1017,13 @@ add_task(async function test_reconcile_three_way_merge() {
|
||||
data == "reconcile" &&
|
||||
subject.wrappedJSObject.collectionName == collectionName
|
||||
);
|
||||
let {forkedGUID} = await profileStorage[collectionName].reconcile(test.remote);
|
||||
let {forkedGUID} = profileStorage[collectionName].reconcile(test.remote);
|
||||
await onReconciled;
|
||||
let reconciledRecord = await profileStorage[collectionName].get(test.parent.guid, {
|
||||
let reconciledRecord = profileStorage[collectionName].get(test.parent.guid, {
|
||||
rawData: true,
|
||||
});
|
||||
if (forkedGUID) {
|
||||
let forkedRecord = await profileStorage[collectionName].get(forkedGUID, {
|
||||
let forkedRecord = profileStorage[collectionName].get(forkedGUID, {
|
||||
rawData: true,
|
||||
});
|
||||
|
||||
|
@ -46,18 +46,15 @@ add_task(async function test_profileSavedFieldNames_update() {
|
||||
Services.prefs.clearUserPref("extensions.formautofill.addresses.enabled");
|
||||
});
|
||||
|
||||
Object.defineProperty(
|
||||
formAutofillParent.formAutofillStorage.addresses,
|
||||
"_data", {writable: true});
|
||||
|
||||
formAutofillParent.formAutofillStorage.addresses._data = [];
|
||||
sinon.stub(formAutofillParent.formAutofillStorage.addresses, "getAll");
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns([]);
|
||||
|
||||
// The set is empty if there's no profile in the store.
|
||||
formAutofillParent._updateSavedFieldNames();
|
||||
Assert.equal(Services.ppmm.initialProcessData.autofillSavedFieldNames.size, 0);
|
||||
|
||||
// 2 profiles with 4 valid fields.
|
||||
formAutofillParent.formAutofillStorage.addresses._data = [{
|
||||
let fakeStorage = [{
|
||||
guid: "test-guid-1",
|
||||
organization: "Sesame Street",
|
||||
"street-address": "123 Sesame Street.",
|
||||
@ -78,7 +75,7 @@ add_task(async function test_profileSavedFieldNames_update() {
|
||||
timeLastModified: 0,
|
||||
timesUsed: 0,
|
||||
}];
|
||||
|
||||
formAutofillParent.formAutofillStorage.addresses.getAll.returns(fakeStorage);
|
||||
formAutofillParent._updateSavedFieldNames();
|
||||
|
||||
let autofillSavedFieldNames = Services.ppmm.initialProcessData.autofillSavedFieldNames;
|
||||
|
@ -63,22 +63,22 @@ function add_storage_task(test_function) {
|
||||
add_storage_task(async function test_remove_everything(storage, records) {
|
||||
info("check simple tombstone semantics");
|
||||
|
||||
let guid = await storage.add(records[0]);
|
||||
Assert.equal((await storage.getAll()).length, 1);
|
||||
let guid = storage.add(records[0]);
|
||||
Assert.equal(storage.getAll().length, 1);
|
||||
|
||||
storage.pullSyncChanges(); // force sync metadata, which triggers tombstone behaviour.
|
||||
|
||||
storage.remove(guid);
|
||||
|
||||
await storage.add(records[1]);
|
||||
storage.add(records[1]);
|
||||
// getAll() is still 1 as we deleted the first.
|
||||
Assert.equal((await storage.getAll()).length, 1);
|
||||
Assert.equal(storage.getAll().length, 1);
|
||||
|
||||
// check we have the tombstone.
|
||||
Assert.equal((await storage.getAll({includeDeleted: true})).length, 2);
|
||||
Assert.equal(storage.getAll({includeDeleted: true}).length, 2);
|
||||
|
||||
storage.removeAll();
|
||||
|
||||
// should have deleted both the existing and deleted records.
|
||||
Assert.equal((await storage.getAll({includeDeleted: true})).length, 0);
|
||||
Assert.equal(storage.getAll({includeDeleted: true}).length, 0);
|
||||
});
|
||||
|
@ -34,8 +34,8 @@ const TEST_ADDRESS_3 = {
|
||||
// storage.get() doesn't support getting deleted items. However, this test
|
||||
// wants to do that, so rather than making .get() support that just for this
|
||||
// test, we use this helper.
|
||||
async function findGUID(storage, guid, options) {
|
||||
let all = await storage.getAll(options);
|
||||
function findGUID(storage, guid, options) {
|
||||
let all = storage.getAll(options);
|
||||
let records = all.filter(r => r.guid == guid);
|
||||
equal(records.length, 1);
|
||||
return records[0];
|
||||
@ -45,7 +45,7 @@ add_task(async function test_changeCounter() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1]);
|
||||
|
||||
let [address] = await profileStorage.addresses.getAll();
|
||||
let [address] = profileStorage.addresses.getAll();
|
||||
// new records don't get the sync metadata.
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, address.guid), -1);
|
||||
// But we can force one.
|
||||
@ -59,7 +59,7 @@ add_task(async function test_pushChanges() {
|
||||
|
||||
profileStorage.addresses.pullSyncChanges(); // force sync metadata for all items
|
||||
|
||||
let [, address] = await profileStorage.addresses.getAll();
|
||||
let [, address] = profileStorage.addresses.getAll();
|
||||
let guid = address.guid;
|
||||
let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
|
||||
@ -75,14 +75,14 @@ add_task(async function test_pushChanges() {
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "update");
|
||||
await profileStorage.addresses.update(guid, TEST_ADDRESS_3);
|
||||
profileStorage.addresses.update(guid, TEST_ADDRESS_3);
|
||||
await onChanged;
|
||||
|
||||
changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
Assert.equal(changeCounter, 2);
|
||||
|
||||
profileStorage.addresses.pushSyncChanges(changes);
|
||||
address = await profileStorage.addresses.get(guid);
|
||||
address = profileStorage.addresses.get(guid);
|
||||
changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
|
||||
// Counter should still be 1, since our sync didn't record the mid-sync change
|
||||
@ -117,13 +117,14 @@ add_task(async function test_add_sourceSync() {
|
||||
let guid = "aaaaaaaaaaaa";
|
||||
let testAddr = Object.assign({guid, version: 1}, TEST_ADDRESS_1);
|
||||
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(testAddr, {sourceSync: true}));
|
||||
|
||||
let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
equal(changeCounter, 0);
|
||||
|
||||
await Assert.rejects(profileStorage.addresses.add({guid, deleted: true}, {sourceSync: true}),
|
||||
Assert.throws(() =>
|
||||
profileStorage.addresses.add({guid, deleted: true}, {sourceSync: true}),
|
||||
/Record aaaaaaaaaaaa already exists/
|
||||
);
|
||||
});
|
||||
@ -133,20 +134,20 @@ add_task(async function test_add_tombstone_sourceSync() {
|
||||
|
||||
let guid = profileStorage.addresses._generateGUID();
|
||||
let testAddr = {guid, deleted: true};
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(testAddr, {sourceSync: true}));
|
||||
|
||||
let added = await findGUID(profileStorage.addresses, guid,
|
||||
let added = findGUID(profileStorage.addresses, guid,
|
||||
{includeDeleted: true});
|
||||
ok(added);
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, guid), 0);
|
||||
ok(added.deleted);
|
||||
|
||||
// Adding same record again shouldn't throw (or change anything)
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(testAddr, {sourceSync: true}));
|
||||
|
||||
added = await findGUID(profileStorage.addresses, guid,
|
||||
added = findGUID(profileStorage.addresses, guid,
|
||||
{includeDeleted: true});
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, guid), 0);
|
||||
ok(added.deleted);
|
||||
@ -158,18 +159,18 @@ add_task(async function test_add_resurrects_tombstones() {
|
||||
let guid = profileStorage.addresses._generateGUID();
|
||||
|
||||
// Add a tombstone.
|
||||
await profileStorage.addresses.add({guid, deleted: true});
|
||||
profileStorage.addresses.add({guid, deleted: true});
|
||||
|
||||
// You can't re-add an item with an explicit GUID.
|
||||
let resurrected = Object.assign({}, TEST_ADDRESS_1, {guid, version: 1});
|
||||
await Assert.rejects(profileStorage.addresses.add(resurrected),
|
||||
Assert.throws(() => profileStorage.addresses.add(resurrected),
|
||||
/"(guid|version)" is not a valid field/);
|
||||
|
||||
// But Sync can!
|
||||
let guid3 = await profileStorage.addresses.add(resurrected, {sourceSync: true});
|
||||
let guid3 = profileStorage.addresses.add(resurrected, {sourceSync: true});
|
||||
equal(guid, guid3);
|
||||
|
||||
let got = await profileStorage.addresses.get(guid);
|
||||
let got = profileStorage.addresses.get(guid);
|
||||
equal(got["given-name"], TEST_ADDRESS_1["given-name"]);
|
||||
});
|
||||
|
||||
@ -177,14 +178,14 @@ add_task(async function test_remove_sourceSync_localChanges() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [TEST_ADDRESS_1]);
|
||||
profileStorage.addresses.pullSyncChanges(); // force sync metadata
|
||||
|
||||
let [{guid}] = await profileStorage.addresses.getAll();
|
||||
let [{guid}] = profileStorage.addresses.getAll();
|
||||
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
// try and remove a record stored locally with local changes
|
||||
await checkingSyncChange("remove", async () =>
|
||||
await checkingSyncChange("remove", () =>
|
||||
profileStorage.addresses.remove(guid, {sourceSync: true}));
|
||||
|
||||
let record = await profileStorage.addresses.get(guid);
|
||||
let record = profileStorage.addresses.get(guid);
|
||||
ok(record);
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
});
|
||||
@ -194,10 +195,10 @@ add_task(async function test_remove_sourceSync_unknown() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, []);
|
||||
|
||||
let guid = profileStorage.addresses._generateGUID();
|
||||
await checkingSyncChange("remove", async () =>
|
||||
await checkingSyncChange("remove", () =>
|
||||
profileStorage.addresses.remove(guid, {sourceSync: true}));
|
||||
|
||||
let tombstone = await findGUID(profileStorage.addresses, guid, {
|
||||
let tombstone = findGUID(profileStorage.addresses, guid, {
|
||||
includeDeleted: true,
|
||||
});
|
||||
ok(tombstone.deleted);
|
||||
@ -211,15 +212,15 @@ add_task(async function test_remove_sourceSync_unchanged() {
|
||||
let guid = profileStorage.addresses._generateGUID();
|
||||
let addr = Object.assign({guid, version: 1}, TEST_ADDRESS_1);
|
||||
// add a record with sourceSync to guarantee changeCounter == 0
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(addr, {sourceSync: true}));
|
||||
|
||||
equal(getSyncChangeCounter(profileStorage.addresses, guid), 0);
|
||||
|
||||
await checkingSyncChange("remove", async () =>
|
||||
await checkingSyncChange("remove", () =>
|
||||
profileStorage.addresses.remove(guid, {sourceSync: true}));
|
||||
|
||||
let tombstone = await findGUID(profileStorage.addresses, guid, {
|
||||
let tombstone = findGUID(profileStorage.addresses, guid, {
|
||||
includeDeleted: true,
|
||||
});
|
||||
ok(tombstone.deleted);
|
||||
@ -230,7 +231,7 @@ add_task(async function test_pullSyncChanges() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let startAddresses = await profileStorage.addresses.getAll();
|
||||
let startAddresses = profileStorage.addresses.getAll();
|
||||
equal(startAddresses.length, 2);
|
||||
// All should start without sync metadata
|
||||
for (let {guid} of profileStorage.addresses._store.data.addresses) {
|
||||
@ -243,11 +244,11 @@ add_task(async function test_pullSyncChanges() {
|
||||
let testAddr = Object.assign({guid: addedDirectGUID, version: 1},
|
||||
TEST_ADDRESS_1, TEST_ADDRESS_3);
|
||||
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(testAddr, {sourceSync: true}));
|
||||
|
||||
let tombstoneGUID = profileStorage.addresses._generateGUID();
|
||||
await checkingSyncChange("add", async () =>
|
||||
await checkingSyncChange("add", () =>
|
||||
profileStorage.addresses.add(
|
||||
{guid: tombstoneGUID, deleted: true},
|
||||
{sourceSync: true}));
|
||||
@ -258,7 +259,7 @@ add_task(async function test_pullSyncChanges() {
|
||||
profileStorage.addresses.remove(startAddresses[0].guid);
|
||||
await onChanged;
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll({
|
||||
let addresses = profileStorage.addresses.getAll({
|
||||
includeDeleted: true,
|
||||
});
|
||||
|
||||
@ -293,9 +294,9 @@ add_task(async function test_pullPushChanges() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, []);
|
||||
let psa = profileStorage.addresses;
|
||||
|
||||
let guid1 = await psa.add(TEST_ADDRESS_1);
|
||||
let guid2 = await psa.add(TEST_ADDRESS_2);
|
||||
let guid3 = await psa.add(TEST_ADDRESS_3);
|
||||
let guid1 = psa.add(TEST_ADDRESS_1);
|
||||
let guid2 = psa.add(TEST_ADDRESS_2);
|
||||
let guid3 = psa.add(TEST_ADDRESS_3);
|
||||
|
||||
let changes = psa.pullSyncChanges();
|
||||
|
||||
@ -304,7 +305,7 @@ add_task(async function test_pullPushChanges() {
|
||||
equal(getSyncChangeCounter(psa, guid3), 1);
|
||||
|
||||
// between the pull and the push we change the second.
|
||||
await psa.update(guid2, Object.assign({}, TEST_ADDRESS_2, {country: "AU"}));
|
||||
psa.update(guid2, Object.assign({}, TEST_ADDRESS_2, {country: "AU"}));
|
||||
equal(getSyncChangeCounter(psa, guid2), 2);
|
||||
// and update the changeset to indicated we did update the first 2, but failed
|
||||
// to update the 3rd for some reason.
|
||||
@ -326,14 +327,14 @@ add_task(async function test_changeGUID() {
|
||||
|
||||
let newguid = () => profileStorage.addresses._generateGUID();
|
||||
|
||||
let guid_synced = await profileStorage.addresses.add(TEST_ADDRESS_1);
|
||||
let guid_synced = profileStorage.addresses.add(TEST_ADDRESS_1);
|
||||
|
||||
// pullSyncChanges so guid_synced is flagged as syncing.
|
||||
profileStorage.addresses.pullSyncChanges();
|
||||
|
||||
// and 2 items that haven't been synced.
|
||||
let guid_u1 = await profileStorage.addresses.add(TEST_ADDRESS_2);
|
||||
let guid_u2 = await profileStorage.addresses.add(TEST_ADDRESS_3);
|
||||
let guid_u1 = profileStorage.addresses.add(TEST_ADDRESS_2);
|
||||
let guid_u2 = profileStorage.addresses.add(TEST_ADDRESS_3);
|
||||
|
||||
// Change a non-existing guid
|
||||
Assert.throws(() => profileStorage.addresses.changeGUID(newguid(), newguid()),
|
||||
@ -350,23 +351,23 @@ add_task(async function test_changeGUID() {
|
||||
/changeGUID: old and new IDs are the same/);
|
||||
|
||||
// and one that works.
|
||||
equal((await profileStorage.addresses.getAll({includeDeleted: true})).length, 3);
|
||||
equal(profileStorage.addresses.getAll({includeDeleted: true}).length, 3);
|
||||
let targetguid = newguid();
|
||||
profileStorage.addresses.changeGUID(guid_u1, targetguid);
|
||||
equal((await profileStorage.addresses.getAll({includeDeleted: true})).length, 3);
|
||||
equal(profileStorage.addresses.getAll({includeDeleted: true}).length, 3);
|
||||
|
||||
ok(await profileStorage.addresses.get(guid_synced), "synced item still exists.");
|
||||
ok(await profileStorage.addresses.get(guid_u2), "guid we didn't touch still exists.");
|
||||
ok(await profileStorage.addresses.get(targetguid), "target guid exists.");
|
||||
ok(!await profileStorage.addresses.get(guid_u1), "old guid no longer exists.");
|
||||
ok(profileStorage.addresses.get(guid_synced), "synced item still exists.");
|
||||
ok(profileStorage.addresses.get(guid_u2), "guid we didn't touch still exists.");
|
||||
ok(profileStorage.addresses.get(targetguid), "target guid exists.");
|
||||
ok(!profileStorage.addresses.get(guid_u1), "old guid no longer exists.");
|
||||
});
|
||||
|
||||
add_task(async function test_findDuplicateGUID() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1]);
|
||||
|
||||
let [record] = await profileStorage.addresses.getAll({rawData: true});
|
||||
await Assert.rejects(profileStorage.addresses.findDuplicateGUID(record),
|
||||
let [record] = profileStorage.addresses.getAll({rawData: true});
|
||||
Assert.throws(() => profileStorage.addresses.findDuplicateGUID(record),
|
||||
/Record \w+ already exists/,
|
||||
"Should throw if the GUID already exists");
|
||||
|
||||
@ -375,14 +376,14 @@ add_task(async function test_findDuplicateGUID() {
|
||||
let timeLastModified = Date.now();
|
||||
let timeCreated = timeLastModified - 60 * 1000;
|
||||
|
||||
await profileStorage.addresses.add({
|
||||
profileStorage.addresses.add({
|
||||
guid: profileStorage.addresses._generateGUID(),
|
||||
version: 1,
|
||||
timeCreated,
|
||||
timeLastModified,
|
||||
}, {sourceSync: true});
|
||||
|
||||
strictEqual(await profileStorage.addresses.findDuplicateGUID({
|
||||
strictEqual(profileStorage.addresses.findDuplicateGUID({
|
||||
guid: profileStorage.addresses._generateGUID(),
|
||||
version: 1,
|
||||
timeCreated,
|
||||
@ -394,7 +395,7 @@ add_task(async function test_reset() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = await profileStorage.addresses.getAll();
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
// All should start without sync metadata
|
||||
for (let {guid} of addresses) {
|
||||
let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
@ -402,14 +403,14 @@ add_task(async function test_reset() {
|
||||
}
|
||||
// pullSyncChanges should create the metadata.
|
||||
profileStorage.addresses.pullSyncChanges();
|
||||
addresses = await profileStorage.addresses.getAll();
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
for (let {guid} of addresses) {
|
||||
let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
equal(changeCounter, 1);
|
||||
}
|
||||
// and resetSync should wipe it.
|
||||
profileStorage.addresses.resetSync();
|
||||
addresses = await profileStorage.addresses.getAll();
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
for (let {guid} of addresses) {
|
||||
let changeCounter = getSyncChangeCounter(profileStorage.addresses, guid);
|
||||
equal(changeCounter, -1);
|
||||
|
@ -56,39 +56,39 @@ function add_storage_task(test_function) {
|
||||
add_storage_task(async function test_simple_tombstone(storage, record) {
|
||||
info("check simple tombstone semantics");
|
||||
|
||||
let guid = await storage.add(record);
|
||||
Assert.equal((await storage.getAll()).length, 1);
|
||||
let guid = storage.add(record);
|
||||
Assert.equal(storage.getAll().length, 1);
|
||||
|
||||
storage.remove(guid);
|
||||
|
||||
// should be unable to get it normally.
|
||||
Assert.equal(await storage.get(guid), null);
|
||||
Assert.equal(storage.get(guid), null);
|
||||
// and getAll should also not return it.
|
||||
Assert.equal((await storage.getAll()).length, 0);
|
||||
Assert.equal(storage.getAll().length, 0);
|
||||
|
||||
// but getAll allows us to access deleted items - but we didn't create
|
||||
// a tombstone here, so even that will not get it.
|
||||
let all = await storage.getAll({includeDeleted: true});
|
||||
let all = storage.getAll({includeDeleted: true});
|
||||
Assert.equal(all.length, 0);
|
||||
});
|
||||
|
||||
add_storage_task(async function test_simple_synctombstone(storage, record) {
|
||||
info("check simple tombstone semantics for synced records");
|
||||
|
||||
let guid = await storage.add(record);
|
||||
Assert.equal((await storage.getAll()).length, 1);
|
||||
let guid = storage.add(record);
|
||||
Assert.equal(storage.getAll().length, 1);
|
||||
|
||||
storage.pullSyncChanges(); // force sync metadata, which triggers tombstone behaviour.
|
||||
|
||||
storage.remove(guid);
|
||||
|
||||
// should be unable to get it normally.
|
||||
Assert.equal(await storage.get(guid), null);
|
||||
Assert.equal(storage.get(guid), null);
|
||||
// and getAll should also not return it.
|
||||
Assert.equal((await storage.getAll()).length, 0);
|
||||
Assert.equal(storage.getAll().length, 0);
|
||||
|
||||
// but getAll allows us to access deleted items.
|
||||
let all = await storage.getAll({includeDeleted: true});
|
||||
let all = storage.getAll({includeDeleted: true});
|
||||
Assert.equal(all.length, 1);
|
||||
|
||||
do_check_tombstone_record(all[0]);
|
||||
@ -102,15 +102,15 @@ add_storage_task(async function test_simple_synctombstone(storage, record) {
|
||||
|
||||
add_storage_task(async function test_add_tombstone(storage, record) {
|
||||
info("Should be able to add a new tombstone");
|
||||
let guid = await storage.add({guid: "test-guid-1", deleted: true});
|
||||
let guid = storage.add({guid: "test-guid-1", deleted: true});
|
||||
|
||||
// should be unable to get it normally.
|
||||
Assert.equal(await storage.get(guid), null);
|
||||
Assert.equal(storage.get(guid), null);
|
||||
// and getAll should also not return it.
|
||||
Assert.equal((await storage.getAll()).length, 0);
|
||||
Assert.equal(storage.getAll().length, 0);
|
||||
|
||||
// but getAll allows us to access deleted items.
|
||||
let all = await storage.getAll({rawData: true, includeDeleted: true});
|
||||
let all = storage.getAll({rawData: true, includeDeleted: true});
|
||||
Assert.equal(all.length, 1);
|
||||
|
||||
do_check_tombstone_record(all[0]);
|
||||
@ -124,35 +124,35 @@ add_storage_task(async function test_add_tombstone(storage, record) {
|
||||
|
||||
add_storage_task(async function test_add_tombstone_without_guid(storage, record) {
|
||||
info("Should not be able to add a new tombstone without specifying the guid");
|
||||
await Assert.rejects(storage.add({deleted: true}),
|
||||
Assert.throws(() => { storage.add({deleted: true}); },
|
||||
/Record missing GUID/);
|
||||
Assert.equal((await storage.getAll({includeDeleted: true})).length, 0);
|
||||
Assert.equal(storage.getAll({includeDeleted: true}).length, 0);
|
||||
});
|
||||
|
||||
add_storage_task(async function test_add_tombstone_existing_guid(storage, record) {
|
||||
info("Should not be able to add a new tombstone when a record with that ID exists");
|
||||
let guid = await storage.add(record);
|
||||
await Assert.rejects(storage.add({guid, deleted: true}),
|
||||
let guid = storage.add(record);
|
||||
Assert.throws(() => { storage.add({guid, deleted: true}); },
|
||||
/a record with this GUID already exists/);
|
||||
|
||||
// same if the existing item is already a tombstone.
|
||||
await storage.add({guid: "test-guid-1", deleted: true});
|
||||
await Assert.rejects(storage.add({guid: "test-guid-1", deleted: true}),
|
||||
storage.add({guid: "test-guid-1", deleted: true});
|
||||
Assert.throws(() => { storage.add({guid: "test-guid-1", deleted: true}); },
|
||||
/a record with this GUID already exists/);
|
||||
});
|
||||
|
||||
add_storage_task(async function test_update_tombstone(storage, record) {
|
||||
info("Updating a tombstone should fail");
|
||||
let guid = await storage.add({guid: "test-guid-1", deleted: true});
|
||||
await Assert.rejects(storage.update(guid, {}), /No matching record./);
|
||||
let guid = storage.add({guid: "test-guid-1", deleted: true});
|
||||
Assert.throws(() => storage.update(guid, {}), /No matching record./);
|
||||
});
|
||||
|
||||
add_storage_task(async function test_remove_existing_tombstone(storage, record) {
|
||||
info("Removing a record that's already a tombstone should be a no-op");
|
||||
let guid = await storage.add({guid: "test-guid-1", deleted: true, timeLastModified: 1234});
|
||||
let guid = storage.add({guid: "test-guid-1", deleted: true, timeLastModified: 1234});
|
||||
|
||||
storage.remove(guid);
|
||||
let all = await storage.getAll({rawData: true, includeDeleted: true});
|
||||
let all = storage.getAll({rawData: true, includeDeleted: true});
|
||||
Assert.equal(all.length, 1);
|
||||
|
||||
do_check_tombstone_record(all[0]);
|
||||
|
@ -44,8 +44,8 @@ const TEST_PROFILE_2 = {
|
||||
country: "US",
|
||||
};
|
||||
|
||||
async function expectLocalProfiles(profileStorage, expected) {
|
||||
let profiles = await profileStorage.addresses.getAll({
|
||||
function expectLocalProfiles(profileStorage, expected) {
|
||||
let profiles = profileStorage.addresses.getAll({
|
||||
rawData: true,
|
||||
includeDeleted: true,
|
||||
});
|
||||
@ -72,7 +72,7 @@ async function expectLocalProfiles(profileStorage, expected) {
|
||||
async function setup() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||
// should always start with no profiles.
|
||||
Assert.equal((await profileStorage.addresses.getAll({includeDeleted: true})).length, 0);
|
||||
Assert.equal(profileStorage.addresses.getAll({includeDeleted: true}).length, 0);
|
||||
|
||||
Services.prefs.setCharPref("services.sync.log.logger.engine.addresses", "Trace");
|
||||
let engine = new AddressesEngine(Service);
|
||||
@ -131,12 +131,12 @@ add_task(async function test_outgoing() {
|
||||
let {profileStorage, server, collection, engine} = await setup();
|
||||
try {
|
||||
equal(engine._tracker.score, 0);
|
||||
let existingGUID = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let existingGUID = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
// And a deleted item.
|
||||
let deletedGUID = profileStorage.addresses._generateGUID();
|
||||
await profileStorage.addresses.add({guid: deletedGUID, deleted: true});
|
||||
profileStorage.addresses.add({guid: deletedGUID, deleted: true});
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
guid: existingGUID,
|
||||
},
|
||||
@ -157,7 +157,7 @@ add_task(async function test_outgoing() {
|
||||
Assert.ok(collection.wbo(existingGUID));
|
||||
Assert.ok(collection.wbo(deletedGUID));
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
guid: existingGUID,
|
||||
},
|
||||
@ -197,7 +197,7 @@ add_task(async function test_incoming_new() {
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
guid: profileID,
|
||||
}, {
|
||||
@ -220,8 +220,8 @@ add_task(async function test_incoming_new() {
|
||||
add_task(async function test_incoming_existing() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid1 = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid2 = await profileStorage.addresses.add(TEST_PROFILE_2);
|
||||
let guid1 = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid2 = profileStorage.addresses.add(TEST_PROFILE_2);
|
||||
|
||||
// an initial sync so we don't think they are locally modified.
|
||||
await engine.setLastSync(0);
|
||||
@ -245,7 +245,7 @@ add_task(async function test_incoming_existing() {
|
||||
|
||||
await engine.sync();
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
Object.assign({}, modifiedEntry1, {guid: guid1}),
|
||||
{guid: guid2, deleted: true},
|
||||
]);
|
||||
@ -257,7 +257,7 @@ add_task(async function test_incoming_existing() {
|
||||
add_task(async function test_tombstones() {
|
||||
let {profileStorage, server, collection, engine} = await setup();
|
||||
try {
|
||||
let existingGUID = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let existingGUID = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
@ -283,7 +283,7 @@ add_task(async function test_tombstones() {
|
||||
add_task(async function test_applyIncoming_both_deleted() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
@ -301,10 +301,10 @@ add_task(async function test_applyIncoming_both_deleted() {
|
||||
|
||||
await engine.sync();
|
||||
|
||||
ok(!await await profileStorage.addresses.get(guid),
|
||||
ok(!profileStorage.addresses.get(guid),
|
||||
"Should not return record for locally deleted item");
|
||||
|
||||
let localRecords = await profileStorage.addresses.getAll({
|
||||
let localRecords = profileStorage.addresses.getAll({
|
||||
includeDeleted: true,
|
||||
});
|
||||
equal(localRecords.length, 1, "Only tombstone should exist locally");
|
||||
@ -329,11 +329,11 @@ add_task(async function test_applyIncoming_nonexistent_tombstone() {
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
|
||||
ok(!await profileStorage.addresses.get(guid),
|
||||
ok(!profileStorage.addresses.get(guid),
|
||||
"Should not return record for uknown deleted item");
|
||||
let localTombstone = (await profileStorage.addresses.getAll({
|
||||
let localTombstone = profileStorage.addresses.getAll({
|
||||
includeDeleted: true,
|
||||
})).find(record => record.guid == guid);
|
||||
}).find(record => record.guid == guid);
|
||||
ok(localTombstone, "Should store tombstone for unknown item");
|
||||
} finally {
|
||||
await cleanup(server);
|
||||
@ -343,7 +343,7 @@ add_task(async function test_applyIncoming_nonexistent_tombstone() {
|
||||
add_task(async function test_applyIncoming_incoming_deleted() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
@ -358,11 +358,11 @@ add_task(async function test_applyIncoming_incoming_deleted() {
|
||||
|
||||
await engine.sync();
|
||||
|
||||
ok(!await profileStorage.addresses.get(guid), "Should delete unmodified item locally");
|
||||
ok(!profileStorage.addresses.get(guid), "Should delete unmodified item locally");
|
||||
|
||||
let localTombstone = (await profileStorage.addresses.getAll({
|
||||
let localTombstone = profileStorage.addresses.getAll({
|
||||
includeDeleted: true,
|
||||
})).find(record => record.guid == guid);
|
||||
}).find(record => record.guid == guid);
|
||||
ok(localTombstone, "Should keep local tombstone for remotely deleted item");
|
||||
strictEqual(getSyncChangeCounter(profileStorage.addresses, guid), 0,
|
||||
"Local tombstone should be marked as syncing");
|
||||
@ -374,7 +374,7 @@ add_task(async function test_applyIncoming_incoming_deleted() {
|
||||
add_task(async function test_applyIncoming_incoming_restored() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// Upload the record to the server.
|
||||
await engine.setLastSync(0);
|
||||
@ -394,7 +394,7 @@ add_task(async function test_applyIncoming_incoming_restored() {
|
||||
await engine.sync();
|
||||
|
||||
// We should replace our tombstone with the server's version.
|
||||
let localRecord = await profileStorage.addresses.get(guid);
|
||||
let localRecord = profileStorage.addresses.get(guid);
|
||||
ok(objectMatches(localRecord, {
|
||||
"given-name": "Timothy",
|
||||
"family-name": "Berners-Lee",
|
||||
@ -411,7 +411,7 @@ add_task(async function test_applyIncoming_incoming_restored() {
|
||||
add_task(async function test_applyIncoming_outgoing_restored() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// Upload the record to the server.
|
||||
await engine.setLastSync(0);
|
||||
@ -420,7 +420,7 @@ add_task(async function test_applyIncoming_outgoing_restored() {
|
||||
// Modify the local record.
|
||||
let localCopy = Object.assign({}, TEST_PROFILE_1);
|
||||
localCopy["street-address"] = "I moved!";
|
||||
await profileStorage.addresses.update(guid, localCopy);
|
||||
profileStorage.addresses.update(guid, localCopy);
|
||||
|
||||
// Replace the record with a tombstone on the server.
|
||||
let lastSync = await engine.getLastSync();
|
||||
@ -442,7 +442,7 @@ add_task(async function test_applyIncoming_outgoing_restored() {
|
||||
"street-address": "I moved!",
|
||||
}));
|
||||
|
||||
let localRecord = await profileStorage.addresses.get(guid);
|
||||
let localRecord = profileStorage.addresses.get(guid);
|
||||
ok(localRecord, "Modified record should not be deleted locally");
|
||||
} finally {
|
||||
await cleanup(server);
|
||||
@ -455,7 +455,7 @@ add_task(async function test_reconcile_both_modified_identical() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
// create a record locally.
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// and an identical record on the server.
|
||||
server.insertWBO("foo", "addresses", new ServerWBO(guid, encryptPayload({
|
||||
@ -466,7 +466,7 @@ add_task(async function test_reconcile_both_modified_identical() {
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
|
||||
await expectLocalProfiles(profileStorage, [{guid}]);
|
||||
expectLocalProfiles(profileStorage, [{guid}]);
|
||||
} finally {
|
||||
await cleanup(server);
|
||||
}
|
||||
@ -477,13 +477,13 @@ add_task(async function test_incoming_dupes() {
|
||||
try {
|
||||
// Create a profile locally, then sync to upload the new profile to the
|
||||
// server.
|
||||
let guid1 = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid1 = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
|
||||
// Create another profile locally, but don't sync it yet.
|
||||
await profileStorage.addresses.add(TEST_PROFILE_2);
|
||||
profileStorage.addresses.add(TEST_PROFILE_2);
|
||||
|
||||
// Now create two records on the server with the same contents as our local
|
||||
// profiles, but different GUIDs.
|
||||
@ -507,7 +507,7 @@ add_task(async function test_incoming_dupes() {
|
||||
// reconcile changes.
|
||||
await engine.sync();
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
// We uploaded `guid1` during the first sync. Even though its contents
|
||||
// are the same as `guid1_dupe`, we keep both.
|
||||
Object.assign({}, TEST_PROFILE_1, {guid: guid1}),
|
||||
@ -525,7 +525,7 @@ add_task(async function test_dedupe_identical_unsynced() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
// create a record locally.
|
||||
let localGuid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let localGuid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// and an identical record on the server but different GUID.
|
||||
let remoteGuid = Utils.makeGUID();
|
||||
@ -542,7 +542,7 @@ add_task(async function test_dedupe_identical_unsynced() {
|
||||
|
||||
// Should have 1 item locally with GUID changed to the remote one.
|
||||
// There's no tombstone as the original was unsynced.
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
guid: remoteGuid,
|
||||
},
|
||||
@ -556,7 +556,7 @@ add_task(async function test_dedupe_identical_synced() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
// create a record locally.
|
||||
let localGuid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let localGuid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// sync it - it will no longer be a candidate for de-duping.
|
||||
await engine.setLastSync(0);
|
||||
@ -575,7 +575,7 @@ add_task(async function test_dedupe_identical_synced() {
|
||||
await engine.sync();
|
||||
|
||||
// Should have 2 items locally, since the first was synced.
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{guid: localGuid},
|
||||
{guid: remoteGuid},
|
||||
]);
|
||||
@ -606,8 +606,8 @@ add_task(async function test_dedupe_multiple_candidates() {
|
||||
}, localRecord);
|
||||
|
||||
// We don't pass `sourceSync` so that the records are marked as NEW.
|
||||
let aGuid = await profileStorage.addresses.add(localRecord);
|
||||
let bGuid = await profileStorage.addresses.add(localRecord);
|
||||
let aGuid = profileStorage.addresses.add(localRecord);
|
||||
let bGuid = profileStorage.addresses.add(localRecord);
|
||||
|
||||
// Insert B before A.
|
||||
server.insertWBO("foo", "addresses", new ServerWBO(bGuid, encryptPayload({
|
||||
@ -622,7 +622,7 @@ add_task(async function test_dedupe_multiple_candidates() {
|
||||
await engine.setLastSync(0);
|
||||
await engine.sync();
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
"guid": aGuid,
|
||||
"given-name": "Mark",
|
||||
@ -656,7 +656,7 @@ add_task(async function test_reconcile_both_modified_conflict() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
// create a record locally.
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
// Upload the record to the server.
|
||||
await engine.setLastSync(0);
|
||||
@ -668,7 +668,7 @@ add_task(async function test_reconcile_both_modified_conflict() {
|
||||
// Change the same field locally and on the server.
|
||||
let localCopy = Object.assign({}, TEST_PROFILE_1);
|
||||
localCopy["street-address"] = "I moved!";
|
||||
await profileStorage.addresses.update(guid, localCopy);
|
||||
profileStorage.addresses.update(guid, localCopy);
|
||||
|
||||
let lastSync = await engine.getLastSync();
|
||||
let collection = server.user("foo").collection("addresses");
|
||||
@ -687,7 +687,7 @@ add_task(async function test_reconcile_both_modified_conflict() {
|
||||
let forkedPayload = serverPayloads.find(payload => payload.id != guid);
|
||||
ok(forkedPayload, "Forked record should exist on server");
|
||||
|
||||
await expectLocalProfiles(profileStorage, [
|
||||
expectLocalProfiles(profileStorage, [
|
||||
{
|
||||
guid,
|
||||
"given-name": "Timothy",
|
||||
@ -714,9 +714,9 @@ add_task(async function test_reconcile_both_modified_conflict() {
|
||||
add_task(async function test_wipe() {
|
||||
let {profileStorage, server, engine} = await setup();
|
||||
try {
|
||||
let guid = await profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
let guid = profileStorage.addresses.add(TEST_PROFILE_1);
|
||||
|
||||
await expectLocalProfiles(profileStorage, [{guid}]);
|
||||
expectLocalProfiles(profileStorage, [{guid}]);
|
||||
|
||||
let promiseObserved = promiseOneObserver("formautofill-storage-changed");
|
||||
|
||||
@ -727,7 +727,7 @@ add_task(async function test_wipe() {
|
||||
Assert.equal(subject.wrappedJSObject.collectionName, "addresses", "got the correct collection");
|
||||
Assert.equal(data, "removeAll", "a removeAll should be noted");
|
||||
|
||||
await expectLocalProfiles(profileStorage, []);
|
||||
expectLocalProfiles(profileStorage, []);
|
||||
} finally {
|
||||
await cleanup(server);
|
||||
}
|
||||
|
@ -895,15 +895,15 @@ add_task(async function test_computeAddressFields() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
for (let testcase of ADDRESS_COMPUTE_TESTCASES) {
|
||||
ADDRESS_COMPUTE_TESTCASES.forEach(testcase => {
|
||||
info("Verify testcase: " + testcase.description);
|
||||
|
||||
let guid = await profileStorage.addresses.add(testcase.address);
|
||||
let address = await profileStorage.addresses.get(guid);
|
||||
let guid = profileStorage.addresses.add(testcase.address);
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
do_check_record_matches(testcase.expectedResult, address);
|
||||
|
||||
profileStorage.addresses.remove(guid);
|
||||
}
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
@ -914,15 +914,15 @@ add_task(async function test_normalizeAddressFields() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
for (let testcase of ADDRESS_NORMALIZE_TESTCASES) {
|
||||
ADDRESS_NORMALIZE_TESTCASES.forEach(testcase => {
|
||||
info("Verify testcase: " + testcase.description);
|
||||
|
||||
let guid = await profileStorage.addresses.add(testcase.address);
|
||||
let address = await profileStorage.addresses.get(guid);
|
||||
let guid = profileStorage.addresses.add(testcase.address);
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
do_check_record_matches(testcase.expectedResult, address);
|
||||
|
||||
profileStorage.addresses.remove(guid);
|
||||
}
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
@ -933,15 +933,15 @@ add_task(async function test_computeCreditCardFields() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
for (let testcase of CREDIT_CARD_COMPUTE_TESTCASES) {
|
||||
CREDIT_CARD_COMPUTE_TESTCASES.forEach(testcase => {
|
||||
info("Verify testcase: " + testcase.description);
|
||||
|
||||
let guid = await profileStorage.creditCards.add(testcase.creditCard);
|
||||
let creditCard = await profileStorage.creditCards.get(guid);
|
||||
let guid = profileStorage.creditCards.add(testcase.creditCard);
|
||||
let creditCard = profileStorage.creditCards.get(guid);
|
||||
do_check_record_matches(testcase.expectedResult, creditCard);
|
||||
|
||||
profileStorage.creditCards.remove(guid);
|
||||
}
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
@ -952,15 +952,15 @@ add_task(async function test_normalizeCreditCardFields() {
|
||||
let profileStorage = new FormAutofillStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
for (let testcase of CREDIT_CARD_NORMALIZE_TESTCASES) {
|
||||
CREDIT_CARD_NORMALIZE_TESTCASES.forEach(testcase => {
|
||||
info("Verify testcase: " + testcase.description);
|
||||
|
||||
let guid = await profileStorage.creditCards.add(testcase.creditCard);
|
||||
let creditCard = await profileStorage.creditCards.get(guid, {rawData: true});
|
||||
let guid = profileStorage.creditCards.add(testcase.creditCard);
|
||||
let creditCard = profileStorage.creditCards.get(guid, {rawData: true});
|
||||
do_check_record_matches(testcase.expectedResult, creditCard);
|
||||
|
||||
profileStorage.creditCards.remove(guid);
|
||||
}
|
||||
});
|
||||
|
||||
await profileStorage._finalize();
|
||||
});
|
||||
|
@ -39,7 +39,7 @@ class FormAutofillBase {
|
||||
|
||||
async Create() {
|
||||
const storage = await this.getStorage();
|
||||
await storage.add(this.props);
|
||||
storage.add(this.props);
|
||||
}
|
||||
|
||||
async Find() {
|
||||
@ -52,7 +52,7 @@ class FormAutofillBase {
|
||||
async Update() {
|
||||
const storage = await this.getStorage();
|
||||
const {guid} = await this.Find();
|
||||
await storage.update(guid, this.updateProps, true);
|
||||
storage.update(guid, this.updateProps, true);
|
||||
}
|
||||
|
||||
async Remove() {
|
||||
@ -110,9 +110,8 @@ class CreditCard extends FormAutofillBase {
|
||||
|
||||
async Find() {
|
||||
const storage = await this.getStorage();
|
||||
await Promise.all(storage._data.map(
|
||||
async entry => entry["cc-number"] = await MasterPassword.decrypt(entry["cc-number-encrypted"])));
|
||||
return storage._data.find(entry => {
|
||||
entry["cc-number"] = MasterPassword.decryptSync(entry["cc-number-encrypted"]);
|
||||
return this._fields.every(field => entry[field] === this.props[field]);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user