merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-09-17 14:42:06 +02:00
commit d61e0e3273
23 changed files with 591 additions and 115 deletions

View File

@ -6983,16 +6983,14 @@ var gIdentityHandler = {
},
/**
* Return the eTLD+1 version of the current hostname
* Attempt to provide proper IDN treatment for host names
*/
getEffectiveHost : function() {
getEffectiveHost: function() {
if (!this._IDNService)
this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
.getService(Ci.nsIIDNService);
try {
let baseDomain =
Services.eTLD.getBaseDomainFromHost(this._uri.host);
return this._IDNService.convertToDisplayIDN(baseDomain, {});
return this._IDNService.convertToDisplayIDN(this._uri.host, {});
} catch (e) {
// If something goes wrong (e.g. host is an IP address) just fail back
// to the full domain.
@ -7162,6 +7160,7 @@ var gIdentityHandler = {
let verifier = "";
let host = "";
let owner = "";
let crop = "start";
try {
host = this.getEffectiveHost();
@ -7181,6 +7180,8 @@ var gIdentityHandler = {
// Fill in organization information if we have a valid EV certificate.
if (isEV) {
crop = "end";
let iData = this.getIdentityData();
host = owner = iData.subjectOrg;
verifier = this._identityBox.tooltipText;
@ -7200,6 +7201,7 @@ var gIdentityHandler = {
// Push the appropriate strings out to the UI. Need to use |value| for the
// host as it's a <label> that will be cropped if too long. Using
// |textContent| would simply wrap the value.
this._identityPopupContentHost.setAttribute("crop", crop);
this._identityPopupContentHost.setAttribute("value", host);
this._identityPopupContentOwner.textContent = owner;
this._identityPopupContentSupp.textContent = supplemental;

View File

@ -5486,6 +5486,7 @@
this._dndCanvas = canvas;
this._dndPanel = document.createElement("panel");
this._dndPanel.setAttribute("type", "drag");
this._dndPanel.setAttribute("mousethrough", "always");
this._dndPanel.appendChild(canvas);
document.documentElement.appendChild(this._dndPanel);
}

View File

@ -470,6 +470,7 @@ skip-if = e10s # Bug 1100700 - test relies on unload event firing on closed tabs
skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_urlbarRevert.js]
[browser_urlbarSearchSingleWordNotification.js]
[browser_urlbarSearchSuggestions.js]
[browser_urlbarSearchSuggestionsNotification.js]
[browser_urlbarStop.js]
[browser_urlbarTrimURLs.js]

View File

@ -17,7 +17,7 @@ var tests = [
{
name: "normal domain",
location: "http://test1.example.org/",
effectiveHost: "example.org"
effectiveHost: "test1.example.org"
},
{
name: "view-source",
@ -33,17 +33,17 @@ var tests = [
{
name: "IDN subdomain",
location: "http://sub1." + idnDomain + "/",
effectiveHost: idnDomain
effectiveHost: "sub1." + idnDomain
},
{
name: "subdomain with port",
location: "http://sub1.test1.example.org:8000/",
effectiveHost: "example.org"
effectiveHost: "sub1.test1.example.org"
},
{
name: "subdomain HTTPS",
location: "https://test1.example.com/",
effectiveHost: "example.com",
effectiveHost: "test1.example.com",
isHTTPS: true
},
{

View File

@ -0,0 +1,63 @@
const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
// Must run first.
add_task(function* prepare() {
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
let oldCurrentEngine = Services.search.currentEngine;
Services.search.currentEngine = engine;
registerCleanupFunction(function () {
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
Services.search.currentEngine = oldCurrentEngine;
// Clicking suggestions causes visits to search results pages, so clear that
// history now.
yield PlacesTestUtils.clearHistory();
// Make sure the popup is closed for the next test.
gURLBar.blur();
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
});
});
add_task(function* clickSuggestion() {
gURLBar.focus();
yield promiseAutocompleteResultPopup("foo");
let [idx, suggestion] = yield promiseFirstSuggestion();
let item = gURLBar.popup.richlistbox.getItemAtIndex(idx);
let loadPromise = promiseTabLoaded(gBrowser.selectedTab);
item.click();
yield loadPromise;
let uri = Services.search.currentEngine.getSubmission(suggestion).uri;
Assert.ok(uri.equals(gBrowser.currentURI),
"The search results page should have loaded");
});
function getFirstSuggestion() {
let controller = gURLBar.popup.input.controller;
let matchCount = controller.matchCount;
let present = false;
for (let i = 0; i < matchCount; i++) {
let url = controller.getValueAt(i);
let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
if (mozActionMatch) {
let [, type, paramStr] = mozActionMatch;
let params = JSON.parse(paramStr);
if (type == "searchengine" && "searchSuggestion" in params) {
return [i, params.searchSuggestion];
}
}
}
return [-1, null];
}
function promiseFirstSuggestion() {
return new Promise(resolve => {
let pair;
waitForCondition(() => {
pair = getFirstSuggestion();
return pair[0] >= 0;
}, () => resolve(pair));
});
}

View File

@ -183,6 +183,19 @@ add_task(function* multipleWindows() {
yield BrowserTestUtils.closeWindow(win3);
});
add_task(function* enableOutsideNotification() {
// Setting the suggest.searches pref outside the notification (e.g., by
// ticking the checkbox in the preferences window) should hide it.
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
yield setUserMadeChoicePref(false);
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
gURLBar.focus();
yield promiseAutocompleteResultPopup("foo");
assertVisible(false);
});
/**
* Setting the choice pref triggers a pref observer in the urlbar, which hides
* the notification if it's present. This function returns a promise that's
@ -214,13 +227,13 @@ function suggestionsPresent() {
let present = false;
for (let i = 0; i < matchCount; i++) {
let url = controller.getValueAt(i);
let [, type, paramStr] = url.match(/^moz-action:([^,]+),(.*)$/);
let params = {};
try {
params = JSON.parse(paramStr);
} catch (err) {}
if (type == "searchengine" && "searchSuggestion" in params) {
return true;
let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
if (mozActionMatch) {
let [, type, paramStr] = mozActionMatch;
let params = JSON.parse(paramStr);
if (type == "searchengine" && "searchSuggestion" in params) {
return true;
}
}
}
return false;

View File

@ -5,5 +5,5 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>browser_searchSuggestionEngine searchSuggestionEngine.xml</ShortName>
<Url type="application/x-suggestions+json" method="GET" template="http://mochi.test:8888/browser/browser/base/content/test/general/searchSuggestionEngine.sjs?{searchTerms}"/>
<Url type="text/html" method="GET" template="http://www.browser-searchSuggestionEngine.com/searchSuggestionEngine&amp;terms={searchTerms}" rel="searchform"/>
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/base/content/test/general/searchSuggestionEngine.sjs?{searchTerms}" rel="searchform"/>
</SearchPlugin>

View File

@ -66,9 +66,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
this.timeout = this._prefs.getIntPref("delay");
this._formattingEnabled = this._prefs.getBoolPref("formatting.enabled");
this._mayTrimURLs = this._prefs.getBoolPref("trimURLs");
this._userMadeSearchSuggestionsChoice =
this._prefs.getBoolPref("userMadeSearchSuggestionsChoice");
this._cacheUserMadeSearchSuggestionsChoice();
this.inputField.controllers.insertControllerAt(0, this._copyCutController);
this.inputField.addEventListener("paste", this, false);
this.inputField.addEventListener("mousedown", this, false);
@ -663,11 +661,19 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
this._formattingEnabled = this._prefs.getBoolPref(aData);
break;
case "userMadeSearchSuggestionsChoice":
this._userMadeSearchSuggestionsChoice =
this._prefs.getBoolPref(aData);
this.popup.searchSuggestionsNotificationWasDismissed(
this._prefs.getBoolPref("suggest.searches")
);
case "suggest.searches":
this._cacheUserMadeSearchSuggestionsChoice();
// Make sure the urlbar is focused. It won't be, for example,
// if the user used an accesskey to make an opt-in choice.
// mIgnoreFocus prevents the text from being selected.
this.mIgnoreFocus = true;
this.focus();
this.mIgnoreFocus = false;
if (this._userMadeSearchSuggestionsChoice) {
this.popup.searchSuggestionsNotificationWasDismissed(
this._prefs.getBoolPref("suggest.searches")
);
}
break;
case "trimURLs":
this._mayTrimURLs = this._prefs.getBoolPref(aData);
@ -825,6 +831,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
}
for (let key of [
"engineName",
"input",
"searchQuery",
"searchSuggestion",
@ -923,6 +930,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
false
]]></field>
<method name="_cacheUserMadeSearchSuggestionsChoice">
<body><![CDATA[
this._userMadeSearchSuggestionsChoice =
this._prefs.getBoolPref("userMadeSearchSuggestionsChoice") ||
this._prefs.getBoolPref("suggest.searches");
]]></body>
</method>
<property name="shouldShowSearchSuggestionsNotification" readonly="true">
<getter><![CDATA[
return !this._userMadeSearchSuggestionsChoice &&

View File

@ -10,7 +10,7 @@
orient="vertical">
<broadcasterset>
<broadcaster id="identity-popup-content-host" class="identity-popup-headline" crop="end"/>
<broadcaster id="identity-popup-content-host" class="identity-popup-headline" crop="start"/>
<broadcaster id="identity-popup-mcb-learn-more" class="text-link plain" value="&identity.learnMore;"/>
</broadcasterset>

View File

@ -2,7 +2,7 @@
* 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/. */
html[dir="rtl"]:not(.outer-html) {
html[dir="rtl"]:not(#outer-html) {
/* Temporary work around and visual hack -
* Scope the root body overflow visible to remove the scroll bars that appear
* inside an iFrame. Can remove this rule after core layout fix for

View File

@ -19,6 +19,10 @@ EdgeProfileMigrator.prototype.getResources = function() {
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
];
let windowsVaultFormPasswordsMigrator =
MSMigrationUtils.getWindowsVaultFormPasswordsMigrator();
windowsVaultFormPasswordsMigrator.name = "EdgeVaultFormPasswords";
resources.push(windowsVaultFormPasswordsMigrator);
return resources.filter(r => r.exists);
};

View File

@ -18,6 +18,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource:///modules/MSMigrationUtils.jsm");
Cu.import("resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
"resource://gre/modules/ctypes.jsm");
@ -30,6 +32,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
Cu.importGlobalProperties(["URL"]);
let CtypesKernelHelpers = MSMigrationUtils.CtypesKernelHelpers;
////////////////////////////////////////////////////////////////////////////////
//// Resources
@ -126,12 +130,19 @@ History.prototype = {
// 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"].
@ -171,7 +182,7 @@ IE7FormPasswords.prototype = {
* @param {nsIURI[]} uris - the uris that are going to be migrated.
*/
_migrateURIs(uris) {
this.ctypesHelpers = new MSMigrationUtils.CtypesHelpers();
this.ctypesKernelHelpers = new MSMigrationUtils.CtypesKernelHelpers();
this._crypto = new OSCrypto();
let nsIWindowsRegKey = Ci.nsIWindowsRegKey;
let key = Cc["@mozilla.org/windows-registry-key;1"].
@ -240,7 +251,7 @@ IE7FormPasswords.prototype = {
key.close();
this._crypto.finalize();
this.ctypesHelpers.finalize();
this.ctypesKernelHelpers.finalize();
},
_crypto: null,
@ -250,52 +261,16 @@ IE7FormPasswords.prototype = {
* @param {Object[]} logins - array of the login details.
*/
_addLogins(ieLogins) {
function addLogin(login, existingLogins) {
// Add the login only if it doesn't already exist
// if the login is not already available, it s going to be added or merged with another
// login
if (existingLogins.some(l => login.matches(l, true))) {
return;
}
let isUpdate = false; // the login is just an update for an old one
for (let existingLogin of existingLogins) {
if (login.username == existingLogin.username && login.password != existingLogin.password) {
// if a login with the same username and different password already exists and it's older
// than the current one, that login needs to be updated using the current one details
if (login.timePasswordChanged > existingLogin.timePasswordChanged) {
// Bug 1187190: Password changes should be propagated depending on timestamps.
// the existing login password and timestamps should be updated
let propBag = Cc["@mozilla.org/hash-property-bag;1"].
createInstance(Ci.nsIWritablePropertyBag);
propBag.setProperty("password", login.password);
propBag.setProperty("timePasswordChanged", login.timePasswordChanged);
Services.logins.modifyLogin(existingLogin, propBag);
// make sure not to add the new login
isUpdate = true;
}
}
}
// if the new login is not an update, add it.
if (!isUpdate) {
Services.logins.addLogin(login);
}
}
for (let ieLogin of ieLogins) {
try {
let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
login.init(ieLogin.url, "", null,
ieLogin.username, ieLogin.password, "", "");
login.QueryInterface(Ci.nsILoginMetaInfo);
login.timeCreated = ieLogin.creation;
login.timeLastUsed = ieLogin.creation;
login.timePasswordChanged = ieLogin.creation;
// login.timesUsed is going to set to the default value 1
// Add the login only if there's not an existing entry
let existingLogins = Services.logins.findLogins({}, login.hostname, "", null);
addLogin(login, existingLogins);
// create a new login
let login = {
username: ieLogin.username,
password: ieLogin.password,
hostname: ieLogin.url,
timeCreated: ieLogin.creation,
};
LoginHelper.maybeImportLogin(login);
} catch (e) {
Cu.reportError(e);
}
@ -365,7 +340,7 @@ IE7FormPasswords.prototype = {
// Bytes 0-31 starting from currentInfoIndex contain the loginItem data structure for the
// current login
let currentLoginItem = currentLoginItemPointer.contents;
let creation = this.ctypesHelpers.
let creation = this.ctypesKernelHelpers.
fileTimeToSecondsSinceEpoch(currentLoginItem.hiDateTime,
currentLoginItem.loDateTime) * 1000;
let currentResult = {
@ -531,6 +506,10 @@ IEProfileMigrator.prototype.getResources = function IE_getResources() {
if (AppConstants.isPlatformAndVersionAtMost("win", "6.1")) {
resources.push(new IE7FormPasswords());
}
let windowsVaultFormPasswordsMigrator =
MSMigrationUtils.getWindowsVaultFormPasswordsMigrator();
windowsVaultFormPasswordsMigrator.name = "IEVaultFormPasswords";
resources.push(windowsVaultFormPasswordsMigrator);
return [r for each (r in resources) if (r.exists)];
};

View File

@ -8,10 +8,13 @@ this.EXPORTED_SYMBOLS = ["MSMigrationUtils"];
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
@ -24,43 +27,64 @@ const EDGE_COOKIE_PATH_OPTIONS = ["", "#!001\\", "#!002\\"];
const EDGE_COOKIES_SUFFIX = "MicrosoftEdge\\Cookies";
const EDGE_FAVORITES = "AC\\MicrosoftEdge\\User\\Default\\Favorites";
const EDGE_READINGLIST = "AC\\MicrosoftEdge\\User\\Default\\DataStore\\Data\\";
const FREE_CLOSE_FAILED = 0;
const INTERNET_EXPLORER_EDGE_GUID = [0x3CCD5499,
0x4B1087A8,
0x886015A2,
0x553BDD88];
const RESULT_SUCCESS = 0;
const VAULT_ENUMERATE_ALL_ITEMS = 512;
const WEB_CREDENTIALS_VAULT_ID = [0x4BF4C442,
0x41A09B8A,
0x4ADD80B3,
0x28DB4D70];
Cu.importGlobalProperties(["File"]);
////////////////////////////////////////////////////////////////////////////////
//// Helpers.
function CtypesHelpers() {
const wintypes = {
BOOL: ctypes.int,
DWORD: ctypes.uint32_t,
DWORDLONG: ctypes.uint64_t,
CHAR: ctypes.char,
PCHAR: ctypes.char.ptr,
LPCWSTR: ctypes.char16_t.ptr,
PDWORD: ctypes.uint32_t.ptr,
VOIDP: ctypes.voidptr_t,
WORD: ctypes.uint16_t,
}
// TODO: Bug 1202978 - Refactor MSMigrationUtils ctypes helpers
function CtypesKernelHelpers() {
this._structs = {};
this._functions = {};
this._libs = {};
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
const BOOL = ctypes.int;
this._structs.SYSTEMTIME = new ctypes.StructType('SYSTEMTIME', [
{wYear: WORD},
{wMonth: WORD},
{wDayOfWeek: WORD},
{wDay: WORD},
{wHour: WORD},
{wMinute: WORD},
{wSecond: WORD},
{wMilliseconds: WORD}
this._structs.SYSTEMTIME = new ctypes.StructType("SYSTEMTIME", [
{wYear: wintypes.WORD},
{wMonth: wintypes.WORD},
{wDayOfWeek: wintypes.WORD},
{wDay: wintypes.WORD},
{wHour: wintypes.WORD},
{wMinute: wintypes.WORD},
{wSecond: wintypes.WORD},
{wMilliseconds: wintypes.WORD}
]);
this._structs.FILETIME = new ctypes.StructType('FILETIME', [
{dwLowDateTime: DWORD},
{dwHighDateTime: DWORD}
this._structs.FILETIME = new ctypes.StructType("FILETIME", [
{dwLowDateTime: wintypes.DWORD},
{dwHighDateTime: wintypes.DWORD}
]);
try {
this._libs.kernel32 = ctypes.open("Kernel32");
this._functions.FileTimeToSystemTime =
this._libs.kernel32.declare("FileTimeToSystemTime",
ctypes.default_abi,
BOOL,
wintypes.BOOL,
this._structs.FILETIME.ptr,
this._structs.SYSTEMTIME.ptr);
} catch (ex) {
@ -68,7 +92,7 @@ function CtypesHelpers() {
}
}
CtypesHelpers.prototype = {
CtypesKernelHelpers.prototype = {
/**
* Must be invoked once after last use of any of the provided helpers.
*/
@ -83,7 +107,7 @@ CtypesHelpers.prototype = {
this._libs = {};
},
/**
/**
* Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct,
* and then deduces the number of seconds since the epoch (which
* is the data we want for the cookie expiry date).
@ -116,6 +140,135 @@ CtypesHelpers.prototype = {
}
};
function CtypesVaultHelpers() {
this._structs = {};
this._functions = {};
// the size of the vault handle in 32 bits version is 32 and 64 in 64 bits version
if (wintypes.VOIDP.size == 4) {
this._vaultHandleType = wintypes.DWORD;
} else {
this._vaultHandleType = wintypes.DWORDLONG;
}
this._structs.GUID = new ctypes.StructType("GUID", [
{id: wintypes.DWORD.array(4)},
]);
this._structs.VAULT_ITEM_ELEMENT = new ctypes.StructType("VAULT_ITEM_ELEMENT", [
// not documented
{schemaElementId: wintypes.DWORD},
// not documented
{unknown1: wintypes.DWORD},
// vault type
{type: wintypes.DWORD},
// not documented
{unknown2: wintypes.DWORD},
// value of the item
{itemValue: wintypes.LPCWSTR},
// not documented
{unknown3: wintypes.CHAR.array(12)},
]);
this._structs.VAULT_ELEMENT = new ctypes.StructType("VAULT_ELEMENT", [
// vault item schemaId
{schemaId: this._structs.GUID},
// a pointer to the name of the browser VAULT_ITEM_ELEMENT
{pszCredentialFriendlyName: wintypes.LPCWSTR},
// a pointer to the url VAULT_ITEM_ELEMENT
{pResourceElement: this._structs.VAULT_ITEM_ELEMENT.ptr},
// a pointer to the username VAULT_ITEM_ELEMENT
{pIdentityElement: this._structs.VAULT_ITEM_ELEMENT.ptr},
// not documented
{pAuthenticatorElement: this._structs.VAULT_ITEM_ELEMENT.ptr},
// not documented
{pPackageSid: this._structs.VAULT_ITEM_ELEMENT.ptr},
// time stamp in local format
{lowLastModified: wintypes.DWORD},
{highLastModified: wintypes.DWORD},
// not documented
{flags: wintypes.DWORD},
// not documented
{dwPropertiesCount: wintypes.DWORD},
// not documented
{pPropertyElements: this._structs.VAULT_ITEM_ELEMENT.ptr},
]);
try {
this._vaultcliLib = ctypes.open("vaultcli.dll");
this._functions.VaultOpenVault =
this._vaultcliLib.declare("VaultOpenVault",
ctypes.winapi_abi,
wintypes.DWORD,
// GUID
this._structs.GUID.ptr,
// Flags
wintypes.DWORD,
// Vault Handle
this._vaultHandleType.ptr);
this._functions.VaultEnumerateItems =
this._vaultcliLib.declare("VaultEnumerateItems",
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
this._vaultHandleType,
// Flags
wintypes.DWORD,
// Items Count
wintypes.PDWORD,
// Items
ctypes.voidptr_t);
this._functions.VaultCloseVault =
this._vaultcliLib.declare("VaultCloseVault",
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
this._vaultHandleType);
this._functions.VaultGetItem =
this._vaultcliLib.declare("VaultGetItem",
ctypes.winapi_abi,
wintypes.DWORD,
// Vault Handle
this._vaultHandleType,
// Schema Id
this._structs.GUID.ptr,
// Resource
this._structs.VAULT_ITEM_ELEMENT.ptr,
// Identity
this._structs.VAULT_ITEM_ELEMENT.ptr,
// Package Sid
this._structs.VAULT_ITEM_ELEMENT.ptr,
// HWND Owner
wintypes.DWORD,
// Flags
wintypes.DWORD,
// Items
this._structs.VAULT_ELEMENT.ptr.ptr);
this._functions.VaultFree =
this._vaultcliLib.declare("VaultFree",
ctypes.winapi_abi,
wintypes.DWORD,
// Memory
this._structs.VAULT_ELEMENT.ptr);
} catch (ex) {
this.finalize();
}
}
CtypesVaultHelpers.prototype = {
/**
* Must be invoked once after last use of any of the provided helpers.
*/
finalize() {
this._structs = {};
this._functions = {};
try {
this._vaultcliLib.close();
} catch (ex) {}
this._vaultcliLib = null;
}
}
/**
* Checks whether an host is an IP (v4 or v6) address.
*
@ -162,7 +315,7 @@ function getEdgeLocalDataFolder() {
Cu.reportError("Exception trying to find the Edge favorites directory: " + ex);
}
return null;
}
};
function Bookmarks(migrationType) {
@ -430,7 +583,7 @@ Cookies.prototype = {
},
migrate(aCallback) {
this.ctypesHelpers = new CtypesHelpers();
this.ctypesKernelHelpers = new CtypesKernelHelpers();
let cookiesGenerator = (function genCookie() {
let success = false;
@ -457,7 +610,7 @@ Cookies.prototype = {
}
}
this.ctypesHelpers.finalize();
this.ctypesKernelHelpers.finalize();
aCallback(success);
}).apply(this);
@ -533,7 +686,7 @@ Cookies.prototype = {
host = "." + host;
}
let expireTime = this.ctypesHelpers.fileTimeToSecondsSinceEpoch(Number(expireTimeHi),
let expireTime = this.ctypesKernelHelpers.fileTimeToSecondsSinceEpoch(Number(expireTimeHi),
Number(expireTimeLo));
Services.cookies.add(host,
path,
@ -547,15 +700,154 @@ Cookies.prototype = {
}
};
// Migrator for form passwords on Windows 8 and higher.
function WindowsVaultFormPasswords () {
}
WindowsVaultFormPasswords.prototype = {
type: MigrationUtils.resourceTypes.PASSWORDS,
get exists() {
// work only on windows 8+
if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2")) {
// check if there are passwords available for migration.
return this.migrate(() => {}, true);
}
return false;
},
/**
* If aOnlyCheckExists is false, import the form passwords on Windows 8 and higher from the vault
* and then call the aCallback.
* Otherwise, check if there are passwords in the vault.
* @param {function} aCallback - a callback called when the migration is done.
* @param {boolean} [aOnlyCheckExists=false] - if aOnlyCheckExists is true, just check if there are some
* passwords to migrate. Import the passwords from the vault and call aCallback otherwise.
* @return true if there are passwords in the vault and aOnlyCheckExists is set to true,
* false if there is no password in the vault and aOnlyCheckExists is set to true, undefined if
* aOnlyCheckExists is set to false.
*/
migrate(aCallback, aOnlyCheckExists = false) {
// check if the vault item is an IE/Edge one
function _isIEOrEdgePassword(id) {
return id[0] == INTERNET_EXPLORER_EDGE_GUID[0] &&
id[1] == INTERNET_EXPLORER_EDGE_GUID[1] &&
id[2] == INTERNET_EXPLORER_EDGE_GUID[2] &&
id[3] == INTERNET_EXPLORER_EDGE_GUID[3];
}
let ctypesVaultHelpers = new CtypesVaultHelpers();
let ctypesKernelHelpers = new CtypesKernelHelpers();
let migrationSucceeded = true;
let successfulVaultOpen = false;
let error, vault;
try {
// web credentials vault id
let vaultGuid = new ctypesVaultHelpers._structs.GUID(WEB_CREDENTIALS_VAULT_ID);
// number of available vaults
let vaultCount = new wintypes.DWORD;
error = new wintypes.DWORD;
// web credentials vault
vault = new ctypesVaultHelpers._vaultHandleType;
// open the current vault using the vaultGuid
error = ctypesVaultHelpers._functions.VaultOpenVault(vaultGuid.address(), 0, vault.address());
if (error != RESULT_SUCCESS) {
throw new Error("Unable to open Vault: " + error);
}
successfulVaultOpen = true;
let item = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr;
let itemCount = new wintypes.DWORD;
// enumerate all the available items. This api is going to return a table of all the
// available items and item is going to point to the first element of this table.
error = ctypesVaultHelpers._functions.VaultEnumerateItems(vault, VAULT_ENUMERATE_ALL_ITEMS,
itemCount.address(),
item.address());
if (error != RESULT_SUCCESS) {
throw new Error("Unable to enumerate Vault items: " + error);
}
for (let j = 0; j < itemCount.value; j++) {
try {
// if it's not an ie/edge password, skip it
if (!_isIEOrEdgePassword(item.contents.schemaId.id)) {
continue;
}
// if aOnlyCheckExists is set to true, the purpose of the call is to return true if there is at
// least a password which is true in this case because a password was by now already found
if (aOnlyCheckExists) {
return true;
}
let url = item.contents.pResourceElement.contents.itemValue.readString();
let username = item.contents.pIdentityElement.contents.itemValue.readString();
// the current login credential object
let credential = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr;
error = ctypesVaultHelpers._functions.VaultGetItem(vault,
item.contents.schemaId.address(),
item.contents.pResourceElement,
item.contents.pIdentityElement, null,
0, 0, credential.address());
if (error != RESULT_SUCCESS) {
throw new Error("Unable to get item: " + error);
}
let password = credential.contents.pAuthenticatorElement.contents.itemValue.readString();
let creation = ctypesKernelHelpers.
fileTimeToSecondsSinceEpoch(item.contents.highLastModified,
item.contents.lowLastModified) * 1000;
// create a new login
let login = {
username, password,
hostname: NetUtil.newURI(url).prePath,
timeCreated: creation,
};
LoginHelper.maybeImportLogin(login);
// close current item
error = ctypesVaultHelpers._functions.VaultFree(credential);
if (error == FREE_CLOSE_FAILED) {
throw new Error("Unable to free item: " + error);
}
} catch (e) {
migrationSucceeded = false;
Cu.reportError(e);
} finally {
// move to next item in the table returned by VaultEnumerateItems
item = item.increment();
}
}
} catch (e) {
Cu.reportError(e);
migrationSucceeded = false;
} finally {
if (successfulVaultOpen) {
// close current vault
error = ctypesVaultHelpers._functions.VaultCloseVault(vault);
if (error == FREE_CLOSE_FAILED) {
Cu.reportError("Unable to close vault: " + error);
}
}
ctypesKernelHelpers.finalize();
ctypesVaultHelpers.finalize();
aCallback(migrationSucceeded);
}
if (aOnlyCheckExists) {
return false;
}
}
};
var MSMigrationUtils = {
MIGRATION_TYPE_IE: 1,
MIGRATION_TYPE_EDGE: 2,
CtypesHelpers: CtypesHelpers,
CtypesKernelHelpers: CtypesKernelHelpers,
getBookmarksMigrator(migrationType = this.MIGRATION_TYPE_IE) {
return new Bookmarks(migrationType);
},
getCookiesMigrator(migrationType = this.MIGRATION_TYPE_IE) {
return new Cookies(migrationType);
},
getWindowsVaultFormPasswordsMigrator() {
return new WindowsVaultFormPasswords();
},
};

View File

@ -1,6 +1,7 @@
const EDGE_AVAILABLE_MIGRATIONS =
MigrationUtils.resourceTypes.COOKIES |
MigrationUtils.resourceTypes.BOOKMARKS;
MigrationUtils.resourceTypes.BOOKMARKS |
MigrationUtils.resourceTypes.PASSWORDS;
add_task(function* () {
let migrator = MigrationUtils.getMigrator("edge");

View File

@ -7,6 +7,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto",
"resource://gre/modules/OSCrypto.jsm");
const CRYPT_PROTECT_UI_FORBIDDEN = 1;
const IE7_FORM_PASSWORDS_MIGRATOR_NAME = "IE7FormPasswords";
const LOGINS_KEY = "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2";
const EXTENSION = "-backup";
const TESTED_WEBSITES = {
@ -273,7 +274,7 @@ function getFirstResourceOfType(type) {
.wrappedJSObject;
let migrators = migrator.getResources();
for (let m of migrators) {
if (m.type == type) {
if (m.name == IE7_FORM_PASSWORDS_MIGRATOR_NAME && m.type == type) {
return m;
}
}

View File

@ -2803,7 +2803,7 @@ var DefaultBrowserCheck = {
this._setAsDefaultButtonClickStartTime = Math.floor(Date.now() / 1000);
this._setAsDefaultTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._setAsDefaultTimer.init(function() {
this._setAsDefaultTimer.init(() => {
let isDefault = false;
let isDefaultError = false;
try {

View File

@ -61,15 +61,35 @@ var gSearchPane = {
this._initAutocomplete();
let urlbarSuggests = document.getElementById("urlBarSuggestion");
urlbarSuggests.hidden = !Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
let suggestsPref =
document.getElementById("browser.search.suggest.enabled");
suggestsPref.addEventListener("change", () => {
this.updateSuggestsCheckbox();
});
this.updateSuggestsCheckbox();
},
let suggestsPref = document.getElementById("browser.search.suggest.enabled")
let updateSuggestsCheckbox = () => {
urlbarSuggests.disabled = !suggestsPref.value;
updateSuggestsCheckbox() {
let urlbarSuggests = document.getElementById("urlBarSuggestion");
urlbarSuggests.hidden =
!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
let suggestsPref =
document.getElementById("browser.search.suggest.enabled");
let permanentPB =
Services.prefs.getBoolPref("browser.privatebrowsing.autostart");
urlbarSuggests.disabled = !suggestsPref.value || permanentPB;
let urlbarSuggestsPref =
document.getElementById("browser.urlbar.suggest.searches");
urlbarSuggests.checked = urlbarSuggestsPref.value;
if (urlbarSuggests.disabled) {
urlbarSuggests.checked = false;
}
suggestsPref.addEventListener("change", updateSuggestsCheckbox);
updateSuggestsCheckbox();
let permanentPBLabel =
document.getElementById("urlBarSuggestionPermanentPBLabel");
permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
},
buildDefaultEngineDropDown: function() {

View File

@ -41,12 +41,15 @@
label="&provideSearchSuggestions.label;"
accesskey="&provideSearchSuggestions.accesskey;"
preference="browser.search.suggest.enabled"/>
<hbox class="indent">
<vbox class="indent">
<checkbox id="urlBarSuggestion" label="&showURLBarSuggestions.label;"
hidden="true"
accesskey="&showURLBarSuggestions.accesskey;"
preference="browser.urlbar.suggest.searches"/>
</hbox>
<hbox id="urlBarSuggestionPermanentPBLabel"
align="center" class="indent">
<label flex="1">&urlBarSuggestionsPermanentPB.label;</label>
</hbox>
</vbox>
<checkbox id="redirectSearchCheckbox"
label="&redirectWindowsSearch.label;"
accesskey="&redirectWindowsSearch.accesskey;"

View File

@ -11,6 +11,7 @@
<!ENTITY showURLBarSuggestions.label "Show search suggestions in location bar results">
<!ENTITY showURLBarSuggestions.accesskey "l">
<!ENTITY urlBarSuggestionsPermanentPB.label "Search suggestions will not be shown in location bar results because you have configured &brandShortName; to never remember history.">
<!ENTITY redirectWindowsSearch.label "Use this search engine for searches from Windows">
<!ENTITY redirectWindowsSearch.accesskey "W">

View File

@ -18,6 +18,7 @@
#include "nsDOMNavigationTiming.h"
#include "nsGlobalWindow.h"
#include "nsJSUtils.h"
#include "nsNetUtil.h"
#include "nsPerformance.h"
#include "ScriptSettings.h"
#include "WorkerPrivate.h"
@ -34,6 +35,7 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIProgrammingLanguage.h"
#include "nsISensitiveInfoHiddenURI.h"
#include "nsIServiceManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIWebNavigation.h"
@ -1210,6 +1212,19 @@ Console::ProcessCallData(ConsoleCallData* aData)
event.mLevel = aData->mMethodString;
event.mFilename = frame.mFilename;
nsCOMPtr<nsIURI> filenameURI;
nsAutoCString pass;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(filenameURI), frame.mFilename)) &&
NS_SUCCEEDED(filenameURI->GetPassword(pass)) && !pass.IsEmpty()) {
nsCOMPtr<nsISensitiveInfoHiddenURI> safeURI = do_QueryInterface(filenameURI);
nsAutoCString spec;
if (safeURI &&
NS_SUCCEEDED(safeURI->GetSensitiveInfoHiddenSpec(spec))) {
CopyUTF8toUTF16(spec, event.mFilename);
}
}
event.mLineNumber = frame.mLineNumber;
event.mColumnNumber = frame.mColumnNumber;
event.mFunctionName = frame.mFunctionName;

View File

@ -6549,15 +6549,14 @@ var IdentityHandler = {
},
/**
* Return the eTLD+1 version of the current hostname
* Attempt to provide proper IDN treatment for host names
*/
getEffectiveHost: function getEffectiveHost() {
if (!this._IDNService)
this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
.getService(Ci.nsIIDNService);
try {
let baseDomain = Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname);
return this._IDNService.convertToDisplayIDN(baseDomain, {});
return this._IDNService.convertToDisplayIDN(this._uri.host, {});
} catch (e) {
// If something goes wrong (e.g. hostname is an IP address) just fail back
// to the full domain.

View File

@ -342,4 +342,64 @@ this.LoginHelper = {
}
return false;
},
/**
* Add the login to the password manager if a similar one doesn't already exist. Merge it
* otherwise with the similar existing ones.
* @param {Object} loginData - the data about the login that needs to be added.
*/
maybeImportLogin(loginData) {
// create a new login
let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
login.init(loginData.hostname,
loginData.submitURL || (typeof(loginData.httpRealm) == "string" ? null : ""),
typeof(loginData.httpRealm) == "string" ? loginData.httpRealm : null,
loginData.username,
loginData.password,
loginData.usernameElement || "",
loginData.passwordElement || "");
login.QueryInterface(Ci.nsILoginMetaInfo);
login.timeCreated = loginData.timeCreated;
login.timeLastUsed = loginData.timeLastUsed || loginData.timeCreated;
login.timePasswordChanged = loginData.timePasswordChanged || loginData.timeCreated;
login.timesUsed = loginData.timesUsed || 1;
// While here we're passing formSubmitURL and httpRealm, they could be empty/null and get
// ignored in that case, leading to multiple logins for the same username.
let existingLogins = Services.logins.findLogins({}, login.hostname,
login.formSubmitURL,
login.httpRealm);
// Add the login only if it doesn't already exist
// if the login is not already available, it's going to be added or merged with other
// logins
if (existingLogins.some(l => login.matches(l, true))) {
return;
}
// the login is just an update for an old one or the login is older than an existing one
let foundMatchingLogin = false;
for (let existingLogin of existingLogins) {
if (login.username == existingLogin.username) {
// Bug 1187190: Password changes should be propagated depending on timestamps.
// this an old login or a just an update, so make sure not to add it
foundMatchingLogin = true;
if(login.password != existingLogin.password &
login.timePasswordChanged > existingLogin.timePasswordChanged) {
// if a login with the same username and different password already exists and it's older
// than the current one, that login needs to be updated using the current one details
// the existing login password and timestamps should be updated
let propBag = Cc["@mozilla.org/hash-property-bag;1"].
createInstance(Ci.nsIWritablePropertyBag);
propBag.setProperty("password", login.password);
propBag.setProperty("timePasswordChanged", login.timePasswordChanged);
Services.logins.modifyLogin(existingLogin, propBag);
}
}
}
// if the new login is an update or is older than an exiting login, don't add it.
if (foundMatchingLogin) {
return;
}
Services.logins.addLogin(login);
}
};

View File

@ -7390,6 +7390,12 @@
"releaseChannelCollection": "opt-out",
"description": "The number of times that a profile has seen the 'Set Default Browser' dialog."
},
"BROWSER_SET_DEFAULT_ALWAYS_CHECK": {
"expires_in_version": "never",
"kind": "boolean",
"releaseChannelCollection": "opt-out",
"description": "True if the profile has `browser.shell.checkDefaultBrowser` set to true."
},
"BROWSER_SET_DEFAULT_RESULT": {
"expires_in_version": "never",
"kind": "enumerated",