Backed out 2 changesets (bug 1818237) for causing mochitest/xpc failures on browser/components/migration/<...>.js CLOSED TREE

Backed out changeset a8584f57dc7c (bug 1818237)
Backed out changeset 477292e081b3 (bug 1818237)
This commit is contained in:
Sandor Molnar
2023-10-11 09:32:23 +03:00
parent db7c1a262a
commit 3a1563107d
22 changed files with 95 additions and 1202 deletions

View File

@@ -2194,7 +2194,6 @@ pref("browser.migrate.chrome.enabled", true);
pref("browser.migrate.chrome.history.limit", 2000);
pref("browser.migrate.chrome.payment_methods.enabled", true);
pref("browser.migrate.chrome.extensions.enabled", true);
pref("browser.migrate.chrome.get_permissions.enabled", true);
pref("browser.migrate.chrome-beta.enabled", true);
pref("browser.migrate.chrome-dev.enabled", true);

View File

@@ -225,21 +225,16 @@ export var ChromeMigrationUtils = {
/**
* Get the local state file content.
*
* @param {string} chromeProjectName
* The type of Chrome data we're looking for (Chromium, Canary, etc.)
* @param {string} [dataPath=undefined]
* The data path that should be used as the parent directory when getting
* the local state. If not supplied, the data path is calculated using
* getDataPath and the chromeProjectName.
* @param {string} dataPath the type of Chrome data we're looking for (Chromium, Canary, etc.)
* @returns {object} The JSON-based content.
*/
async getLocalState(chromeProjectName = "Chrome", dataPath) {
async getLocalState(dataPath = "Chrome") {
let localState = null;
try {
if (!dataPath) {
dataPath = await this.getDataPath(chromeProjectName);
}
let localStatePath = PathUtils.join(dataPath, "Local State");
let localStatePath = PathUtils.join(
await this.getDataPath(dataPath),
"Local State"
);
localState = JSON.parse(await IOUtils.readUTF8(localStatePath));
} catch (ex) {
// Don't report the error if it's just a file not existing.
@@ -269,8 +264,6 @@ export var ChromeMigrationUtils = {
* @returns {string} The path of application data directory.
*/
async getDataPath(chromeProjectName = "Chrome") {
const SNAP_REAL_HOME = "SNAP_REAL_HOME";
const SUB_DIRECTORIES = {
win: {
Brave: [
@@ -311,17 +304,7 @@ export var ChromeMigrationUtils = {
"Chrome Dev": [["Home", ".config", "google-chrome-unstable"]],
Chromium: [
["Home", ".config", "chromium"],
// If we're installed normally, we can look for Chromium installed
// as a Snap on Ubuntu Linux by looking here.
["Home", "snap", "chromium", "common", "chromium"],
// If we're installed as a Snap, "Home" is a special place that
// the Snap environment has given us, and the Chromium data is
// not within it. We want to, instead, start at the path set
// on the environment variable "SNAP_REAL_HOME".
// See: https://snapcraft.io/docs/environment-variables#heading--snap-real-home
[SNAP_REAL_HOME, "snap", "chromium", "common", "chromium"],
],
// Opera GX is not available on Linux.
// Canary is not available on Linux.
@@ -338,14 +321,7 @@ export var ChromeMigrationUtils = {
for (let subfolders of options) {
let rootDir = subfolders[0];
try {
let targetPath;
if (rootDir == SNAP_REAL_HOME) {
targetPath = Services.env.get("SNAP_REAL_HOME");
} else {
targetPath = Services.dirsvc.get(rootDir, Ci.nsIFile).path;
}
let targetPath = Services.dirsvc.get(rootDir, Ci.nsIFile).path;
targetPath = PathUtils.join(targetPath, ...subfolders.slice(1));
if (await IOUtils.exists(targetPath)) {
return targetPath;

View File

@@ -78,23 +78,6 @@ function convertBookmarks(items, bookmarkURLAccumulator, errorAccumulator) {
* migrators for browsers that are variants of Chrome.
*/
export class ChromeProfileMigrator extends MigratorBase {
/**
* On Ubuntu Linux, when the browser is installed as a Snap package,
* we must request permission to read data from other browsers. We
* make that request by opening up a native file picker in folder
* selection mode and instructing the user to navigate to the folder
* that the other browser's user data resides in.
*
* For Snap packages, this gives the browser read access - but it does
* so through a temporary symlink that does not match the original user
* data path. Effectively, the user data directory is remapped to a
* temporary location on the file system. We record these remaps here,
* keyed on the original data directory.
*
* @type {Map<string, string>}
*/
#dataPathRemappings = new Map();
static get key() {
return "chrome";
}
@@ -111,101 +94,13 @@ export class ChromeProfileMigrator extends MigratorBase {
return "Chrome";
}
async hasPermissions() {
let dataPath = await this._getChromeUserDataPathIfExists();
if (!dataPath) {
return true;
}
let localStatePath = PathUtils.join(dataPath, "Local State");
try {
// Read one byte since on snap we can check existence even without being able
// to read the file.
await IOUtils.read(localStatePath, { maxBytes: 1 });
return true;
} catch (ex) {
console.error("No permissions for local state folder.");
}
return false;
}
async getPermissions(win) {
// Get the original path to the user data and ignore any existing remapping.
// This allows us to set a new remapping if the user navigates the platforms
// filepicker to a different directory on a second permission request attempt.
let originalDataPath = await this._getChromeUserDataPathIfExists(
true /* noRemapping */
);
// Keep prompting the user until they pick something that grants us access
// to Chrome's local state directory.
while (!(await this.hasPermissions())) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(win, "", Ci.nsIFilePicker.modeGetFolder);
fp.filterIndex = 1;
// Now wait for the filepicker to open and close. If the user picks
// the local state folder, the OS should grant us read access to everything
// inside, so we don't need to check or do anything else with what's
// returned by the filepicker.
let result = await new Promise(resolve => fp.open(resolve));
// Bail if the user cancels the dialog:
if (result == Ci.nsIFilePicker.returnCancel) {
return false;
}
if (fp.fileURL.filePath != originalDataPath) {
this.#dataPathRemappings.set(originalDataPath, fp.fileURL.filePath);
}
}
return true;
}
async canGetPermissions() {
if (
!Services.prefs.getBoolPref(
"browser.migrate.chrome.get_permissions.enabled"
)
) {
return false;
}
if (await MigrationUtils.canGetPermissionsOnPlatform()) {
let dataPath = await this._getChromeUserDataPathIfExists();
if (dataPath) {
let localStatePath = PathUtils.join(dataPath, "Local State");
if (await IOUtils.exists(localStatePath)) {
return dataPath;
}
}
}
return false;
}
_keychainServiceName = "Chrome Safe Storage";
_keychainAccountName = "Chrome";
/**
* Returns a Promise that resolves to the data path containing the
* Local State and profile directories for this browser.
*
* @param {boolean} [noRemapping=false]
* Set to true to bypass any remapping that might have occurred on
* platforms where the data path changes once permission has been
* granted.
* @returns {Promise<string>}
*/
async _getChromeUserDataPathIfExists(noRemapping = false) {
async _getChromeUserDataPathIfExists() {
if (this._chromeUserDataPath) {
// Skip looking up any remapping if `noRemapping` was passed. This is
// helpful if the caller needs create a new remapping and overwrite
// an old remapping, as "real" user data path is used as a key for
// the remapping.
if (noRemapping) {
return this._chromeUserDataPath;
}
let remappedPath = this.#dataPathRemappings.get(this._chromeUserDataPath);
return remappedPath || this._chromeUserDataPath;
return this._chromeUserDataPath;
}
let path = await lazy.ChromeMigrationUtils.getDataPath(
this._chromeUserDataPathSuffix
@@ -220,10 +115,6 @@ export class ChromeProfileMigrator extends MigratorBase {
}
async getResources(aProfile) {
if (!(await this.hasPermissions())) {
return [];
}
let chromeUserDataPath = await this._getChromeUserDataPathIfExists();
if (chromeUserDataPath) {
let profileFolder = chromeUserDataPath;
@@ -301,8 +192,7 @@ export class ChromeProfileMigrator extends MigratorBase {
let profiles = [];
try {
localState = await lazy.ChromeMigrationUtils.getLocalState(
this._chromeUserDataPathSuffix,
chromeUserDataPath
this._chromeUserDataPathSuffix
);
let info_cache = localState.profile.info_cache;
for (let profileFolderName in info_cache) {
@@ -316,14 +206,6 @@ export class ChromeProfileMigrator extends MigratorBase {
if (localState || e.name != "NotFoundError") {
console.error("Error detecting Chrome profiles: ", e);
}
// If we didn't have permission to read the local state, return the
// empty array. The user might have the opportunity to request
// permission using `hasPermission` and `getPermission`.
if (e.name == "NotAllowedError") {
return [];
}
// If we weren't able to detect any profiles above, fallback to the Default profile.
let defaultProfilePath = PathUtils.join(chromeUserDataPath, "Default");
if (await IOUtils.exists(defaultProfilePath)) {
@@ -358,16 +240,6 @@ export class ChromeProfileMigrator extends MigratorBase {
return null;
}
let tempFilePath = null;
if (MigrationUtils.IS_LINUX_SNAP_PACKAGE) {
tempFilePath = await IOUtils.createUniqueFile(
PathUtils.tempDir,
"Login Data"
);
await IOUtils.copy(loginPath, tempFilePath);
loginPath = tempFilePath;
}
let {
_chromeUserDataPathSuffix,
_keychainServiceName,
@@ -397,15 +269,10 @@ export class ChromeProfileMigrator extends MigratorBase {
`SELECT origin_url, action_url, username_element, username_value,
password_element, password_value, signon_realm, scheme, date_created,
times_used FROM logins WHERE blacklisted_by_user = 0`
)
.catch(ex => {
console.error(ex);
aCallback(false);
})
.finally(() => {
return tempFilePath && IOUtils.remove(tempFilePath);
});
).catch(ex => {
console.error(ex);
aCallback(false);
});
// If the promise was rejected we will have already called aCallback,
// so we can just return here.
if (!rows) {
@@ -540,27 +407,13 @@ export class ChromeProfileMigrator extends MigratorBase {
return null;
}
let tempFilePath = null;
if (MigrationUtils.IS_LINUX_SNAP_PACKAGE) {
tempFilePath = await IOUtils.createUniqueFile(
PathUtils.tempDir,
"Web Data"
);
await IOUtils.copy(paymentMethodsPath, tempFilePath);
paymentMethodsPath = tempFilePath;
}
let rows = await MigrationUtils.getRowsFromDBWithoutLocks(
paymentMethodsPath,
"Chrome Credit Cards",
"SELECT name_on_card, card_number_encrypted, expiration_month, expiration_year FROM credit_cards"
)
.catch(ex => {
console.error(ex);
})
.finally(() => {
return tempFilePath && IOUtils.remove(tempFilePath);
});
).catch(ex => {
console.error(ex);
});
if (!rows?.length) {
return null;
@@ -654,17 +507,6 @@ async function GetBookmarksResource(aProfileFolder, aBrowserKey) {
if (!(await IOUtils.exists(bookmarksPath))) {
return null;
}
let tempFilePath = null;
if (MigrationUtils.IS_LINUX_SNAP_PACKAGE) {
tempFilePath = await IOUtils.createUniqueFile(
PathUtils.tempDir,
"Favicons"
);
await IOUtils.copy(faviconsPath, tempFilePath);
faviconsPath = tempFilePath;
}
// check to read JSON bookmarks structure and see if any bookmarks exist else return null
// Parse Chrome bookmark file that is JSON format
let bookmarkJSON = await IOUtils.readJSON(bookmarksPath);
@@ -696,12 +538,7 @@ async function GetBookmarksResource(aProfileFolder, aBrowserKey) {
);
} catch (ex) {
console.error(ex);
} finally {
if (tempFilePath) {
await IOUtils.remove(tempFilePath);
}
}
// Create Hashmap for favicons
let faviconMap = new Map();
for (let faviconRow of faviconRows) {
@@ -801,14 +638,6 @@ async function GetHistoryResource(aProfileFolder) {
if (!(await IOUtils.exists(historyPath))) {
return null;
}
let tempFilePath = null;
if (MigrationUtils.IS_LINUX_SNAP_PACKAGE) {
tempFilePath = await IOUtils.createUniqueFile(PathUtils.tempDir, "History");
await IOUtils.copy(historyPath, tempFilePath);
historyPath = tempFilePath;
}
let countQuery = "SELECT COUNT(*) FROM urls WHERE hidden = 0";
let countRows = await MigrationUtils.getRowsFromDBWithoutLocks(
@@ -839,19 +668,11 @@ async function GetHistoryResource(aProfileFolder) {
query += " ORDER BY last_visit_time DESC LIMIT " + LIMIT;
}
let rows;
try {
rows = await MigrationUtils.getRowsFromDBWithoutLocks(
historyPath,
"Chrome history",
query
);
} finally {
if (tempFilePath) {
await IOUtils.remove(tempFilePath);
}
}
let rows = await MigrationUtils.getRowsFromDBWithoutLocks(
historyPath,
"Chrome history",
query
);
let pageInfos = [];
let fallbackVisitDate = new Date();
for (let row of rows) {
@@ -903,16 +724,6 @@ async function GetFormdataResource(aProfileFolder) {
}
let countQuery = "SELECT COUNT(*) FROM autofill";
let tempFilePath = null;
if (MigrationUtils.IS_LINUX_SNAP_PACKAGE) {
tempFilePath = await IOUtils.createUniqueFile(
PathUtils.tempDir,
"Web Data"
);
await IOUtils.copy(formdataPath, tempFilePath);
formdataPath = tempFilePath;
}
let countRows = await MigrationUtils.getRowsFromDBWithoutLocks(
formdataPath,
"Chrome formdata",
@@ -927,20 +738,11 @@ async function GetFormdataResource(aProfileFolder) {
async migrate(aCallback) {
let query =
"SELECT name, value, count, date_created, date_last_used FROM autofill";
let rows;
try {
rows = await MigrationUtils.getRowsFromDBWithoutLocks(
formdataPath,
"Chrome formdata",
query
);
} finally {
if (tempFilePath) {
await IOUtils.remove(tempFilePath);
}
}
let rows = await MigrationUtils.getRowsFromDBWithoutLocks(
formdataPath,
"Chrome formdata",
query
);
let addOps = [];
for (let row of rows) {
try {

View File

@@ -18,15 +18,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
"chrome://browser/content/migration/migration-wizard-constants.mjs",
});
ChromeUtils.defineLazyGetter(
lazy,
"gCanGetPermissionsOnPlatformPromise",
() => {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
return fp.isModeSupported(Ci.nsIFilePicker.modeGetFolder);
}
);
var gMigrators = null;
var gFileMigrators = null;
var gProfileStartup = null;
@@ -155,7 +146,6 @@ class MigrationUtils {
"MigrationWizard:RequestSafariPermissions": { wantUntrusted: true },
"MigrationWizard:SelectSafariPasswordFile": { wantUntrusted: true },
"MigrationWizard:OpenAboutAddons": { wantUntrusted: true },
"MigrationWizard:GetPermissions": { wantUntrusted: true },
},
},
@@ -170,20 +160,6 @@ class MigrationUtils {
"about:firefoxview-next",
],
});
XPCOMUtils.defineLazyGetter(this, "IS_LINUX_SNAP_PACKAGE", () => {
if (
AppConstants.platform != "linux" ||
!Cc["@mozilla.org/gio-service;1"]
) {
return false;
}
let gIOSvc = Cc["@mozilla.org/gio-service;1"].getService(
Ci.nsIGIOService
);
return gIOSvc.isRunningUnderSnap;
});
}
resourceTypes = Object.freeze({
@@ -425,13 +401,18 @@ class MigrationUtils {
/**
* Returns the migrator for the given source, if any data is available
* for this source, or if permissions are required in order to read
* data from this source. Returns null otherwise.
* for this source, or null otherwise.
*
* If null is returned, either no data can be imported for the given migrator,
* or aMigratorKey is invalid (e.g. ie on mac, or mosaic everywhere). This
* method should be used rather than direct getService for future compatibility
* (see bug 718280).
*
* @param {string} aKey
* Internal name of the migration source. See `availableMigratorKeys`
* for supported values by OS.
* @returns {Promise<MigratorBase|null>}
*
* @returns {MigratorBase}
* A profile migrator implementing nsIBrowserProfileMigrator, if it can
* import any data, null otherwise.
*/
@@ -443,18 +424,7 @@ class MigrationUtils {
}
try {
if (!migrator) {
return null;
}
if (
(await migrator.isSourceAvailable()) ||
(!(await migrator.hasPermissions()) && migrator.canGetPermissions())
) {
return migrator;
}
return null;
return migrator && (await migrator.isSourceAvailable()) ? migrator : null;
} catch (ex) {
console.error(ex);
return null;
@@ -1242,18 +1212,6 @@ class MigrationUtils {
get HISTORY_MAX_AGE_IN_MILLISECONDS() {
return this.HISTORY_MAX_AGE_IN_DAYS * 24 * 60 * 60 * 1000;
}
/**
* Determines whether or not the underlying platform supports creating
* native file pickers that can do folder selection, which is a
* pre-requisite for getting read-access permissions for data from other
* browsers that we can import from.
*
* @returns {Promise<boolean>}
*/
canGetPermissionsOnPlatform() {
return lazy.gCanGetPermissionsOnPlatformPromise;
}
}
const MigrationUtilsSingleton = new MigrationUtils();

View File

@@ -82,7 +82,18 @@ export class MigrationWizardChild extends JSWindowActorChild {
switch (event.type) {
case "MigrationWizard:RequestState": {
this.#sendTelemetryEvent("opened");
await this.#requestState(event.detail?.allowOnlyFileMigrators);
this.setComponentState({
page: MigrationWizardConstants.PAGES.LOADING,
});
await this.#populateMigrators(event.detail?.allowOnlyFileMigrators);
this.#wizardEl.dispatchEvent(
new this.contentWindow.CustomEvent("MigrationWizard:Ready", {
bubbles: true,
})
);
break;
}
@@ -142,33 +153,9 @@ export class MigrationWizardChild extends JSWindowActorChild {
this.sendAsyncMessage("OpenAboutAddons");
break;
}
case "MigrationWizard:GetPermissions": {
let success = await this.sendQuery("GetPermissions", {
key: event.detail.key,
});
if (success) {
await this.#requestState(true /* allowOnlyFileMigrators */);
}
break;
}
}
}
async #requestState(allowOnlyFileMigrators) {
this.setComponentState({
page: MigrationWizardConstants.PAGES.LOADING,
});
await this.#populateMigrators(allowOnlyFileMigrators);
this.#wizardEl.dispatchEvent(
new this.contentWindow.CustomEvent("MigrationWizard:Ready", {
bubbles: true,
})
);
}
/**
* Sends a message to the parent actor to record Event Telemetry.
*

View File

@@ -167,11 +167,6 @@ export class MigrationWizardParent extends JSWindowActorParent {
this.#openAboutAddons(browser);
break;
}
case "GetPermissions": {
let migrator = await MigrationUtils.getMigrator(message.data.key);
return migrator.getPermissions(this.browsingContext.topChromeWindow);
}
}
return null;
@@ -584,21 +579,6 @@ export class MigrationWizardParent extends JSWindowActorParent {
return null;
}
if (!(await migrator.hasPermissions())) {
// If we're unable to get permissions for this migrator, then we
// just don't bother showing it.
let permissionsPath = await migrator.canGetPermissions();
if (!permissionsPath) {
return null;
}
return this.#serializeMigratorAndProfile(
migrator,
null,
false /* hasPermissions */,
permissionsPath
);
}
let sourceProfiles = await migrator.getSourceProfiles();
if (Array.isArray(sourceProfiles)) {
if (!sourceProfiles.length) {
@@ -644,23 +624,9 @@ export class MigrationWizardParent extends JSWindowActorParent {
* The user profile object representing the profile to get information
* about. This object is usually gotten by calling getSourceProfiles on
* the migrator.
* @param {boolean} [hasPermissions=true]
* Whether or not the migrator has permission to read the data for the
* other browser. It is expected that the caller will have already
* computed this by calling hasPermissions() on the migrator, and
* passing the result into this method. This is true by default.
* @param {string} [permissionsPath=undefined]
* The path that the selected migrator needs read access to in order to
* do a migration, in the event that hasPermissions is false. This is
* undefined if hasPermissions is true.
* @returns {Promise<MigratorProfileInstance>}
*/
async #serializeMigratorAndProfile(
migrator,
profileObj,
hasPermissions = true,
permissionsPath
) {
async #serializeMigratorAndProfile(migrator, profileObj) {
let [profileMigrationData, lastModifiedDate] = await Promise.all([
migrator.getMigrateData(profileObj),
migrator.getLastUsedDate(),
@@ -668,27 +634,25 @@ export class MigrationWizardParent extends JSWindowActorParent {
let availableResourceTypes = [];
if (hasPermissions) {
for (let resourceType in MigrationUtils.resourceTypes) {
// Normally, we check each possible resourceType to see if we have one or
// more corresponding resourceTypes in profileMigrationData. The exception
// is for Safari, where the migrator does not expose a PASSWORDS resource
// type, but we allow the user to express that they'd like to import
// passwords from it anyways. This is because the Safari migration flow is
// special, and allows the user to import passwords from a file exported
// from Safari.
if (
profileMigrationData & MigrationUtils.resourceTypes[resourceType] ||
(migrator.constructor.key == lazy.SafariProfileMigrator?.key &&
MigrationUtils.resourceTypes[resourceType] ==
MigrationUtils.resourceTypes.PASSWORDS &&
Services.prefs.getBoolPref(
"signon.management.page.fileImport.enabled",
false
))
) {
availableResourceTypes.push(resourceType);
}
for (let resourceType in MigrationUtils.resourceTypes) {
// Normally, we check each possible resourceType to see if we have one or
// more corresponding resourceTypes in profileMigrationData. The exception
// is for Safari, where the migrator does not expose a PASSWORDS resource
// type, but we allow the user to express that they'd like to import
// passwords from it anyways. This is because the Safari migration flow is
// special, and allows the user to import passwords from a file exported
// from Safari.
if (
profileMigrationData & MigrationUtils.resourceTypes[resourceType] ||
(migrator.constructor.key == lazy.SafariProfileMigrator?.key &&
MigrationUtils.resourceTypes[resourceType] ==
MigrationUtils.resourceTypes.PASSWORDS &&
Services.prefs.getBoolPref(
"signon.management.page.fileImport.enabled",
false
))
) {
availableResourceTypes.push(resourceType);
}
}
@@ -713,8 +677,6 @@ export class MigrationWizardParent extends JSWindowActorParent {
resourceTypes: availableResourceTypes,
profile: profileObj,
lastModifiedDate,
hasPermissions,
permissionsPath,
};
}

View File

@@ -235,13 +235,6 @@ export class MigratorBase {
return Promise.resolve(true);
}
/**
* @returns {Promise<boolean|string>}
*/
async canGetPermissions() {
return Promise.resolve(false);
}
/**
* This method returns a number that is the bitwise OR of all resource
* types that are available in aProfile. See MigrationUtils.resourceTypes

View File

@@ -644,16 +644,6 @@ export class SafariProfileMigrator extends MigratorBase {
return true;
}
async canGetPermissions() {
if (await MigrationUtils.canGetPermissionsOnPlatform()) {
const profileDir = FileUtils.getDir("ULibDir", ["Safari"]);
if (await IOUtils.exists(profileDir.path)) {
return profileDir.path;
}
}
return false;
}
get mainPreferencesPropertyList() {
if (this._mainPreferencesPropertyList === undefined) {
let file = FileUtils.getDir("UsrPrfs", []);

View File

@@ -23,7 +23,6 @@ export class MigrationWizard extends HTMLElement {
#importButton = null;
#importFromFileButton = null;
#chooseImportFromFile = null;
#getPermissionsButton = null;
#safariPermissionButton = null;
#safariPasswordImportSkipButton = null;
#safariPasswordImportSelectButton = null;
@@ -64,22 +63,8 @@ export class MigrationWizard extends HTMLElement {
<span class="error-icon" role="img"></span>
<div data-l10n-id="migration-wizard-import-browser-no-resources"></div>
</div>
<div class="no-permissions-message">
<p data-l10n-id="migration-no-permissions-message">
</p>
<p data-l10n-id="migration-no-permissions-instructions">
</p>
<ol>
<li data-l10n-id="migration-no-permissions-instructions-step1"></li>
<li class="migration-no-permissions-instructions-step2" data-l10n-id="migration-no-permissions-instructions-step2" data-l10n-args='{"permissionsPath": "" }'>
<code></code>
</li>
</ol>
</div>
<div data-l10n-id="migration-wizard-selection-list" class="resource-selection-preamble deemphasized-text hide-on-error"></div>
<details class="resource-selection-details hide-on-error">
<div data-l10n-id="migration-wizard-selection-list" class="resource-selection-preamble deemphasized-text hide-on-no-resources-error"></div>
<details class="resource-selection-details hide-on-no-resources-error">
<summary id="resource-selection-summary">
<div class="selected-data-header" data-l10n-id="migration-all-available-data-label"></div>
<div class="selected-data deemphasized-text">&nbsp;</div>
@@ -119,7 +104,6 @@ export class MigrationWizard extends HTMLElement {
<button class="cancel-close" data-l10n-id="migration-cancel-button-label"></button>
<button id="import-from-file" class="primary" data-l10n-id="migration-import-from-file-button-label"></button>
<button id="import" class="primary" data-l10n-id="migration-import-button-label"></button>
<button id="get-permissions" class="primary" data-l10n-id="migration-continue-button-label"></button>
</moz-button-group>
</div>
@@ -328,8 +312,6 @@ export class MigrationWizard extends HTMLElement {
"#choose-import-from-file"
);
this.#chooseImportFromFile.addEventListener("click", this);
this.#getPermissionsButton = shadow.querySelector("#get-permissions");
this.#getPermissionsButton.addEventListener("click", this);
this.#browserProfileSelector.addEventListener("click", this);
this.#resourceTypeList = shadow.querySelector("#resource-type-list");
@@ -518,33 +500,10 @@ export class MigrationWizard extends HTMLElement {
"div[name='page-selection']"
);
selectionPage.setAttribute("migrator-type", panelItem.getAttribute("type"));
// Safari currently has a special flow for requesting permissions that
// occurs _after_ resource selection, so we don't show this message
// for that migrator.
let showNoPermissionsMessage =
panelItem.getAttribute("type") ==
MigrationWizardConstants.MIGRATOR_TYPES.BROWSER &&
!panelItem.hasPermissions &&
panelItem.getAttribute("key") != "safari";
selectionPage.toggleAttribute("no-permissions", showNoPermissionsMessage);
if (showNoPermissionsMessage) {
let step2 = selectionPage.querySelector(
".migration-no-permissions-instructions-step2"
);
step2.setAttribute(
"data-l10n-args",
JSON.stringify({ permissionsPath: panelItem.permissionsPath })
);
}
selectionPage.toggleAttribute(
"no-resources",
panelItem.getAttribute("type") ==
MigrationWizardConstants.MIGRATOR_TYPES.BROWSER &&
!resourceTypes.length &&
panelItem.hasPermissions
MigrationWizardConstants.MIGRATOR_TYPES.BROWSER && !resourceTypes.length
);
}
@@ -595,7 +554,6 @@ export class MigrationWizard extends HTMLElement {
opt.displayName = migrator.displayName;
opt.resourceTypes = migrator.resourceTypes;
opt.hasPermissions = migrator.hasPermissions;
opt.permissionsPath = migrator.permissionsPath;
opt.brandImage = migrator.brandImage;
let button = opt.shadowRoot.querySelector("button");
@@ -1135,20 +1093,6 @@ export class MigrationWizard extends HTMLElement {
);
}
/**
* Sends a request to get read permissions for the data associated
* with the selected browser.
*/
#getPermissions() {
let migrationEventDetail = this.#gatherMigrationEventDetails();
this.dispatchEvent(
new CustomEvent("MigrationWizard:GetPermissions", {
bubbles: true,
detail: migrationEventDetail,
})
);
}
/**
* Changes selected-data-header text and selected-data text based on
* how many resources are checked
@@ -1324,8 +1268,6 @@ export class MigrationWizard extends HTMLElement {
})
);
event.preventDefault();
} else if (event.target == this.#getPermissionsButton) {
this.#getPermissions();
}
break;
}

View File

@@ -37,8 +37,6 @@ support-files = ["dummy_file.csv"]
["browser_only_file_migrators.js"]
["browser_permissions.js"]
["browser_safari_passwords.js"]
run-if = ["os == 'mac'"]

View File

@@ -71,10 +71,6 @@ add_task(async function test_discovered_migrators_keyed_scalar() {
{ id: "chrome-test-2", name: "Chrome test profile 2" },
]);
sandbox
.stub(ChromeProfileMigrator.prototype, "hasPermissions")
.resolves(true);
// We also need to ensure that the ChromeProfileMigrator actually has
// some resources to migrate, otherwise it won't get listed.
sandbox

View File

@@ -1,144 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [["browser.migrate.chrome.get_permissions.enabled", true]],
});
});
/**
* Tests that the migration wizard can request permission from
* the user to read from other browser data directories when
* explicit permission needs to be granted.
*
* This can occur when, for example, Firefox is installed as a
* Snap on Ubuntu Linux. In this state, Firefox does not have
* direct read access to other browser's data directories (although)
* it can tell if they exist. For Chromium-based browsers, this
* means we cannot tell what profiles nor resources are available
* for Chromium-based browsers without read permissions.
*
* Note that the Safari migrator is not tested here, as it has
* its own special permission flow. This is because we can
* determine what resources Safari has before requiring permissions,
* and (as of this writing) Safari does not support multiple
* user profiles.
*/
add_task(async function test_permissions() {
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
sandbox
.stub(InternalTestingProfileMigrator.prototype, "canGetPermissions")
.resolves("/some/path");
let hasPermissionsStub = sandbox
.stub(InternalTestingProfileMigrator.prototype, "hasPermissions")
.resolves(false);
let testingMigrator = await MigrationUtils.getMigrator(
InternalTestingProfileMigrator.key
);
Assert.ok(
testingMigrator,
"Got migrator, even though we don't yet have permission to read its resources."
);
sandbox.stub(testingMigrator, "getPermissions").callsFake(async () => {
testingMigrator.flushResourceCache();
hasPermissionsStub.resolves(true);
return Promise.resolve(true);
});
let getResourcesStub = sandbox
.stub(testingMigrator, "getResources")
.resolves([]);
let migration = waitForTestMigration(
[MigrationUtils.resourceTypes.BOOKMARKS],
[MigrationUtils.resourceTypes.BOOKMARKS],
InternalTestingProfileMigrator.testProfile
);
await withMigrationWizardDialog(async prefsWin => {
let dialogBody = prefsWin.document.body;
let wizard = dialogBody.querySelector("migration-wizard");
let shadow = wizard.openOrClosedShadowRoot;
let panelItem = shadow.querySelector(
`panel-item[key="${InternalTestingProfileMigrator.key}"]`
);
panelItem.click();
let resourceList = shadow.querySelector(".resource-selection-details");
Assert.ok(
BrowserTestUtils.is_hidden(resourceList),
"Resources list is hidden."
);
let importButton = shadow.querySelector("#import");
Assert.ok(
BrowserTestUtils.is_hidden(importButton),
"Import button hidden."
);
let noPermissionsMessage = shadow.querySelector(".no-permissions-message");
Assert.ok(
BrowserTestUtils.is_visible(noPermissionsMessage),
"No permissions message shown."
);
let getPermissionButton = shadow.querySelector("#get-permissions");
Assert.ok(
BrowserTestUtils.is_visible(getPermissionButton),
"Get permissions button shown."
);
// Now put the permissions functions back into their default
// state - which is the "permission granted" state.
getResourcesStub.restore();
hasPermissionsStub.restore();
let refreshDone = BrowserTestUtils.waitForEvent(
wizard,
"MigrationWizard:Ready"
);
getPermissionButton.click();
await refreshDone;
Assert.ok(true, "Refreshed migrator list.");
let wizardDone = BrowserTestUtils.waitForEvent(
wizard,
"MigrationWizard:DoneMigration"
);
selectResourceTypesAndStartMigration(wizard, [
MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS,
]);
await migration;
await wizardDone;
assertQuantitiesShown(wizard, [
MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS,
]);
let dialog = prefsWin.document.querySelector("#migrationWizardDialog");
let doneButton = shadow.querySelector(
"div[name='page-progress'] .done-button"
);
await new Promise(resolve => prefsWin.requestAnimationFrame(resolve));
Assert.equal(
shadow.activeElement,
doneButton,
"Done button should be focused."
);
let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "close");
doneButton.click();
await dialogClosed;
});
});

View File

@@ -28,35 +28,34 @@ add_task(async function test_safari_permissions() {
sandbox.restore();
});
let hasPermissionsStub = sandbox
let safariMigrator = new SafariProfileMigrator();
sandbox.stub(MigrationUtils, "getMigrator").resolves(safariMigrator);
sandbox
.stub(SafariProfileMigrator.prototype, "hasPermissions")
.resolves(false);
.onFirstCall()
.resolves(false)
.onSecondCall()
.resolves(true);
let safariMigrator = await MigrationUtils.getMigrator(
SafariProfileMigrator.key
);
Assert.ok(
safariMigrator,
"Got migrator, even though we don't yet have permission to read its resources."
);
sandbox
.stub(SafariProfileMigrator.prototype, "getPermissions")
.resolves(true);
sandbox.stub(safariMigrator, "getPermissions").callsFake(async () => {
hasPermissionsStub.resolves(true);
return Promise.resolve(true);
});
sandbox.stub(safariMigrator, "getResources").callsFake(() => {
return Promise.resolve([
{
type: MigrationUtils.resourceTypes.BOOKMARKS,
migrate: () => {},
},
]);
});
sandbox
.stub(SafariProfileMigrator.prototype, "getResources")
.callsFake(() => {
return Promise.resolve([
{
type: MigrationUtils.resourceTypes.BOOKMARKS,
migrate: () => {},
},
]);
});
let didMigration = new Promise(resolve => {
sandbox
.stub(safariMigrator, "migrate")
.stub(SafariProfileMigrator.prototype, "migrate")
.callsFake((aResourceTypes, aStartup, aProfile, aProgressCallback) => {
Assert.ok(
!aStartup,

View File

@@ -30,7 +30,6 @@
displayName: "Some Browser 0",
resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS", "EXTENSIONS"],
profile: { id: "person-2", name: "Person 2" },
hasPermissions: true,
},
{
key: "some-browser-1",
@@ -38,7 +37,6 @@
displayName: "Some Browser 1",
resourceTypes: ["HISTORY", "BOOKMARKS"],
profile: null,
hasPermissions: true,
},
];
@@ -218,7 +216,6 @@
displayName: "Some Browser 0 with no resources",
resourceTypes: [],
profile: { id: "person-1", name: "Person 1" },
hasPermissions: true,
}],
showImportAll: false,
});
@@ -383,14 +380,12 @@
displayName: "Some Browser 0 with a single resource",
resourceTypes: ["HISTORY"],
profile: { id: "person-1", name: "Person 1" },
hasPermissions: true,
}, {
key: "some-browser-1",
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
displayName: "Some Browser 1 with a two resources",
resourceTypes: ["HISTORY", "BOOKMARKS"],
profile: { id: "person-2", name: "Person 2" },
hasPermissions: true,
}],
showImportAll: true,
});
@@ -1039,7 +1034,6 @@
displayName: "Legacy Microsoft Browser",
resourceTypes: ["BOOKMARKS"],
profile: null,
hasPermissions: true,
}],
showImportAll: false,
});
@@ -1063,7 +1057,6 @@
displayName: "Legacy Microsoft Browser",
resourceTypes: ["BOOKMARKS"],
profile: null,
hasPermissions: true,
}],
showImportAll: true,
});
@@ -1334,7 +1327,6 @@
displayName: "Some Browser 0",
resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS"],
profile: { id: "person-2", name: "Person 2" },
hasPermissions: true,
},
{
key: "some-browser-1",
@@ -1342,7 +1334,6 @@
displayName: "Some Browser 1",
resourceTypes: ["HISTORY", "BOOKMARKS"],
profile: null,
hasPermissions: true,
},
{
key: FILE_MIGRATOR_KEY,
@@ -1433,94 +1424,6 @@
gWiz.removeAttribute("force-show-import-all");
});
/**
* Tests that for non-Safari migrators without permissions, we show
* the appropriate message and the button for getting permissions.
*/
add_task(async function no_permissions() {
const SOME_FAKE_PERMISSION_PATH = "/some/fake/path";
gWiz.setState({
page: MigrationWizardConstants.PAGES.SELECTION,
migrators: [{
key: "some-browser-0",
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
displayName: "Some Browser 0 with no permissions",
resourceTypes: [],
profile: null,
hasPermissions: false,
permissionsPath: SOME_FAKE_PERMISSION_PATH,
}],
showImportAll: false,
});
let selectionPage = gShadowRoot.querySelector("div[name='page-selection']");
ok(selectionPage.hasAttribute("no-permissions"), "no-permissions attribute set.");
let resourceList = gShadowRoot.querySelector(".resource-selection-details");
ok(isHidden(resourceList), "Resources list is hidden.");
let importButton = gShadowRoot.querySelector("#import");
ok(isHidden(importButton), "Import button hidden.");
let noPermissionsMessage = gShadowRoot.querySelector(".no-permissions-message");
ok(!isHidden(noPermissionsMessage), "No permissions message shown.");
let getPermissionButton = gShadowRoot.querySelector("#get-permissions");
ok(!isHidden(getPermissionButton), "Get permissions button shown.");
let step2 = gShadowRoot.querySelector(".migration-no-permissions-instructions-step2");
ok(step2.hasAttribute("data-l10n-args"));
is(JSON.parse(step2.getAttribute("data-l10n-args")).permissionsPath, SOME_FAKE_PERMISSION_PATH);
gWiz.setState({
page: MigrationWizardConstants.PAGES.SELECTION,
migrators: MIGRATOR_PROFILE_INSTANCES,
showImportAll: false,
});
ok(!selectionPage.hasAttribute("no-permissions"), "no-permissions attribute set to false.");
ok(!isHidden(resourceList), "Resources list is shown.");
ok(!isHidden(importButton), "Import button is shown.");
ok(isHidden(noPermissionsMessage), "No permissions message hidden.");
ok(isHidden(getPermissionButton), "Get permissions button hidden.");
});
/**
* Tests that for the Safari migrator without permissions, we show the
* normal resources list and impor tbutton instead of the no permissions
* message. Safari has a special flow where permissions are requested
* only after resource selection has occurred.
*/
add_task(async function no_permissions_safari() {
const SOME_FAKE_PERMISSION_PATH = "/some/fake/safari/path";
gWiz.setState({
page: MigrationWizardConstants.PAGES.SELECTION,
migrators: [{
key: "safari",
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
displayName: "Safari with no permissions",
resourceTypes: ["HISTORY", "BOOKMARKS"],
profile: null,
hasPermissions: false,
permissionsPath: SOME_FAKE_PERMISSION_PATH,
}],
showImportAll: false,
});
let selectionPage = gShadowRoot.querySelector("div[name='page-selection']");
ok(!selectionPage.hasAttribute("no-permissions"), "no-permissions attribute not set.");
let resourceList = gShadowRoot.querySelector(".resource-selection-details");
ok(!isHidden(resourceList), "Resources list is shown.");
let importButton = gShadowRoot.querySelector("#import");
ok(!isHidden(importButton), "Import button shown.");
let noPermissionsMessage = gShadowRoot.querySelector(".no-permissions-message");
ok(isHidden(noPermissionsMessage), "No permissions message hidden.");
let getPermissionButton = gShadowRoot.querySelector("#get-permissions");
ok(isHidden(getPermissionButton), "Get permissions button hiddne.");
});
</script>
</head>
<body>

View File

@@ -49,17 +49,12 @@ async function testBookmarks(migratorKey, subDirs) {
}
let target = rootDir.clone();
// Pretend this is the default profile
subDirs.push("Default");
while (subDirs.length) {
target.append(subDirs.shift());
}
let localStatePath = PathUtils.join(target.path, "Local State");
await IOUtils.writeJSON(localStatePath, []);
target.append("Default");
await IOUtils.makeDirectory(target.path, {
createAncestor: true,
ignoreExisting: true,
@@ -85,7 +80,6 @@ async function testBookmarks(migratorKey, subDirs) {
await IOUtils.writeJSON(target.path, bookmarksData);
let migrator = await MigrationUtils.getMigrator(migratorKey);
Assert.ok(await migrator.hasPermissions(), "Has permissions");
// Sanity check for the source.
Assert.ok(await migrator.isSourceAvailable());

View File

@@ -1,205 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that if the migrator does not have the permission to
* read from the Chrome data directory, that it can request
* permission to read from it, if the system allows.
*/
const { ChromeMigrationUtils } = ChromeUtils.importESModule(
"resource:///modules/ChromeMigrationUtils.sys.mjs"
);
const { ChromeProfileMigrator } = ChromeUtils.importESModule(
"resource:///modules/ChromeProfileMigrator.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
"resource://testing-common/Sinon.sys.mjs"
);
const { MockFilePicker } = ChromeUtils.importESModule(
"resource://testing-common/MockFilePicker.sys.mjs"
);
let gTempDir;
add_setup(async () => {
Services.prefs.setBoolPref(
"browser.migrate.chrome.get_permissions.enabled",
true
);
gTempDir = do_get_tempdir();
await IOUtils.writeJSON(PathUtils.join(gTempDir.path, "Local State"), []);
MockFilePicker.init(globalThis);
registerCleanupFunction(() => {
MockFilePicker.cleanup();
});
});
/**
* Tests that canGetPermissions will return false if the platform does
* not allow for folder selection in the native file picker, and returns
* the data path otherwise.
*/
add_task(async function test_canGetPermissions() {
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
let migrator = new ChromeProfileMigrator();
let canGetPermissionsStub = sandbox
.stub(MigrationUtils, "canGetPermissionsOnPlatform")
.resolves(false);
sandbox.stub(ChromeMigrationUtils, "getDataPath").resolves(gTempDir.path);
Assert.ok(
!(await migrator.canGetPermissions()),
"Should not be able to get permissions."
);
canGetPermissionsStub.resolves(true);
Assert.equal(
await migrator.canGetPermissions(),
gTempDir.path,
"Should be able to get the permissions path."
);
sandbox.restore();
});
/**
* Tests that getPermissions will show the native file picker in a
* loop until either the user cancels or selects a folder that grants
* read permissions to the data directory.
*/
add_task(async function test_getPermissions() {
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
let migrator = new ChromeProfileMigrator();
sandbox.stub(MigrationUtils, "canGetPermissionsOnPlatform").resolves(true);
sandbox.stub(ChromeMigrationUtils, "getDataPath").resolves(gTempDir.path);
let hasPermissionsStub = sandbox
.stub(migrator, "hasPermissions")
.resolves(false);
Assert.equal(
await migrator.canGetPermissions(),
gTempDir.path,
"Should be able to get the permissions path."
);
let filePickerSeenCount = 0;
let filePickerShownPromise = new Promise(resolve => {
MockFilePicker.showCallback = () => {
Assert.ok(true, "Filepicker shown.");
MockFilePicker.useDirectory([gTempDir.path]);
filePickerSeenCount++;
if (filePickerSeenCount > 3) {
Assert.ok(true, "File picker looped 3 times.");
hasPermissionsStub.resolves(true);
resolve();
}
};
});
MockFilePicker.returnValue = MockFilePicker.returnOK;
Assert.ok(
await migrator.getPermissions(),
"Should report that we got permissions."
);
await filePickerShownPromise;
// Make sure that the user can also hit "cancel" and that we
// file picker loop.
hasPermissionsStub.resolves(false);
filePickerSeenCount = 0;
filePickerShownPromise = new Promise(resolve => {
MockFilePicker.showCallback = () => {
Assert.ok(true, "Filepicker shown.");
filePickerSeenCount++;
Assert.equal(filePickerSeenCount, 1, "Saw the picker once.");
resolve();
};
});
MockFilePicker.returnValue = MockFilePicker.returnCancel;
Assert.ok(
!(await migrator.getPermissions()),
"Should report that we didn't get permissions."
);
await filePickerShownPromise;
sandbox.restore();
});
/**
* Tests that if the native file picker chooses a different directory
* than the one we originally asked for, that we remap attempts to
* read profiles from that new directory. This is because Ubuntu Snaps
* will return us paths from the native file picker that are symlinks
* to the original directories.
*/
add_task(async function test_remapDirectories() {
let remapDir = new FileUtils.File(
await IOUtils.createUniqueDirectory(
PathUtils.tempDir,
"test-chrome-migration"
)
);
let localStatePath = PathUtils.join(remapDir.path, "Local State");
await IOUtils.writeJSON(localStatePath, []);
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
let migrator = new ChromeProfileMigrator();
sandbox.stub(MigrationUtils, "canGetPermissionsOnPlatform").resolves(true);
sandbox.stub(ChromeMigrationUtils, "getDataPath").resolves(gTempDir.path);
let hasPermissionsStub = sandbox
.stub(migrator, "hasPermissions")
.resolves(false);
Assert.equal(
await migrator.canGetPermissions(),
gTempDir.path,
"Should be able to get the permissions path."
);
let filePickerShownPromise = new Promise(resolve => {
MockFilePicker.showCallback = () => {
Assert.ok(true, "Filepicker shown.");
MockFilePicker.useDirectory([remapDir.path]);
hasPermissionsStub.resolves(true);
resolve();
};
});
MockFilePicker.returnValue = MockFilePicker.returnOK;
Assert.ok(
await migrator.getPermissions(),
"Should report that we got permissions."
);
Assert.equal(
PathUtils.normalize(await migrator.canGetPermissions()),
PathUtils.normalize(remapDir.path),
"Should be able to get the remapped permissions path."
);
await filePickerShownPromise;
sandbox.restore();
});

View File

@@ -1,145 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that if the migrator does not have the permission to
* read from the Safari data directory, that it can request
* permission to read from it, if the system allows.
*/
const { SafariProfileMigrator } = ChromeUtils.importESModule(
"resource:///modules/SafariProfileMigrator.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
"resource://testing-common/Sinon.sys.mjs"
);
const { MockFilePicker } = ChromeUtils.importESModule(
"resource://testing-common/MockFilePicker.sys.mjs"
);
let gDataDir;
add_setup(async () => {
let tempDir = do_get_tempdir();
gDataDir = PathUtils.join(tempDir.path, "Safari");
await IOUtils.makeDirectory(gDataDir);
registerFakePath("ULibDir", tempDir);
MockFilePicker.init(globalThis);
registerCleanupFunction(() => {
MockFilePicker.cleanup();
});
});
/**
* Tests that canGetPermissions will return false if the platform does
* not allow for folder selection in the native file picker, and returns
* the data path otherwise.
*/
add_task(async function test_canGetPermissions() {
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
let migrator = new SafariProfileMigrator();
// Not being able to get a folder picker is not a problem on macOS, but
// we'll test that case anyways.
let canGetPermissionsStub = sandbox
.stub(MigrationUtils, "canGetPermissionsOnPlatform")
.resolves(false);
Assert.ok(
!(await migrator.canGetPermissions()),
"Should not be able to get permissions."
);
canGetPermissionsStub.resolves(true);
Assert.equal(
await migrator.canGetPermissions(),
gDataDir,
"Should be able to get the permissions path."
);
sandbox.restore();
});
/**
* Tests that getPermissions will show the native file picker in a
* loop until either the user cancels or selects a folder that grants
* read permissions to the data directory.
*/
add_task(async function test_getPermissions() {
let sandbox = sinon.createSandbox();
registerCleanupFunction(() => {
sandbox.restore();
});
let migrator = new SafariProfileMigrator();
sandbox.stub(MigrationUtils, "canGetPermissionsOnPlatform").resolves(true);
let hasPermissionsStub = sandbox
.stub(migrator, "hasPermissions")
.resolves(false);
Assert.equal(
await migrator.canGetPermissions(),
gDataDir,
"Should be able to get the permissions path."
);
let filePickerSeenCount = 0;
let filePickerShownPromise = new Promise(resolve => {
MockFilePicker.showCallback = () => {
Assert.ok(true, "Filepicker shown.");
MockFilePicker.useDirectory([gDataDir]);
filePickerSeenCount++;
if (filePickerSeenCount > 3) {
Assert.ok(true, "File picker looped 3 times.");
hasPermissionsStub.resolves(true);
resolve();
}
};
});
MockFilePicker.returnValue = MockFilePicker.returnOK;
// This is a little awkward, but we need to ensure that the
// filePickerShownPromise resolves first before we await
// the getPermissionsPromise in order to get the correct
// filePickerSeenCount.
let getPermissionsPromise = migrator.getPermissions();
await filePickerShownPromise;
Assert.ok(
await getPermissionsPromise,
"Should report that we got permissions."
);
// Make sure that the user can also hit "cancel" and that we
// file picker loop.
hasPermissionsStub.resolves(false);
filePickerSeenCount = 0;
filePickerShownPromise = new Promise(resolve => {
MockFilePicker.showCallback = () => {
Assert.ok(true, "Filepicker shown.");
filePickerSeenCount++;
Assert.equal(filePickerSeenCount, 1, "Saw the picker once.");
resolve();
};
});
MockFilePicker.returnValue = MockFilePicker.returnCancel;
Assert.ok(
!(await migrator.getPermissions()),
"Should report that we didn't get permissions."
);
await filePickerShownPromise;
sandbox.restore();
});

View File

@@ -38,7 +38,6 @@ support-files =
LibraryWithNoData/**
[test_ChromeMigrationUtils.js]
[test_ChromeMigrationUtils_path.js]
[test_Chrome_permissions.js]
[test_Edge_db_migration.js]
skip-if = os != "win"
[test_Edge_registry_migration.js]
@@ -57,5 +56,3 @@ skip-if = !debug && os == "mac" #Bug 1558330
skip-if = os != "mac"
[test_Safari_history.js]
skip-if = os != "mac"
[test_Safari_permissions.js]
skip-if = os != "mac"

View File

@@ -34,7 +34,6 @@ const FAKE_MIGRATOR_LIST = [
],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/chrome.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -50,7 +49,6 @@ const FAKE_MIGRATOR_LIST = [
],
profile: { id: "person-2", name: "Person 2" },
brandImage: "chrome://browser/content/migration/brands/chrome.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -59,7 +57,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "BOOKMARKS"],
profile: null,
brandImage: "chrome://global/skin/icons/defaultFavicon.svg",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -68,7 +65,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS"],
profile: null,
brandImage: "chrome://global/skin/icons/defaultFavicon.svg",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -83,7 +79,6 @@ const FAKE_MIGRATOR_LIST = [
],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/edge.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -98,7 +93,6 @@ const FAKE_MIGRATOR_LIST = [
],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/brave.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -107,7 +101,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "PASSWORDS", "BOOKMARKS"],
profile: null,
brandImage: "chrome://global/skin/icons/defaultFavicon.svg",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -116,7 +109,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "PASSWORDS", "BOOKMARKS"],
profile: null,
brandImage: "chrome://browser/content/migration/brands/safari.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -125,7 +117,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS"],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/opera.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -134,7 +125,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY", "FORMDATA", "PASSWORDS", "BOOKMARKS"],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/operagx.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -143,7 +133,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: ["HISTORY"],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/vivaldi.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
@@ -152,7 +141,6 @@ const FAKE_MIGRATOR_LIST = [
resourceTypes: [],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://global/skin/icons/defaultFavicon.svg",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.FILE,
@@ -160,7 +148,6 @@ const FAKE_MIGRATOR_LIST = [
displayName: "Passwords from CSV file",
brandImage: "chrome://branding/content/document.ico",
resourceTypes: [],
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.FILE,
@@ -168,7 +155,6 @@ const FAKE_MIGRATOR_LIST = [
displayName: "Bookmarks from file",
brandImage: "chrome://branding/content/document.ico",
resourceTypes: [],
hasPermissions: true,
},
];
@@ -217,62 +203,6 @@ MainSelectorVariant2.args = {
},
};
export const NoPermissionMessage = Template.bind({});
NoPermissionMessage.args = {
dialogMode: true,
state: {
page: MigrationWizardConstants.PAGES.SELECTION,
migrators: [
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
key: "chromium",
displayName: "Chromium",
resourceTypes: [],
profile: null,
brandImage: "chrome://browser/content/migration/brands/chromium.png",
hasPermissions: false,
permissionsPath: "/home/user/snap/chromium/common/chromium",
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
key: "safari",
displayName: "Safari",
resourceTypes: ["HISTORY", "PASSWORDS", "BOOKMARKS"],
profile: null,
brandImage: "chrome://browser/content/migration/brands/safari.png",
hasPermissions: false,
permissionsPath: "/Users/user/Library/Safari",
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.BROWSER,
key: "vivaldi",
displayName: "Vivaldi",
resourceTypes: ["HISTORY"],
profile: { id: "Default", name: "Default" },
brandImage: "chrome://browser/content/migration/brands/vivaldi.png",
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.FILE,
key: "file-password-csv",
displayName: "Passwords from CSV file",
brandImage: "chrome://branding/content/document.ico",
resourceTypes: [],
hasPermissions: true,
},
{
type: MigrationWizardConstants.MIGRATOR_TYPES.FILE,
key: "file-bookmarks",
displayName: "Bookmarks from file",
brandImage: "chrome://branding/content/document.ico",
resourceTypes: [],
hasPermissions: true,
},
],
showImportAll: false,
},
};
export const Progress = Template.bind({});
Progress.args = {
dialogMode: true,

View File

@@ -45,23 +45,6 @@ migration-wizard-migrator-display-name-opera-gx = Opera GX
migration-wizard-migrator-display-name-safari = Safari
migration-wizard-migrator-display-name-vivaldi = Vivaldi
## These strings are shown if the selected browser data directory is unreadable.
## In practice, this tends to only occur on Linux when Firefox
## is installed as a Snap.
migration-no-permissions-message = { -brand-short-name } does not have access to other browsers profiles installed on this device.
migration-no-permissions-instructions = To continue importing data from another browser, grant { -brand-short-name } access to its profile folder.
migration-no-permissions-instructions-step1 = Select “Continue”
# The second step in getting permissions to read data for the selected
# browser type.
#
# Variables:
# $permissionsPath (String): the file system path that the user will need to grant read permission to.
migration-no-permissions-instructions-step2 = In the file picker, navigate to <code>{ $permissionsPath }</code> and choose “Select”
## These strings will be displayed based on how many resources are selected to import
migration-all-available-data-label = Import all available data

View File

@@ -157,9 +157,6 @@ div[name="page-selection"][show-import-all] #select-all {
}
div[name="page-selection"][migrator-type="browser"] > .buttons > #import-from-file,
div[name="page-selection"][migrator-type="browser"][no-permissions] > .buttons > #import,
div[name="page-selection"][migrator-type="browser"]:not([no-permissions]) > .buttons > #get-permissions,
div[name="page-selection"][migrator-type="file"] > .buttons > #get-permissions,
div[name="page-selection"][migrator-type="file"] > .buttons > #import,
div[name="page-selection"][migrator-type="file"] > .resource-selection-details,
div[name="page-selection"][migrator-type="file"] > .resource-selection-preamble,
@@ -167,15 +164,6 @@ div[name="page-selection"][show-import-all] .resource-selection-preamble {
display: none;
}
/**
* We're using <code> to ease legibility for paths on
* the user's system, but intentionally reduce the font
* size to more closely match the surrounding text.
*/
.migration-no-permissions-instructions-step2 > code {
font-size: 0.94em;
}
.resource-selection-preamble {
margin-block-start: 16px;
}
@@ -357,8 +345,7 @@ summary {
}
div[name="page-selection"]:not([no-resources]) .no-resources-found,
div[name="page-selection"]:not([no-permissions]) .no-permissions-message,
div[name="page-selection"]:is([no-resources],[no-permissions]) .hide-on-error,
div[name="page-selection"][no-resources] .hide-on-no-resources-error,
div[name="page-selection"]:not([file-import-error]) .file-import-error {
display: none;
}

View File

@@ -1562,15 +1562,6 @@ migrationWizard:
description: True if importing extensions is enabled.
type: boolean
setPref: browser.migrate.chrome.extensions.enabled
chromeCanRequestPermissions:
description: >-
True if Chrome-based browsers can request read permissions on
platforms where the browser is restricted from reading the contents
of a Chrome-based browser's user data directory. In practice, this
is only relevant to the Linux platform when the browser is installed
as a Snap package.
type: boolean
setPref: browser.migrate.chrome.get_permissions.enabled
mixedContentUpgrading:
description: Prefs to control whether we upgrade mixed passive content (images, audio, video) from http to https