diff options
Diffstat (limited to 'browser/components/migration/IEProfileMigrator.js')
-rw-r--r-- | browser/components/migration/IEProfileMigrator.js | 542 |
1 files changed, 0 insertions, 542 deletions
diff --git a/browser/components/migration/IEProfileMigrator.js b/browser/components/migration/IEProfileMigrator.js deleted file mode 100644 index ac055686c..000000000 --- a/browser/components/migration/IEProfileMigrator.js +++ /dev/null @@ -1,542 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; - -const kLoginsKey = "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2"; -const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main"; - -Cu.import("resource://gre/modules/AppConstants.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); /* globals OS */ -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource:///modules/MigrationUtils.jsm"); /* globals MigratorPrototype */ -Cu.import("resource:///modules/MSMigrationUtils.jsm"); - - -XPCOMUtils.defineLazyModuleGetter(this, "ctypes", - "resource://gre/modules/ctypes.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", - "resource://gre/modules/PlacesUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto", - "resource://gre/modules/OSCrypto.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry", - "resource://gre/modules/WindowsRegistry.jsm"); - -Cu.importGlobalProperties(["URL"]); - -// Resources - -function History() { -} - -History.prototype = { - type: MigrationUtils.resourceTypes.HISTORY, - - get exists() { - return true; - }, - - migrate: function H_migrate(aCallback) { - let places = []; - let typedURLs = MSMigrationUtils.getTypedURLs("Software\\Microsoft\\Internet Explorer"); - let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"]. - createInstance(Ci.nsISimpleEnumerator); - while (historyEnumerator.hasMoreElements()) { - let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2); - let uri = entry.get("uri").QueryInterface(Ci.nsIURI); - // MSIE stores some types of URLs in its history that we don't handle, - // like HTMLHelp and others. Since we don't properly map handling for - // all of them we just avoid importing them. - if (["http", "https", "ftp", "file"].indexOf(uri.scheme) == -1) { - continue; - } - - let title = entry.get("title"); - // Embed visits have no title and don't need to be imported. - if (title.length == 0) { - continue; - } - - // The typed urls are already fixed-up, so we can use them for comparison. - let transitionType = typedURLs.has(uri.spec) ? - Ci.nsINavHistoryService.TRANSITION_TYPED : - Ci.nsINavHistoryService.TRANSITION_LINK; - // use the current date if we have no visits for this entry. - // Note that the entry will have a time in microseconds (PRTime), - // and Date.now() returns milliseconds. Places expects PRTime, - // so we multiply the Date.now return value to make up the difference. - let lastVisitTime = entry.get("time") || (Date.now() * 1000); - - places.push( - { uri: uri, - title: title, - visits: [{ transitionType: transitionType, - visitDate: lastVisitTime }] - } - ); - } - - // Check whether there is any history to import. - if (places.length == 0) { - aCallback(true); - return; - } - - MigrationUtils.insertVisitsWrapper(places, { - _success: false, - handleResult: function() { - // Importing any entry is considered a successful import. - this._success = true; - }, - handleError: function() {}, - handleCompletion: function() { - aCallback(this._success); - } - }); - } -}; - -// IE form password migrator supporting windows from XP until 7 and IE from 7 until 11 -function IE7FormPasswords() { - // used to distinguish between this migrator and other passwords migrators in tests. - this.name = "IE7FormPasswords"; -} - -IE7FormPasswords.prototype = { - type: MigrationUtils.resourceTypes.PASSWORDS, - - get exists() { - // work only on windows until 7 - if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2")) { - return false; - } - - try { - let nsIWindowsRegKey = Ci.nsIWindowsRegKey; - let key = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(nsIWindowsRegKey); - key.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, kLoginsKey, - nsIWindowsRegKey.ACCESS_READ); - let count = key.valueCount; - key.close(); - return count > 0; - } catch (e) { - return false; - } - }, - - migrate(aCallback) { - let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"]. - createInstance(Ci.nsISimpleEnumerator); - let uris = []; // the uris of the websites that are going to be migrated - while (historyEnumerator.hasMoreElements()) { - let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2); - let uri = entry.get("uri").QueryInterface(Ci.nsIURI); - // MSIE stores some types of URLs in its history that we don't handle, like HTMLHelp - // and others. Since we are not going to import the logins that are performed in these URLs - // we can just skip them. - if (["http", "https", "ftp"].indexOf(uri.scheme) == -1) { - continue; - } - - uris.push(uri); - } - this._migrateURIs(uris); - aCallback(true); - }, - - /** - * Migrate the logins that were saved for the uris arguments. - * @param {nsIURI[]} uris - the uris that are going to be migrated. - */ - _migrateURIs(uris) { - this.ctypesKernelHelpers = new MSMigrationUtils.CtypesKernelHelpers(); - this._crypto = new OSCrypto(); - let nsIWindowsRegKey = Ci.nsIWindowsRegKey; - let key = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(nsIWindowsRegKey); - key.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, kLoginsKey, - nsIWindowsRegKey.ACCESS_READ); - - let urlsSet = new Set(); // set of the already processed urls. - // number of the successfully decrypted registry values - let successfullyDecryptedValues = 0; - /* The logins are stored in the registry, where the key is a hashed URL and its - * value contains the encrypted details for all logins for that URL. - * - * First iterate through IE history, hashing each URL and looking for a match. If - * found, decrypt the value, using the URL as a salt. Finally add any found logins - * to the Firefox password manager. - */ - - for (let uri of uris) { - try { - // remove the query and the ref parts of the URL - let urlObject = new URL(uri.spec); - let url = urlObject.origin + urlObject.pathname; - // if the current url is already processed, it should be skipped - if (urlsSet.has(url)) { - continue; - } - urlsSet.add(url); - // hash value of the current uri - let hashStr = this._crypto.getIELoginHash(url); - if (!key.hasValue(hashStr)) { - continue; - } - let value = key.readBinaryValue(hashStr); - // if no value was found, the uri is skipped - if (value == null) { - continue; - } - let data; - try { - // the url is used as salt to decrypt the registry value - data = this._crypto.decryptData(value, url, true); - } catch (e) { - continue; - } - // extract the login details from the decrypted data - let ieLogins = this._extractDetails(data, uri); - // if at least a credential was found in the current data, successfullyDecryptedValues should - // be incremented by one - if (ieLogins.length) { - successfullyDecryptedValues++; - } - this._addLogins(ieLogins); - } catch (e) { - Cu.reportError("Error while importing logins for " + uri.spec + ": " + e); - } - } - // if the number of the imported values is less than the number of values in the key, it means - // that not all the values were imported and an error should be reported - if (successfullyDecryptedValues < key.valueCount) { - Cu.reportError("We failed to decrypt and import some logins. " + - "This is likely because we didn't find the URLs where these " + - "passwords were submitted in the IE history and which are needed to be used " + - "as keys in the decryption."); - } - - key.close(); - this._crypto.finalize(); - this.ctypesKernelHelpers.finalize(); - }, - - _crypto: null, - - /** - * Add the logins to the password manager. - * @param {Object[]} logins - array of the login details. - */ - _addLogins(ieLogins) { - for (let ieLogin of ieLogins) { - try { - // create a new login - let login = { - username: ieLogin.username, - password: ieLogin.password, - hostname: ieLogin.url, - timeCreated: ieLogin.creation, - }; - MigrationUtils.insertLoginWrapper(login); - } catch (e) { - Cu.reportError(e); - } - } - }, - - /** - * Extract the details of one or more logins from the raw decrypted data. - * @param {string} data - the decrypted data containing raw information. - * @param {nsURI} uri - the nsURI of page where the login has occur. - * @returns {Object[]} array of objects where each of them contains the username, password, URL, - * and creation time representing all the logins found in the data arguments. - */ - _extractDetails(data, uri) { - // the structure of the header of the IE7 decrypted data for all the logins sharing the same URL - let loginData = new ctypes.StructType("loginData", [ - // Bytes 0-3 are not needed and not documented - {"unknown1": ctypes.uint32_t}, - // Bytes 4-7 are the header size - {"headerSize": ctypes.uint32_t}, - // Bytes 8-11 are the data size - {"dataSize": ctypes.uint32_t}, - // Bytes 12-19 are not needed and not documented - {"unknown2": ctypes.uint32_t}, - {"unknown3": ctypes.uint32_t}, - // Bytes 20-23 are the data count: each username and password is considered as a data - {"dataMax": ctypes.uint32_t}, - // Bytes 24-35 are not needed and not documented - {"unknown4": ctypes.uint32_t}, - {"unknown5": ctypes.uint32_t}, - {"unknown6": ctypes.uint32_t} - ]); - - // the structure of a IE7 decrypted login item - let loginItem = new ctypes.StructType("loginItem", [ - // Bytes 0-3 are the offset of the username - {"usernameOffset": ctypes.uint32_t}, - // Bytes 4-11 are the date - {"loDateTime": ctypes.uint32_t}, - {"hiDateTime": ctypes.uint32_t}, - // Bytes 12-15 are not needed and not documented - {"foo": ctypes.uint32_t}, - // Bytes 16-19 are the offset of the password - {"passwordOffset": ctypes.uint32_t}, - // Bytes 20-31 are not needed and not documented - {"unknown1": ctypes.uint32_t}, - {"unknown2": ctypes.uint32_t}, - {"unknown3": ctypes.uint32_t} - ]); - - let url = uri.prePath; - let results = []; - let arr = this._crypto.stringToArray(data); - // convert data to ctypes.unsigned_char.array(arr.length) - let cdata = ctypes.unsigned_char.array(arr.length)(arr); - // Bytes 0-35 contain the loginData data structure for all the logins sharing the same URL - let currentLoginData = ctypes.cast(cdata, loginData); - let headerSize = currentLoginData.headerSize; - let currentInfoIndex = loginData.size; - // pointer to the current login item - let currentLoginItemPointer = ctypes.cast(cdata.addressOfElement(currentInfoIndex), - loginItem.ptr); - // currentLoginData.dataMax is the data count: each username and password is considered as - // a data. So, the number of logins is the number of data dived by 2 - let numLogins = currentLoginData.dataMax / 2; - for (let n = 0; n < numLogins; n++) { - // Bytes 0-31 starting from currentInfoIndex contain the loginItem data structure for the - // current login - let currentLoginItem = currentLoginItemPointer.contents; - let creation = this.ctypesKernelHelpers. - fileTimeToSecondsSinceEpoch(currentLoginItem.hiDateTime, - currentLoginItem.loDateTime) * 1000; - let currentResult = { - creation: creation, - url: url, - }; - // The username is UTF-16 and null-terminated. - currentResult.username = - ctypes.cast(cdata.addressOfElement(headerSize + 12 + currentLoginItem.usernameOffset), - ctypes.char16_t.ptr).readString(); - // The password is UTF-16 and null-terminated. - currentResult.password = - ctypes.cast(cdata.addressOfElement(headerSize + 12 + currentLoginItem.passwordOffset), - ctypes.char16_t.ptr).readString(); - results.push(currentResult); - // move to the next login item - currentLoginItemPointer = currentLoginItemPointer.increment(); - } - return results; - }, -}; - -function Settings() { -} - -Settings.prototype = { - type: MigrationUtils.resourceTypes.SETTINGS, - - get exists() { - return true; - }, - - migrate: function S_migrate(aCallback) { - // Converts from yes/no to a boolean. - let yesNoToBoolean = v => v == "yes"; - - // Converts source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into - // destination format like "en-us, ar-kw, ar-om". - // Final string is sorted by quality (q=) param. - function parseAcceptLanguageList(v) { - return v.match(/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/gi) - .sort(function(a, b) { - let qA = parseFloat(a.split(";q=")[1]) || 1.0; - let qB = parseFloat(b.split(";q=")[1]) || 1.0; - return qB - qA; - }) - .map(a => a.split(";")[0]); - } - - // For reference on some of the available IE Registry settings: - // * http://msdn.microsoft.com/en-us/library/cc980058%28v=prot.13%29.aspx - // * http://msdn.microsoft.com/en-us/library/cc980059%28v=prot.13%29.aspx - - // Note that only settings exposed in our UI should be migrated. - - this._set("Software\\Microsoft\\Internet Explorer\\International", - "AcceptLanguage", - "intl.accept_languages", - parseAcceptLanguageList); - // TODO (bug 745853): For now, only x-western font is translated. - this._set("Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3", - "IEFixedFontName", - "font.name.monospace.x-western"); - this._set(kMainKey, - "Use FormSuggest", - "browser.formfill.enable", - yesNoToBoolean); - this._set(kMainKey, - "FormSuggest Passwords", - "signon.rememberSignons", - yesNoToBoolean); - this._set(kMainKey, - "Anchor Underline", - "browser.underline_anchors", - yesNoToBoolean); - this._set(kMainKey, - "Display Inline Images", - "permissions.default.image", - v => yesNoToBoolean(v) ? 1 : 2); - this._set(kMainKey, - "Move System Caret", - "accessibility.browsewithcaret", - yesNoToBoolean); - this._set("Software\\Microsoft\\Internet Explorer\\Settings", - "Always Use My Colors", - "browser.display.document_color_use", - v => (!v ? 0 : 2)); - this._set("Software\\Microsoft\\Internet Explorer\\Settings", - "Always Use My Font Face", - "browser.display.use_document_fonts", - v => !v); - this._set(kMainKey, - "SmoothScroll", - "general.smoothScroll", - Boolean); - this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\", - "WarnOnClose", - "browser.tabs.warnOnClose", - Boolean); - this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\", - "OpenInForeground", - "browser.tabs.loadInBackground", - v => !v); - - aCallback(true); - }, - - /** - * Reads a setting from the Registry and stores the converted result into - * the appropriate Firefox preference. - * - * @param aPath - * Registry path under HKCU. - * @param aKey - * Name of the key. - * @param aPref - * Firefox preference. - * @param [optional] aTransformFn - * Conversion function from the Registry format to the pref format. - */ - _set: function S__set(aPath, aKey, aPref, aTransformFn) { - let value = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - aPath, aKey); - // Don't import settings that have never been flipped. - if (value === undefined) - return; - - if (aTransformFn) - value = aTransformFn(value); - - switch (typeof value) { - case "string": - Services.prefs.setCharPref(aPref, value); - break; - case "number": - Services.prefs.setIntPref(aPref, value); - break; - case "boolean": - Services.prefs.setBoolPref(aPref, value); - break; - default: - throw new Error("Unexpected value type: " + (typeof value)); - } - } -}; - -function IEProfileMigrator() -{ - this.wrappedJSObject = this; // export this to be able to use it in the unittest. -} - -IEProfileMigrator.prototype = Object.create(MigratorPrototype); - -IEProfileMigrator.prototype.getResources = function IE_getResources() { - let resources = [ - MSMigrationUtils.getBookmarksMigrator(), - new History(), - MSMigrationUtils.getCookiesMigrator(), - new Settings(), - ]; - // Only support the form password migrator for Windows XP to 7. - if (AppConstants.isPlatformAndVersionAtMost("win", "6.1")) { - resources.push(new IE7FormPasswords()); - } - let windowsVaultFormPasswordsMigrator = - MSMigrationUtils.getWindowsVaultFormPasswordsMigrator(); - windowsVaultFormPasswordsMigrator.name = "IEVaultFormPasswords"; - resources.push(windowsVaultFormPasswordsMigrator); - return resources.filter(r => r.exists); -}; - -IEProfileMigrator.prototype.getLastUsedDate = function IE_getLastUsedDate() { - let datePromises = ["Favs", "CookD"].map(dirId => { - let {path} = Services.dirsvc.get(dirId, Ci.nsIFile); - return OS.File.stat(path).catch(() => null).then(info => { - return info ? info.lastModificationDate : 0; - }); - }); - datePromises.push(new Promise(resolve => { - let typedURLs = new Map(); - try { - typedURLs = MSMigrationUtils.getTypedURLs("Software\\Microsoft\\Internet Explorer"); - } catch (ex) {} - let dates = [0, ... typedURLs.values()]; - resolve(Math.max.apply(Math, dates)); - })); - return Promise.all(datePromises).then(dates => { - return new Date(Math.max.apply(Math, dates)); - }); -}; - -Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", { - get: function IE_get_sourceHomePageURL() { - let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, - kMainKey, "Default_Page_URL"); - let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - kMainKey, "Start Page"); - // If the user didn't customize the Start Page, he is still on the default - // page, that may be considered the equivalent of our about:home. There's - // no reason to retain it, since it is heavily targeted to IE. - let homepage = startPage != defaultStartPage ? startPage : ""; - - // IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These - // are in addition to the Start Page, and no empty entries are possible, - // thus a Start Page is always defined if any of these exists, though it - // may be the default one. - let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - kMainKey, "Secondary Start Pages"); - if (secondaryPages) { - if (homepage) - secondaryPages.unshift(homepage); - homepage = secondaryPages.join("|"); - } - - return homepage; - } -}); - -IEProfileMigrator.prototype.classDescription = "IE Profile Migrator"; -IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie"; -IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}"); - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]); |