summaryrefslogtreecommitdiffstats
path: root/browser/components/migration
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--browser/components/migration/ChromeProfileMigrator.sys.mjs3
-rw-r--r--browser/components/migration/MSMigrationUtils.sys.mjs2
-rw-r--r--browser/components/migration/MigrationUtils.sys.mjs49
-rw-r--r--browser/components/migration/SafariProfileMigrator.sys.mjs4
-rw-r--r--browser/components/migration/content/migration-wizard.mjs206
-rw-r--r--browser/components/migration/tests/browser/browser_disabled_migrator.js4
-rw-r--r--browser/components/migration/tests/browser/browser_do_migration.js2
-rw-r--r--browser/components/migration/tests/browser/browser_file_migration.js4
-rw-r--r--browser/components/migration/tests/browser/head.js2
-rw-r--r--browser/components/migration/tests/chrome/test_migration_wizard.html4
-rw-r--r--browser/components/migration/tests/unit/head_migration.js28
-rw-r--r--browser/components/migration/tests/unit/test_Chrome_bookmarks.js20
-rw-r--r--browser/components/migration/tests/unit/test_Safari_history_strange_entries.js7
13 files changed, 203 insertions, 132 deletions
diff --git a/browser/components/migration/ChromeProfileMigrator.sys.mjs b/browser/components/migration/ChromeProfileMigrator.sys.mjs
index e32417cd04..17aba35e8a 100644
--- a/browser/components/migration/ChromeProfileMigrator.sys.mjs
+++ b/browser/components/migration/ChromeProfileMigrator.sys.mjs
@@ -785,7 +785,8 @@ async function GetBookmarksResource(aProfileFolder, aBrowserKey) {
}
// Import Bookmark Favicons
- MigrationUtils.insertManyFavicons(favicons);
+ MigrationUtils.insertManyFavicons(favicons).catch(console.error);
+
if (gotErrors) {
throw new Error("The migration included errors.");
}
diff --git a/browser/components/migration/MSMigrationUtils.sys.mjs b/browser/components/migration/MSMigrationUtils.sys.mjs
index 8d9a666e66..37dd69bf10 100644
--- a/browser/components/migration/MSMigrationUtils.sys.mjs
+++ b/browser/components/migration/MSMigrationUtils.sys.mjs
@@ -381,7 +381,7 @@ Bookmarks.prototype = {
}
await MigrationUtils.insertManyBookmarksWrapper(bookmarks, aDestFolderGuid);
- MigrationUtils.insertManyFavicons(favicons);
+ MigrationUtils.insertManyFavicons(favicons).catch(console.error);
},
/**
diff --git a/browser/components/migration/MigrationUtils.sys.mjs b/browser/components/migration/MigrationUtils.sys.mjs
index cda3028cc4..90ba6a535e 100644
--- a/browser/components/migration/MigrationUtils.sys.mjs
+++ b/browser/components/migration/MigrationUtils.sys.mjs
@@ -870,36 +870,53 @@ class MigrationUtils {
* Iterates through the favicons, sniffs for a mime type,
* and uses the mime type to properly import the favicon.
*
+ * Note: You may not want to await on the returned promise, especially if by
+ * doing so there's risk of interrupting the migration of more critical
+ * data (e.g. bookmarks).
+ *
* @param {object[]} favicons
* An array of Objects with these properties:
* {Uint8Array} faviconData: The binary data of a favicon
* {nsIURI} uri: The URI of the associated page
*/
- insertManyFavicons(favicons) {
+ async insertManyFavicons(favicons) {
let sniffer = Cc["@mozilla.org/image/loader;1"].createInstance(
Ci.nsIContentSniffer
);
+
for (let faviconDataItem of favicons) {
- let mimeType = sniffer.getMIMETypeFromContent(
- null,
- faviconDataItem.faviconData,
- faviconDataItem.faviconData.length
- );
+ let dataURL;
+
+ try {
+ // getMIMETypeFromContent throws error if could not get the mime type
+ // from the data.
+ let mimeType = sniffer.getMIMETypeFromContent(
+ null,
+ faviconDataItem.faviconData,
+ faviconDataItem.faviconData.length
+ );
+
+ dataURL = await new Promise((resolve, reject) => {
+ let buffer = new Uint8ClampedArray(faviconDataItem.faviconData);
+ let blob = new Blob([buffer], { type: mimeType });
+ let reader = new FileReader();
+ reader.addEventListener("load", () => resolve(reader.result));
+ reader.addEventListener("error", reject);
+ reader.readAsDataURL(blob);
+ });
+ } catch (e) {
+ // Even if error happens for favicon, continue the process.
+ console.warn(e);
+ continue;
+ }
+
let fakeFaviconURI = Services.io.newURI(
"fake-favicon-uri:" + faviconDataItem.uri.spec
);
- lazy.PlacesUtils.favicons.replaceFaviconData(
- fakeFaviconURI,
- faviconDataItem.faviconData,
- mimeType
- );
- lazy.PlacesUtils.favicons.setAndFetchFaviconForPage(
+ lazy.PlacesUtils.favicons.setFaviconForPage(
faviconDataItem.uri,
fakeFaviconURI,
- true,
- lazy.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
- null,
- Services.scriptSecurityManager.getSystemPrincipal()
+ Services.io.newURI(dataURL)
);
}
}
diff --git a/browser/components/migration/SafariProfileMigrator.sys.mjs b/browser/components/migration/SafariProfileMigrator.sys.mjs
index c134c0869a..307edbd230 100644
--- a/browser/components/migration/SafariProfileMigrator.sys.mjs
+++ b/browser/components/migration/SafariProfileMigrator.sys.mjs
@@ -98,7 +98,7 @@ Bookmarks.prototype = {
let rows = await MigrationUtils.getRowsFromDBWithoutLocks(
dbPath,
"Safari favicons",
- `SELECT I.uuid, I.url AS favicon_url, P.url
+ `SELECT I.uuid, I.url AS favicon_url, P.url
FROM icon_info I
INNER JOIN page_url P ON I.uuid = P.uuid;`
);
@@ -253,7 +253,7 @@ Bookmarks.prototype = {
parentGuid
);
- MigrationUtils.insertManyFavicons(favicons);
+ MigrationUtils.insertManyFavicons(favicons).catch(console.error);
},
/**
diff --git a/browser/components/migration/content/migration-wizard.mjs b/browser/components/migration/content/migration-wizard.mjs
index 89872a1558..9d58fbe95f 100644
--- a/browser/components/migration/content/migration-wizard.mjs
+++ b/browser/components/migration/content/migration-wizard.mjs
@@ -333,6 +333,7 @@ export class MigrationWizard extends HTMLElement {
this.#getPermissionsButton.addEventListener("click", this);
this.#browserProfileSelector.addEventListener("click", this);
+ this.#browserProfileSelector.addEventListener("mousedown", this);
this.#resourceTypeList = shadow.querySelector("#resource-type-list");
this.#resourceTypeList.addEventListener("change", this);
@@ -1396,107 +1397,122 @@ export class MigrationWizard extends HTMLElement {
}
}
+ #handleClickEvent(event) {
+ if (
+ event.target == this.#importButton ||
+ event.target == this.#importFromFileButton
+ ) {
+ this.#doImport();
+ } else if (
+ event.target.classList.contains("cancel-close") ||
+ event.target.classList.contains("finish-button")
+ ) {
+ this.dispatchEvent(
+ new CustomEvent("MigrationWizard:Close", { bubbles: true })
+ );
+ } else if (
+ event.currentTarget == this.#browserProfileSelectorList &&
+ event.target != this.#browserProfileSelectorList
+ ) {
+ this.#onBrowserProfileSelectionChanged(event.target);
+ // If the user selected a file migration type from the selector, we'll
+ // help the user out by immediately starting the file migration flow,
+ // rather than waiting for them to click the "Select File".
+ if (
+ event.target.getAttribute("type") ==
+ MigrationWizardConstants.MIGRATOR_TYPES.FILE
+ ) {
+ this.#doImport();
+ }
+ } else if (event.target == this.#safariPermissionButton) {
+ this.#requestSafariPermissions();
+ } else if (event.currentTarget == this.#resourceSummary) {
+ this.#expandedDetails = true;
+ } else if (event.target == this.#chooseImportFromFile) {
+ this.dispatchEvent(
+ new CustomEvent("MigrationWizard:RequestState", {
+ bubbles: true,
+ detail: {
+ allowOnlyFileMigrators: true,
+ },
+ })
+ );
+ } else if (event.target == this.#safariPasswordImportSkipButton) {
+ // If the user chose to skip importing passwords from Safari, we
+ // programmatically uncheck the PASSWORDS resource type and re-request
+ // import.
+ let checkbox = this.#shadowRoot.querySelector(
+ `label[data-resource-type="${MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS}"]`
+ ).control;
+ checkbox.checked = false;
+
+ // If there are no other checked checkboxes, go back to the selection
+ // screen.
+ let checked = this.#shadowRoot.querySelectorAll(
+ `label[data-resource-type] > input:checked`
+ ).length;
+
+ if (!checked) {
+ this.requestState();
+ } else {
+ this.#doImport();
+ }
+ } else if (event.target == this.#safariPasswordImportSelectButton) {
+ this.#selectSafariPasswordFile();
+ } else if (event.target == this.#extensionsSuccessLink) {
+ this.dispatchEvent(
+ new CustomEvent("MigrationWizard:OpenAboutAddons", {
+ bubbles: true,
+ })
+ );
+ event.preventDefault();
+ } else if (event.target == this.#getPermissionsButton) {
+ this.#getPermissions();
+ }
+ }
+
+ #handleChangeEvent(event) {
+ if (event.target == this.#browserProfileSelector) {
+ this.#onBrowserProfileSelectionChanged();
+ } else if (event.target == this.#selectAllCheckbox) {
+ let checkboxes = this.#shadowRoot.querySelectorAll(
+ 'label[data-resource-type]:not([hidden]) > input[type="checkbox"]'
+ );
+ for (let checkbox of checkboxes) {
+ checkbox.checked = this.#selectAllCheckbox.checked;
+ }
+ this.#displaySelectedResources();
+ } else {
+ let checkboxes = this.#shadowRoot.querySelectorAll(
+ 'label[data-resource-type]:not([hidden]) > input[type="checkbox"]'
+ );
+
+ let allVisibleChecked = Array.from(checkboxes).every(checkbox => {
+ return checkbox.checked;
+ });
+
+ this.#selectAllCheckbox.checked = allVisibleChecked;
+ this.#displaySelectedResources();
+ }
+ }
+
handleEvent(event) {
+ if (
+ event.target == this.#browserProfileSelector &&
+ (event.type == "mousedown" ||
+ (event.type == "click" &&
+ event.mozInputSource == MouseEvent.MOZ_SOURCE_KEYBOARD))
+ ) {
+ this.#browserProfileSelectorList.toggle(event);
+ return;
+ }
switch (event.type) {
case "click": {
- if (
- event.target == this.#importButton ||
- event.target == this.#importFromFileButton
- ) {
- this.#doImport();
- } else if (
- event.target.classList.contains("cancel-close") ||
- event.target.classList.contains("finish-button")
- ) {
- this.dispatchEvent(
- new CustomEvent("MigrationWizard:Close", { bubbles: true })
- );
- } else if (event.target == this.#browserProfileSelector) {
- this.#browserProfileSelectorList.show(event);
- } else if (
- event.currentTarget == this.#browserProfileSelectorList &&
- event.target != this.#browserProfileSelectorList
- ) {
- this.#onBrowserProfileSelectionChanged(event.target);
- // If the user selected a file migration type from the selector, we'll
- // help the user out by immediately starting the file migration flow,
- // rather than waiting for them to click the "Select File".
- if (
- event.target.getAttribute("type") ==
- MigrationWizardConstants.MIGRATOR_TYPES.FILE
- ) {
- this.#doImport();
- }
- } else if (event.target == this.#safariPermissionButton) {
- this.#requestSafariPermissions();
- } else if (event.currentTarget == this.#resourceSummary) {
- this.#expandedDetails = true;
- } else if (event.target == this.#chooseImportFromFile) {
- this.dispatchEvent(
- new CustomEvent("MigrationWizard:RequestState", {
- bubbles: true,
- detail: {
- allowOnlyFileMigrators: true,
- },
- })
- );
- } else if (event.target == this.#safariPasswordImportSkipButton) {
- // If the user chose to skip importing passwords from Safari, we
- // programmatically uncheck the PASSWORDS resource type and re-request
- // import.
- let checkbox = this.#shadowRoot.querySelector(
- `label[data-resource-type="${MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS}"]`
- ).control;
- checkbox.checked = false;
-
- // If there are no other checked checkboxes, go back to the selection
- // screen.
- let checked = this.#shadowRoot.querySelectorAll(
- `label[data-resource-type] > input:checked`
- ).length;
-
- if (!checked) {
- this.requestState();
- } else {
- this.#doImport();
- }
- } else if (event.target == this.#safariPasswordImportSelectButton) {
- this.#selectSafariPasswordFile();
- } else if (event.target == this.#extensionsSuccessLink) {
- this.dispatchEvent(
- new CustomEvent("MigrationWizard:OpenAboutAddons", {
- bubbles: true,
- })
- );
- event.preventDefault();
- } else if (event.target == this.#getPermissionsButton) {
- this.#getPermissions();
- }
+ this.#handleClickEvent(event);
break;
}
case "change": {
- if (event.target == this.#browserProfileSelector) {
- this.#onBrowserProfileSelectionChanged();
- } else if (event.target == this.#selectAllCheckbox) {
- let checkboxes = this.#shadowRoot.querySelectorAll(
- 'label[data-resource-type]:not([hidden]) > input[type="checkbox"]'
- );
- for (let checkbox of checkboxes) {
- checkbox.checked = this.#selectAllCheckbox.checked;
- }
- this.#displaySelectedResources();
- } else {
- let checkboxes = this.#shadowRoot.querySelectorAll(
- 'label[data-resource-type]:not([hidden]) > input[type="checkbox"]'
- );
-
- let allVisibleChecked = Array.from(checkboxes).every(checkbox => {
- return checkbox.checked;
- });
-
- this.#selectAllCheckbox.checked = allVisibleChecked;
- this.#displaySelectedResources();
- }
+ this.#handleChangeEvent(event);
break;
}
}
diff --git a/browser/components/migration/tests/browser/browser_disabled_migrator.js b/browser/components/migration/tests/browser/browser_disabled_migrator.js
index 782666f6a6..a9a6b3083c 100644
--- a/browser/components/migration/tests/browser/browser_disabled_migrator.js
+++ b/browser/components/migration/tests/browser/browser_disabled_migrator.js
@@ -17,7 +17,7 @@ add_task(async function test_enabled_migrator() {
let wizard = dialog.querySelector("migration-wizard");
let shadow = wizard.openOrClosedShadowRoot;
let selector = shadow.querySelector("#browser-profile-selector");
- selector.click();
+ EventUtils.synthesizeMouseAtCenter(selector, {}, prefsWin);
await new Promise(resolve => {
shadow
@@ -78,7 +78,7 @@ add_task(async function test_disabling_migrator() {
let wizard = dialog.querySelector("migration-wizard");
let shadow = wizard.openOrClosedShadowRoot;
let selector = shadow.querySelector("#browser-profile-selector");
- selector.click();
+ EventUtils.synthesizeMouseAtCenter(selector, {}, prefsWin);
await new Promise(resolve => {
shadow
diff --git a/browser/components/migration/tests/browser/browser_do_migration.js b/browser/components/migration/tests/browser/browser_do_migration.js
index fab9641960..74454c0ab1 100644
--- a/browser/components/migration/tests/browser/browser_do_migration.js
+++ b/browser/components/migration/tests/browser/browser_do_migration.js
@@ -106,7 +106,7 @@ add_task(async function test_successful_migrations() {
);
let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "close");
- doneButton.click();
+ EventUtils.synthesizeMouseAtCenter(doneButton, {}, prefsWin);
await dialogClosed;
assertQuantitiesShown(wizard, [
MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.PASSWORDS,
diff --git a/browser/components/migration/tests/browser/browser_file_migration.js b/browser/components/migration/tests/browser/browser_file_migration.js
index c73dfc4456..94f4ff2908 100644
--- a/browser/components/migration/tests/browser/browser_file_migration.js
+++ b/browser/components/migration/tests/browser/browser_file_migration.js
@@ -132,7 +132,7 @@ add_task(async function test_file_migration() {
// Now select our DummyFileMigrator from the list.
let selector = shadow.querySelector("#browser-profile-selector");
- selector.click();
+ EventUtils.synthesizeMouseAtCenter(selector, {}, prefsWin);
info("Waiting for panel-list shown");
await new Promise(resolve => {
@@ -246,7 +246,7 @@ add_task(async function test_file_migration_error() {
// Now select our DummyFileMigrator from the list.
let selector = shadow.querySelector("#browser-profile-selector");
- selector.click();
+ EventUtils.synthesizeMouseAtCenter(selector, {}, prefsWin);
info("Waiting for panel-list shown");
await new Promise(resolve => {
diff --git a/browser/components/migration/tests/browser/head.js b/browser/components/migration/tests/browser/head.js
index d3d188a7e1..8824a50ee9 100644
--- a/browser/components/migration/tests/browser/head.js
+++ b/browser/components/migration/tests/browser/head.js
@@ -332,7 +332,7 @@ async function selectResourceTypesAndStartMigration(
// First, select the InternalTestingProfileMigrator browser.
let selector = shadow.querySelector("#browser-profile-selector");
- selector.click();
+ EventUtils.synthesizeMouseAtCenter(selector, {}, wizard.ownerGlobal);
await new Promise(resolve => {
shadow
diff --git a/browser/components/migration/tests/chrome/test_migration_wizard.html b/browser/components/migration/tests/chrome/test_migration_wizard.html
index cc2d8a0363..43fd3ab931 100644
--- a/browser/components/migration/tests/chrome/test_migration_wizard.html
+++ b/browser/components/migration/tests/chrome/test_migration_wizard.html
@@ -147,7 +147,7 @@
// Test that the resource type checkboxes are shown or hidden depending on
// which resourceTypes are included with the MigratorProfileInstance.
for (let migratorInstance of MIGRATOR_PROFILE_INSTANCES) {
- selector.click();
+ synthesizeMouseAtCenter(selector, {}, gWiz.ownerGlobal);
await new Promise(resolve => {
gShadowRoot
.querySelector("panel-list")
@@ -248,7 +248,7 @@
ok(isHidden(preamble), "preamble should be hidden.");
let selector = gShadowRoot.querySelector("#browser-profile-selector");
- selector.click();
+ synthesizeMouseAtCenter(selector, {}, gWiz.ownerGlobal);
await new Promise(resolve => {
let panelList = gShadowRoot.querySelector("panel-list");
if (panelList) {
diff --git a/browser/components/migration/tests/unit/head_migration.js b/browser/components/migration/tests/unit/head_migration.js
index 9900f34232..9b056e6670 100644
--- a/browser/components/migration/tests/unit/head_migration.js
+++ b/browser/components/migration/tests/unit/head_migration.js
@@ -118,6 +118,34 @@ async function assertFavicons(pageURIs) {
}
/**
+ * Check the image data for favicon of given page uri.
+ *
+ * @param {string} pageURI
+ * The page URI to which the favicon belongs.
+ * @param {Array} expectedImageData
+ * Expected image data of the favicon.
+ * @param {string} expectedMimeType
+ * Expected mime type of the favicon.
+ */
+async function assertFavicon(pageURI, expectedImageData, expectedMimeType) {
+ let result = await new Promise(resolve => {
+ PlacesUtils.favicons.getFaviconDataForPage(
+ Services.io.newURI(pageURI),
+ (faviconURI, dataLen, imageData, mimeType) => {
+ resolve({ faviconURI, dataLen, imageData, mimeType });
+ }
+ );
+ });
+ Assert.ok(!!result, `Got favicon for ${pageURI}`);
+ Assert.equal(
+ result.imageData.join(","),
+ expectedImageData.join(","),
+ "Image data is correct"
+ );
+ Assert.equal(result.mimeType, expectedMimeType, "Mime type is correct");
+}
+
+/**
* Replaces a directory service entry with a given nsIFile.
*
* @param {string} key
diff --git a/browser/components/migration/tests/unit/test_Chrome_bookmarks.js b/browser/components/migration/tests/unit/test_Chrome_bookmarks.js
index d115cda412..3c09869800 100644
--- a/browser/components/migration/tests/unit/test_Chrome_bookmarks.js
+++ b/browser/components/migration/tests/unit/test_Chrome_bookmarks.js
@@ -71,11 +71,13 @@ async function testBookmarks(migratorKey, subDirs) {
).path;
await IOUtils.copy(sourcePath, target.path);
- // Get page url for each favicon
- let faviconURIs = await MigrationUtils.getRowsFromDBWithoutLocks(
+ // Get page url and the image data for each favicon
+ let favicons = await MigrationUtils.getRowsFromDBWithoutLocks(
sourcePath,
"Chrome Bookmark Favicons",
- `select page_url from icon_mapping`
+ `SELECT page_url, image_data FROM icon_mapping
+ INNER JOIN favicon_bitmaps ON (favicon_bitmaps.icon_id = icon_mapping.icon_id)
+ `
);
target.append("Bookmarks");
@@ -171,10 +173,14 @@ async function testBookmarks(migratorKey, subDirs) {
"Telemetry reporting correct."
);
Assert.ok(observerNotified, "The observer should be notified upon migration");
- let pageUrls = Array.from(faviconURIs, f =>
- Services.io.newURI(f.getResultByName("page_url"))
- );
- await assertFavicons(pageUrls);
+
+ for (const favicon of favicons) {
+ await assertFavicon(
+ favicon.getResultByName("page_url"),
+ favicon.getResultByName("image_data"),
+ "image/png"
+ );
+ }
}
add_task(async function test_Chrome() {
diff --git a/browser/components/migration/tests/unit/test_Safari_history_strange_entries.js b/browser/components/migration/tests/unit/test_Safari_history_strange_entries.js
index 2578353e35..a22e6e1655 100644
--- a/browser/components/migration/tests/unit/test_Safari_history_strange_entries.js
+++ b/browser/components/migration/tests/unit/test_Safari_history_strange_entries.js
@@ -74,7 +74,7 @@ add_task(async function testHistoryImportStrangeEntries() {
await PlacesUtils.history.clear();
let placesQuery = new PlacesQuery();
- let emptyHistory = await placesQuery.getHistory();
+ let emptyHistory = await placesQuery.getHistory({ daysOld: Infinity });
Assert.equal(emptyHistory.size, 0, "Empty history should indeed be empty.");
const EXPECTED_MIGRATED_SITES = 10;
@@ -94,7 +94,10 @@ add_task(async function testHistoryImportStrangeEntries() {
let migrator = await MigrationUtils.getMigrator("safari");
await promiseMigration(migrator, MigrationUtils.resourceTypes.HISTORY);
- let migratedHistory = await placesQuery.getHistory({ sortBy: "site" });
+ let migratedHistory = await placesQuery.getHistory({
+ daysOld: Infinity,
+ sortBy: "site",
+ });
let siteCount = migratedHistory.size;
let visitCount = 0;
for (let [, visits] of migratedHistory) {