import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1199466 - part 1 - Expose originAttributes in nsICookie, r=jduell (a2273aad63)
- Bug 1103314 - Clarify label of "Remove All Cookies" button to indicate whether it removes all cookies or just removes the cookies shown. r=dao (38c7786e15)
- Bug 1199466 - part 2 - Cookie manager in FF preferences should show the userContextId, r=paolo (74e7e421eb)
- Bug 1239606 - Implement UserContextUI.jsm, r=paolo (1d1edecfff)
- Bug 1244795 - adding a string for the default container under cookie manager, r=paolo (9a83def6c5)
- Bug 1244795 - adding a string for the default container under cookie manager, part 2, r=me (a2f6382fdb)
- Bug 1119747 - Fix up selected cookie count. r=dao (5bb5a63a26)
- Bug 1118226 - Allow to add number to string for removing selected cookies to improve localizability. r=dao (153d08797c)
- Bug 1243643 - Don't pass unsafe CPOWs to saveImageURL when offering to save media to disk. r=jld (4e3a0b9ea2)
- Bug 1244248: Cache the certificate database during startup rather than getting it everytime it is needed. r=rhelmer (aafe8e9820)
- Bug 1195353 - leave extension proxy files that point to invalid manifests r=mossop (4f1a82a3d7)
- Bug 1244357: Use a shim around the certificate DB to allow the add-ons manager to think that add-ons are signed when they aren't. r=rhelmer (e0e239a63c)
- Bug 1172724 - Use the "openas" verb to select the default HTTP handler on Windows 10. r=jaws, jimm (4488b9f0cb)
- Bug 791501 - Default Programs UI should select Firefox by default. r=jimm (722973de01)
- Bug 1238712 - Move duplicated shell-service code to a shared JSM. r=gijs (7d55c3dbe1)
- Bug 1039845 - Give nsWindowsShellService a private destructor; r=bjacob (cbba5f167b)
- Bug 1184508 - Remember registry hash for later use on Win8+. r=jimm (b6c6bbcbb7)
- Bug 1216150 - Split xpc::InitGlobalObject into an options-setting component and a global-object-modifying component, with the options-setting component being called before global object creation in all callers. r=bz (5393e6a522)
- Bug 1139849 - postMessage to incorrect target domain should print a console security error r=bz (df179f78cf)
- Bug 1236580 - Remove the IS_UNIFIED_TELEMETRY constant and the related preferences. r=gfritzsche (687c1f149e)
- Bug 920169 - Remove references to C++ constants in Histograms.json. r=gfritzsche (4f287dfbd9)
- Bug 1234526 - Don't track healthreport.sqlite statements from Telemetry. r=gfritzsche (aaf0e88c25)
- Bug 1241508 - Have TelemetryImpl::RecordIceCandidates check for mCanRecordExtended. r=drno (9729fdd17b)
This commit is contained in:
2023-12-15 13:52:19 +08:00
parent ef61aa708b
commit 47d0459001
65 changed files with 1227 additions and 419 deletions
+2
View File
@@ -1354,6 +1354,8 @@ pref("status4evar.status.toolbar.maxLength", 0);
pref("status4evar.status.popup.invertMirror", false);
pref("status4evar.status.popup.mouseMirror", true);
pref("privacy.trackingprotection.ui.enabled", false);
// How often to check for CPOW timeouts. CPOWs are only timed out by
// the hang monitor.
pref("dom.ipc.cpow.timeout", 500);
@@ -11,6 +11,9 @@ Cu.import("resource://gre/modules/Services.jsm");
const prefs = new Preferences("datareporting.healthreport.");
const PREF_UNIFIED = "toolkit.telemetry.unified";
const PREF_REPORTING_URL = "datareporting.healthreport.about.reportUrl";
var healthReportWrapper = {
init: function () {
let iframe = document.getElementById("remote-report");
@@ -28,7 +31,7 @@ var healthReportWrapper = {
},
_getReportURI: function () {
let url = Services.urlFormatter.formatURLPref("datareporting.healthreport.about.reportUrl");
let url = Services.urlFormatter.formatURLPref(PREF_REPORTING_URL);
return Services.io.newURI(url, null, null);
},
+1
View File
@@ -10,6 +10,7 @@ var Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NotificationDB.jsm");
Cu.import("resource:///modules/RecentWindow.jsm");
Cu.import("resource:///modules/UserContextUI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
+9 -4
View File
@@ -1121,6 +1121,8 @@ nsContextMenu.prototype = {
saveVideoFrameAsImage: function () {
let mm = this.browser.messageManager;
let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
let name = "";
if (this.mediaURL) {
try {
@@ -1141,7 +1143,8 @@ nsContextMenu.prototype = {
mm.removeMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage);
let dataURL = message.data.dataURL;
saveImageURL(dataURL, name, "SaveImageTitle", true, false,
document.documentURIObject, document);
document.documentURIObject, null, null, null,
isPrivate);
};
mm.addMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage);
},
@@ -1382,18 +1385,20 @@ nsContextMenu.prototype = {
saveMedia: function() {
let doc = this.ownerDoc;
let referrerURI = gContextMenuContentData.documentURIObject;
let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
if (this.onCanvas) {
// Bypass cache, since it's a data: URL.
this._canvasToDataURL(this.target).then(function(dataURL) {
saveImageURL(dataURL, "canvas.png", "SaveImageTitle",
true, false, referrerURI, doc);
true, false, referrerURI, null, null, null,
isPrivate);
}, Cu.reportError);
}
else if (this.onImage) {
urlSecurityCheck(this.mediaURL, this.principal);
saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
false, referrerURI, doc, gContextMenuContentData.contentType,
gContextMenuContentData.contentDisposition);
false, referrerURI, null, gContextMenuContentData.contentType,
gContextMenuContentData.contentDisposition, isPrivate);
}
else if (this.onVideo || this.onAudio) {
urlSecurityCheck(this.mediaURL, this.principal);
@@ -16,7 +16,6 @@ XPCOMUtils.defineLazyGetter(this, "gDatareportingService",
.wrappedJSObject);
const PREF_BRANCH = "datareporting.policy.";
const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled";
const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification";
const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion";
const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion";
@@ -108,13 +107,11 @@ let checkInfobarButton = Task.async(function* (aNotification) {
});
add_task(function* setup(){
const drsEnabled = Preferences.get(PREF_DRS_ENABLED, true);
const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true);
const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1);
// Register a cleanup function to reset our preferences.
registerCleanupFunction(() => {
Preferences.set(PREF_DRS_ENABLED, drsEnabled);
Preferences.set(PREF_BYPASS_NOTIFICATION, bypassNotification);
Preferences.set(PREF_CURRENT_POLICY_VERSION, currentPolicyVersion);
@@ -124,8 +121,6 @@ add_task(function* setup(){
return closeAllNotifications();
});
// Disable Healthreport/Data reporting service.
Preferences.set(PREF_DRS_ENABLED, false);
// Don't skip the infobar visualisation.
Preferences.set(PREF_BYPASS_NOTIFICATION, false);
// Set the current policy version.
+5 -7
View File
@@ -10,6 +10,9 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Components.utils.import("resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
"resource:///modules/ShellService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
@@ -466,15 +469,10 @@ function gatherTextUnder ( root )
return text;
}
// This function exists for legacy reasons.
function getShellService()
{
var shell = null;
try {
shell = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIShellService);
} catch (e) {
}
return shell;
return ShellService;
}
function isBidiEnabled() {
@@ -12,6 +12,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
"resource:///modules/ShellService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
"@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
@@ -604,6 +606,19 @@ nsBrowserContentHandler.prototype = {
var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam))
throw NS_ERROR_ABORT;
var isDefault = false;
try {
var url = Services.urlFormatter.formatURLPref("app.support.baseURL") +
"win10-default-browser";
if (urlParam == url) {
isDefault = ShellService.isDefaultBrowser(false, false);
}
} catch (ex) {}
if (isDefault) {
// Firefox is already the default HTTP handler.
// We don't have to show the instruction page.
throw NS_ERROR_ABORT;
}
cmdLine.handleFlag("osint", false)
}
},
+4 -11
View File
@@ -129,22 +129,15 @@ if (AppConstants.MOZ_CRASHREPORTER) {
XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
"resource:///modules/ReaderParent.jsm");
XPCOMUtils.defineLazyGetter(this, "ShellService", function() {
try {
return Cc["@mozilla.org/browser/shell-service;1"].
getService(Ci.nsIShellService);
}
catch(ex) {
return null;
}
});
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
"resource://gre/modules/ExtensionManagement.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
"resource:///modules/ShellService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "AlertsService",
"@mozilla.org/alerts-service;1", "nsIAlertsService");
@@ -1119,7 +1112,7 @@ BrowserGlue.prototype = {
if (AppConstants.E10S_TESTING_ONLY) {
E10SUINotification.checkStatus();
}
if (AppConstants.platform == "win") {
if (AppConstants.E10S_TESTING_ONLY && AppConstants.platform == "win") {
// Handles prompting to inform about incompatibilites when accessibility
// and e10s are active together.
E10SAccessibilityCheck.init();
+38 -25
View File
@@ -5,6 +5,10 @@
const nsICookie = Components.interfaces.nsICookie;
Components.utils.import("resource://gre/modules/PluralForm.jsm");
Components.utils.import("resource://gre/modules/Services.jsm")
Components.utils.import("resource:///modules/UserContextUI.jsm");
var gCookiesWindow = {
_cm : Components.classes["@mozilla.org/cookiemanager;1"]
.getService(Components.interfaces.nsICookieManager),
@@ -455,16 +459,17 @@ var gCookiesWindow = {
_makeCookieObject: function (aStrippedHost, aCookie) {
var host = aCookie.host;
var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host;
var c = { name : aCookie.name,
value : aCookie.value,
isDomain : aCookie.isDomain,
host : aCookie.host,
rawHost : aStrippedHost,
path : aCookie.path,
isSecure : aCookie.isSecure,
expires : aCookie.expires,
level : 1,
container : false };
var c = { name : aCookie.name,
value : aCookie.value,
isDomain : aCookie.isDomain,
host : aCookie.host,
rawHost : aStrippedHost,
path : aCookie.path,
isSecure : aCookie.isSecure,
expires : aCookie.expires,
level : 1,
container : false,
originAttributes: aCookie.originAttributes };
return c;
},
@@ -500,9 +505,17 @@ var gCookiesWindow = {
return this._bundle.getString("expireAtEndOfSession");
},
_getUserContextString: function(aUserContextId) {
if (parseInt(aUserContextId) == 0) {
return this._bundle.getString("defaultUserContextLabel");
}
return UserContextUI.getUserContextLabel(aUserContextId);
},
_updateCookieData: function (aItem) {
var seln = this._view.selection;
var ids = ["name", "value", "host", "path", "isSecure", "expires"];
var ids = ["name", "value", "host", "path", "isSecure", "expires", "userContext"];
var properties;
if (aItem && !aItem.container && seln.count > 0) {
@@ -511,24 +524,27 @@ var gCookiesWindow = {
isDomain: aItem.isDomain ? this._bundle.getString("domainColon")
: this._bundle.getString("hostColon"),
isSecure: aItem.isSecure ? this._bundle.getString("forSecureOnly")
: this._bundle.getString("forAnyConnection") };
for (var i = 0; i < ids.length; ++i)
: this._bundle.getString("forAnyConnection"),
userContext: this._getUserContextString(aItem.originAttributes.userContextId) };
for (var i = 0; i < ids.length; ++i) {
document.getElementById(ids[i]).disabled = false;
}
}
else {
var noneSelected = this._bundle.getString("noCookieSelected");
properties = { name: noneSelected, value: noneSelected, host: noneSelected,
path: noneSelected, expires: noneSelected,
isSecure: noneSelected };
for (i = 0; i < ids.length; ++i)
isSecure: noneSelected, userContext: noneSelected };
for (i = 0; i < ids.length; ++i) {
document.getElementById(ids[i]).disabled = true;
}
}
for (var property in properties)
document.getElementById(property).value = properties[property];
},
onCookieSelected: function () {
var properties, item;
var item;
var seln = this._tree.view.selection;
if (!this._view._filtered)
item = this._view._getItemAtIndex(seln.currentIndex);
@@ -545,22 +561,19 @@ var gCookiesWindow = {
for (var j = min.value; j <= max.value; ++j) {
item = this._view._getItemAtIndex(j);
if (!item) continue;
if (item.container && !item.open)
if (item.container)
selectedCookieCount += item.cookies.length;
else if (!item.container)
++selectedCookieCount;
}
}
var item = this._view._getItemAtIndex(seln.currentIndex);
if (item && seln.count == 1 && item.container && item.open)
selectedCookieCount += 2;
var removeCookie = document.getElementById("removeCookie");
var removeCookies = document.getElementById("removeCookies");
removeCookie.parentNode.selectedPanel =
selectedCookieCount == 1 ? removeCookie : removeCookies;
let buttonLabel = this._bundle.getString("removeSelectedCookies");
let removeSelectedCookies = document.getElementById("removeSelectedCookies");
removeSelectedCookies.label = PluralForm.get(selectedCookieCount, buttonLabel)
.replace("#1", selectedCookieCount);
removeCookie.disabled = removeCookies.disabled = !(seln.count > 0);
removeSelectedCookies.disabled = !(seln.count > 0);
},
performDeletion: function gCookiesWindow_performDeletion(deleteItems) {
+8 -9
View File
@@ -85,22 +85,21 @@
<hbox pack="end"><label id="expiresLabel" control="expires" value="&props.expires.label;"/></hbox>
<textbox id="expires" readonly="true" class="plain"/>
</row>
<row align="center" id="userContextRow">
<hbox pack="end"><label id="userContextLabel" control="userContext" value="&props.container.label;"/></hbox>
<textbox id="userContext" readonly="true" class="plain"/>
</row>
</rows>
</grid>
</hbox>
</vbox>
<hbox align="end">
<hbox class="actionButtons" flex="1">
<deck oncommand="gCookiesWindow.deleteCookie();">
<button id="removeCookie" disabled="true" icon="remove"
label="&button.removecookie.label;"
accesskey="&button.removecookie.accesskey;"/>
<button id="removeCookies" disabled="true" icon="remove"
label="&button.removecookies.label;"
accesskey="&button.removecookie.accesskey;"/>
</deck>
<button id="removeSelectedCookies" disabled="true" icon="clear"
accesskey="&button.removeSelectedCookies.accesskey;"
oncommand="gCookiesWindow.deleteCookie();"/>
<button id="removeAllCookies" disabled="true" icon="clear"
label="&button.removeallcookies.label;" accesskey="&button.removeallcookies.accesskey;"
label="&button.removeAllCookies.label;" accesskey="&button.removeAllCookies.accesskey;"
oncommand="gCookiesWindow.deleteAllCookies();"/>
<spacer flex="1"/>
#ifndef XP_MACOSX
+86
View File
@@ -0,0 +1,86 @@
/* 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";
this.EXPORTED_SYMBOLS = ["ShellService"];
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
/**
* Internal functionality to save and restore the docShell.allow* properties.
*/
let ShellServiceInternal = {
/**
* Used to determine whether or not to offer "Set as desktop background"
* functionality. Even if shell service is available it is not
* guaranteed that it is able to set the background for every desktop
* which is especially true for Linux with its many different desktop
* environments.
*/
get canSetDesktopBackground() {
if (AppConstants.platform == "win" ||
AppConstants.platform == "macosx") {
return true;
}
if (AppConstants.platform == "linux") {
if (this.shellService) {
let linuxShellService = this.shellService
.QueryInterface(Ci.nsIGNOMEShellService);
return linuxShellService.canSetDesktopBackground;
}
}
return false;
},
/**
* Used to determine whether or not to show a "Set Default Browser"
* query dialog. This attribute is true if the application is starting
* up and "browser.shell.checkDefaultBrowser" is true, otherwise it
* is false.
*/
_checkedThisSession: false,
get shouldCheckDefaultBrowser() {
// If we've already checked, the browser has been started and this is a
// new window open, and we don't want to check again.
if (this._checkedThisSession) {
return false;
}
return Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser");
},
set shouldCheckDefaultBrowser(shouldCheck) {
Services.prefs.setBoolPref("browser.shell.checkDefaultBrowser", !!shouldCheck);
},
isDefaultBrowser(startupCheck, forAllTypes) {
// If this is the first browser window, maintain internal state that we've
// checked this session (so that subsequent window opens don't show the
// default browser dialog).
if (startupCheck) {
this._checkedThisSession = true;
}
if (this.shellService) {
return this.shellService.isDefaultBrowser(startupCheck, forAllTypes);
}
}
};
XPCOMUtils.defineLazyServiceGetter(ShellServiceInternal, "shellService",
"@mozilla.org/browser/shell-service;1", Ci.nsIShellService);
/**
* The external API exported by this module.
*/
this.ShellService = new Proxy(ShellServiceInternal, {
get(target, name) {
return name in target ? target[name] :
target.shellService[name];
}
});
+8
View File
@@ -20,6 +20,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
XPIDL_SOURCES += [
'nsIMacShellService.idl',
]
elif CONFIG['MOZ_WIDGET_GTK']:
XPIDL_SOURCES += [
'nsIGNOMEShellService.idl',
]
XPIDL_MODULE = 'shellservice'
@@ -44,6 +48,10 @@ EXTRA_COMPONENTS += [
'nsSetDefaultBrowser.manifest',
]
EXTRA_JS_MODULES += [
'ShellService.jsm',
]
for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION'):
DEFINES[var] = '"%s"' % CONFIG[var]
@@ -117,7 +117,7 @@ nsGNOMEShellService::Init()
return appPath->GetNativePath(mAppPath);
}
NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIShellService)
NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService)
bool
nsGNOMEShellService::GetAppPathFromLauncher()
@@ -201,8 +201,6 @@ nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck,
bool* aIsDefaultBrowser)
{
*aIsDefaultBrowser = false;
if (aStartupCheck)
mCheckedThisSession = true;
nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
@@ -325,37 +323,6 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes,
return NS_OK;
}
NS_IMETHODIMP
nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
// If we've already checked, the browser has been started and this is a
// new window open, and we don't want to check again.
if (mCheckedThisSession) {
*aResult = false;
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
}
NS_IMETHODIMP
nsGNOMEShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
}
NS_IMETHODIMP
nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult)
{
@@ -6,17 +6,18 @@
#ifndef nsgnomeshellservice_h____
#define nsgnomeshellservice_h____
#include "nsIShellService.h"
#include "nsIGNOMEShellService.h"
#include "nsStringAPI.h"
#include "mozilla/Attributes.h"
class nsGNOMEShellService final : public nsIShellService
class nsGNOMEShellService final : public nsIGNOMEShellService
{
public:
nsGNOMEShellService() : mCheckedThisSession(false), mAppIsInPath(false) { }
nsGNOMEShellService() : mAppIsInPath(false) { }
NS_DECL_ISUPPORTS
NS_DECL_NSISHELLSERVICE
NS_DECL_NSIGNOMESHELLSERVICE
nsresult Init();
@@ -27,7 +28,6 @@ private:
bool CheckHandlerMatchesAppName(const nsACString& handler) const;
bool GetAppPathFromLauncher();
bool mCheckedThisSession;
bool mUseLocaleFilenames;
nsCString mAppPath;
bool mAppIsInPath;
@@ -0,0 +1,19 @@
/* 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/. */
#include "nsIShellService.idl"
[scriptable, uuid(2ce5c803-edcd-443d-98eb-ceba86d02d13)]
interface nsIGNOMEShellService : nsIShellService
{
/**
* Used to determine whether or not to offer "Set as desktop background"
* functionality. Even if shell service is available it is not
* guaranteed that it is able to set the background for every desktop
* which is especially true for Linux with its many different desktop
* environments.
*/
readonly attribute boolean canSetDesktopBackground;
};
@@ -5,7 +5,7 @@
#include "nsIShellService.idl"
[scriptable, uuid(291a27cd-ef4c-46c6-a2f8-83182498167e)]
[scriptable, uuid(387fdc80-0077-4b60-a0d9-d9e80a83ba64)]
interface nsIMacShellService : nsIShellService
{
const long APPLICATION_KEYCHAIN_ACCESS = 2;
+1 -18
View File
@@ -8,7 +8,7 @@
interface nsIDOMElement;
interface nsIFile;
[scriptable, uuid(53f4bc4a-5b86-4643-8e67-4907ecbab34c)]
[scriptable, uuid(2d1a95e4-5bd8-4eeb-b0a8-c1455fd2a357)]
interface nsIShellService : nsISupports
{
/**
@@ -38,23 +38,6 @@ interface nsIShellService : nsISupports
*/
void setDefaultBrowser(in boolean aClaimAllTypes, in boolean aForAllUsers);
/**
* Used to determine whether or not to show a "Set Default Browser"
* query dialog. This attribute is true if the application is starting
* up and "browser.shell.checkDefaultBrowser" is true, otherwise it
* is false.
*/
attribute boolean shouldCheckDefaultBrowser;
/**
* Used to determine whether or not to offer "Set as desktop background"
* functionality. Even if shell service is available it is not
* guaranteed that it is able to set the background for every desktop
* which is especially true for Linux with its many different desktop
* environments.
*/
readonly attribute boolean canSetDesktopBackground;
/**
* Flags for positioning/sizing of the Desktop Background image.
*/
@@ -5,7 +5,7 @@
#include "nsIShellService.idl"
[scriptable, uuid(13f20725-4fd5-431f-90a1-525ab31755b1)]
[scriptable, uuid(f8a26b94-49e5-4441-8fbc-315e0b4f22ef)]
interface nsIWindowsShellService : nsIShellService
{
/**
@@ -57,12 +57,6 @@ nsMacShellService::IsDefaultBrowser(bool aStartupCheck,
::CFRelease(defaultBrowserID);
}
// If this is the first browser window, maintain internal state that we've
// checked this session (so that subsequent window opens don't show the
// default browser dialog).
if (aStartupCheck)
mCheckedThisSession = true;
return NS_OK;
}
@@ -103,44 +97,6 @@ nsMacShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
return NS_OK;
}
NS_IMETHODIMP
nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
// If we've already checked, the browser has been started and this is a
// new window open, and we don't want to check again.
if (mCheckedThisSession) {
*aResult = false;
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
}
NS_IMETHODIMP
nsMacShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
}
NS_IMETHODIMP
nsMacShellService::GetCanSetDesktopBackground(bool* aResult)
{
*aResult = true;
return NS_OK;
}
NS_IMETHODIMP
nsMacShellService::SetDesktopBackground(nsIDOMElement* aElement,
int32_t aPosition)
+1 -3
View File
@@ -15,7 +15,7 @@ class nsMacShellService : public nsIMacShellService,
public nsIWebProgressListener
{
public:
nsMacShellService() : mCheckedThisSession(false) {};
nsMacShellService() {};
NS_DECL_ISUPPORTS
NS_DECL_NSISHELLSERVICE
@@ -27,8 +27,6 @@ protected:
private:
nsCOMPtr<nsIFile> mBackgroundFile;
bool mCheckedThisSession;
};
#endif // nsmacshellservice_h____
@@ -2,13 +2,14 @@
* 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/. */
/*
/*
* --setDefaultBrowser commandline handler
* Makes the current executable the "default browser".
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
Components.utils.import("resource:///modules/ShellService.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function nsSetDefaultBrowser() {}
@@ -16,9 +17,7 @@ function nsSetDefaultBrowser() {}
nsSetDefaultBrowser.prototype = {
handle: function nsSetDefault_handle(aCmdline) {
if (aCmdline.handleFlag("setDefaultBrowser", false)) {
var shell = Cc["@mozilla.org/browser/shell-service;1"].
getService(Ci.nsIShellService);
shell.setDefaultBrowser(true, true);
ShellService.setDefaultBrowser(true, true);
}
},
+314 -128
View File
@@ -3,6 +3,8 @@
* 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/. */
#include "nsWindowsShellService.h"
#include "imgIContainer.h"
#include "imgIRequest.h"
#include "mozilla/gfx/2D.h"
@@ -17,7 +19,6 @@
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsShellService.h"
#include "nsWindowsShellService.h"
#include "nsIProcess.h"
#include "nsICategoryManager.h"
#include "nsBrowserCompsCID.h"
@@ -28,6 +29,7 @@
#include "nsUnicharUtils.h"
#include "nsIWinTaskbar.h"
#include "nsISupportsPrimitives.h"
#include "nsIURLFormatter.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "mozilla/WindowsVersion.h"
@@ -84,6 +86,38 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
return NS_OK;
}
static bool
GetPrefString(const nsCString& aPrefName, nsAString& aValue)
{
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefs) {
return false;
}
nsAutoCString prefCStr;
nsresult rv = prefs->GetCharPref(aPrefName.get(),
getter_Copies(prefCStr));
if (NS_FAILED(rv)) {
return false;
}
CopyUTF8toUTF16(prefCStr, aValue);
return true;
}
static bool
SetPrefString(const nsCString& aPrefName, const nsString& aValue)
{
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefs) {
return false;
}
nsresult rv = prefs->SetCharPref(aPrefName.get(),
NS_ConvertUTF16toUTF8(aValue).get());
return NS_SUCCEEDED(rv);
}
///////////////////////////////////////////////////////////////////////////////
// Default Browser Registry Settings
//
@@ -321,38 +355,219 @@ nsWindowsShellService::ShortcutMaintenance()
}
static bool
IsAARDefaultHTTP(IApplicationAssociationRegistration* pAAR,
bool* aIsDefaultBrowser)
IsAARDefault(const RefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
// Make sure the Prog ID matches what we have
LPWSTR registeredApp;
HRESULT hr = pAAR->QueryCurrentDefault(L"http", AT_URLPROTOCOL, AL_EFFECTIVE,
bool isProtocol = *aClassName != L'.';
ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION;
HRESULT hr = pAAR->QueryCurrentDefault(aClassName, queryType, AL_EFFECTIVE,
&registeredApp);
if (SUCCEEDED(hr)) {
LPCWSTR firefoxHTTPProgID = L"PaleMoonURL";
*aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTTPProgID);
CoTaskMemFree(registeredApp);
} else {
*aIsDefaultBrowser = false;
if (FAILED(hr)) {
return false;
}
return SUCCEEDED(hr);
LPCWSTR progID = isProtocol ? L"FirefoxURL" : L"FirefoxHTML";
bool isDefault = !wcsicmp(registeredApp, progID);
CoTaskMemFree(registeredApp);
return isDefault;
}
static void
GetUserChoiceKeyName(LPCWSTR aClassName, bool aIsProtocol,
nsAString& aKeyName)
{
aKeyName.AssignLiteral(aIsProtocol
? "Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
: "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
aKeyName.Append(aClassName);
aKeyName.AppendLiteral("\\UserChoice");
}
static void
GetHashPrefName(LPCWSTR aClassName, nsACString& aPrefName)
{
aPrefName.AssignLiteral("browser.shell.associationHash.");
aPrefName.Append(NS_ConvertUTF16toUTF8(*aClassName == L'.' ? aClassName + 1
: aClassName));
}
static bool
IsAARDefaultHTML(IApplicationAssociationRegistration* pAAR,
bool* aIsDefaultBrowser)
SaveWin8RegistryHash(const RefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
LPWSTR registeredApp;
HRESULT hr = pAAR->QueryCurrentDefault(L".html", AT_FILEEXTENSION, AL_EFFECTIVE,
&registeredApp);
if (SUCCEEDED(hr)) {
LPCWSTR firefoxHTMLProgID = L"PaleMoonHTML";
*aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTMLProgID);
CoTaskMemFree(registeredApp);
} else {
*aIsDefaultBrowser = false;
bool isProtocol = *aClassName != L'.';
bool isDefault = IsAARDefault(pAAR, aClassName);
// We can save the value only if ArctiFox is the default.
if (!isDefault) {
return isDefault;
}
return SUCCEEDED(hr);
nsAutoString keyName;
GetUserChoiceKeyName(aClassName, isProtocol, keyName);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) {
return isDefault;
}
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
keyName, nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
return isDefault;
}
nsAutoString hash;
rv = regKey->ReadStringValue(NS_LITERAL_STRING("Hash"), hash);
if (NS_FAILED(rv)) {
return isDefault;
}
nsAutoCString prefName;
GetHashPrefName(aClassName, prefName);
SetPrefString(prefName, hash);
return isDefault;
}
static bool
RestoreWin8RegistryHash(const RefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
nsAutoCString prefName;
GetHashPrefName(aClassName, prefName);
nsAutoString hash;
if (!GetPrefString(prefName, hash)) {
return false;
}
bool isProtocol = *aClassName != L'.';
nsString progId = isProtocol ? NS_LITERAL_STRING("ArcticFoxURL")
: NS_LITERAL_STRING("ArcticFoxHTML");
nsAutoString keyName;
GetUserChoiceKeyName(aClassName, isProtocol, keyName);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) {
return false;
}
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
keyName, nsIWindowsRegKey::ACCESS_READ);
if (NS_SUCCEEDED(rv)) {
nsAutoString currValue;
if (NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("Hash"),
currValue)) &&
currValue.Equals(hash) &&
NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("ProgId"),
currValue)) &&
currValue.Equals(progId)) {
// The value is already set.
return true;
}
// We need to close this explicitly because nsIWindowsRegKey::SetKey
// does not close the old key.
regKey->Close();
}
// We have to use the registry function directly because
// nsIWindowsRegKey::Create will only return NS_ERROR_FAILURE
// on failure.
HKEY theKey;
DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0,
KEY_READ | KEY_SET_VALUE, &theKey);
if (REG_FAILED(res)) {
if (res != ERROR_ACCESS_DENIED && res != ERROR_FILE_NOT_FOUND) {
return false;
}
if (res == ERROR_ACCESS_DENIED) {
res = ::RegDeleteKeyW(HKEY_CURRENT_USER, keyName.get());
if (REG_FAILED(res)) {
return false;
}
}
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, keyName.get(), 0,
nullptr, 0, KEY_READ | KEY_SET_VALUE,
nullptr, &theKey, nullptr);
if (REG_FAILED(res)) {
return false;
}
}
regKey->SetKey(theKey);
rv = regKey->WriteStringValue(NS_LITERAL_STRING("Hash"), hash);
if (NS_FAILED(rv)) {
return false;
}
rv = regKey->WriteStringValue(NS_LITERAL_STRING("ProgId"), progId);
if (NS_FAILED(rv)) {
return false;
}
return IsAARDefault(pAAR, aClassName);
}
static void
SaveWin8RegistryHashes(bool aCheckAllTypes, bool* aIsDefaultBrowser)
{
RefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return;
}
bool res = SaveWin8RegistryHash(pAAR, L"http");
if (*aIsDefaultBrowser) {
*aIsDefaultBrowser = res;
}
SaveWin8RegistryHash(pAAR, L"https");
SaveWin8RegistryHash(pAAR, L"ftp");
res = SaveWin8RegistryHash(pAAR, L".html");
if (*aIsDefaultBrowser && aCheckAllTypes) {
*aIsDefaultBrowser = res;
}
SaveWin8RegistryHash(pAAR, L".htm");
SaveWin8RegistryHash(pAAR, L".shtml");
SaveWin8RegistryHash(pAAR, L".xhtml");
SaveWin8RegistryHash(pAAR, L".xht");
}
static bool
RestoreWin8RegistryHashes(bool aClaimAllTypes)
{
RefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return false;
}
bool res = RestoreWin8RegistryHash(pAAR, L"http");
res = RestoreWin8RegistryHash(pAAR, L"https") && res;
RestoreWin8RegistryHash(pAAR, L"ftp");
bool res2 = RestoreWin8RegistryHash(pAAR, L".html");
res2 = RestoreWin8RegistryHash(pAAR, L".htm") && res2;
if (aClaimAllTypes) {
res = res && res2;
}
RestoreWin8RegistryHash(pAAR, L".shtml");
RestoreWin8RegistryHash(pAAR, L".xhtml");
RestoreWin8RegistryHash(pAAR, L".xht");
return res;
}
/*
@@ -365,37 +580,27 @@ bool
nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
bool* aIsDefaultBrowser)
{
IApplicationAssociationRegistration* pAAR;
RefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
(void**)&pAAR);
if (SUCCEEDED(hr)) {
if (aCheckAllTypes) {
BOOL res;
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
APP_REG_NAME,
&res);
*aIsDefaultBrowser = res;
// If we have all defaults, let's make sure that our ProgID
// is explicitly returned as well. Needed only for Windows 8.
if (*aIsDefaultBrowser && IsWin8OrLater()) {
IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
if (*aIsDefaultBrowser) {
IsAARDefaultHTML(pAAR, aIsDefaultBrowser);
}
}
} else {
IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
}
pAAR->Release();
return true;
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return false;
}
return false;
if (aCheckAllTypes) {
BOOL res;
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
APP_REG_NAME,
&res);
*aIsDefaultBrowser = res;
} else if (!IsWin8OrLater()) {
*aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
}
return true;
}
NS_IMETHODIMP
@@ -403,12 +608,6 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
bool aForAllTypes,
bool* aIsDefaultBrowser)
{
// If this is the first browser window, maintain internal state that we've
// checked this session (so that subsequent window opens don't show the
// default browser dialog).
if (aStartupCheck)
mCheckedThisSession = true;
// Assume we're the default unless one of the several checks below tell us
// otherwise.
*aIsDefaultBrowser = true;
@@ -494,7 +693,9 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
// Only check if PaleMoon is the default browser on Vista and above if the
// previous checks show that PaleMoon is the default browser.
if (*aIsDefaultBrowser) {
IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser);
if (IsWin8OrLater()) {
SaveWin8RegistryHashes(aForAllTypes, aIsDefaultBrowser);
}
}
// To handle the case where DDE isn't disabled due for a user because there
@@ -599,13 +800,6 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
return NS_OK;
}
NS_IMETHODIMP
nsWindowsShellService::GetCanSetDesktopBackground(bool* aResult)
{
*aResult = true;
return NS_OK;
}
static nsresult
DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
{
@@ -632,34 +826,19 @@ DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
}
nsresult
nsWindowsShellService::LaunchControlPanelDefaultPrograms()
nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI()
{
// Build the path control.exe path safely
WCHAR controlEXEPath[MAX_PATH + 1] = { '\0' };
if (!GetSystemDirectoryW(controlEXEPath, MAX_PATH)) {
return NS_ERROR_FAILURE;
IApplicationAssociationRegistrationUI* pAARUI;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI,
NULL,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistrationUI,
(void**)&pAARUI);
if (SUCCEEDED(hr)) {
hr = pAARUI->LaunchAdvancedAssociationUI(APP_REG_NAME);
pAARUI->Release();
}
LPCWSTR controlEXE = L"control.exe";
if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) {
return NS_ERROR_FAILURE;
}
if (!PathAppendW(controlEXEPath, controlEXE)) {
return NS_ERROR_FAILURE;
}
WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram";
STARTUPINFOW si = {sizeof(si), 0};
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWDEFAULT;
PROCESS_INFORMATION pi = {0};
if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
0, nullptr, nullptr, &si, &pi)) {
return NS_ERROR_FAILURE;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return NS_OK;
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
@@ -684,6 +863,36 @@ nsWindowsShellService::LaunchModernSettingsDialogDefaultApps()
return NS_OK;
}
nsresult
nsWindowsShellService::InvokeHTTPOpenAsVerb()
{
nsCOMPtr<nsIURLFormatter> formatter(
do_GetService("@mozilla.org/toolkit/URLFormatterService;1"));
if (!formatter) {
return NS_ERROR_UNEXPECTED;
}
nsString urlStr;
nsresult rv = formatter->FormatURLPref(
NS_LITERAL_STRING("app.support.baseURL"), urlStr);
if (NS_FAILED(rv)) {
return rv;
}
if (!StringBeginsWith(urlStr, NS_LITERAL_STRING("https://"))) {
return NS_ERROR_FAILURE;
}
urlStr.AppendLiteral("win10-default-browser");
SHELLEXECUTEINFOW seinfo = { sizeof(SHELLEXECUTEINFOW) };
seinfo.lpVerb = L"openas";
seinfo.lpFile = urlStr.get();
seinfo.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&seinfo)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsWindowsShellService::LaunchHTTPHandlerPane()
{
@@ -710,13 +919,22 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
}
nsresult rv = LaunchHelper(appHelperPath);
if (NS_SUCCEEDED(rv) && IsWin8OrLater()) {
if (NS_SUCCEEDED(rv) && IsWin8OrLater() &&
!RestoreWin8RegistryHashes(aClaimAllTypes)) {
if (aClaimAllTypes) {
rv = LaunchControlPanelDefaultPrograms();
if (IsWin10OrLater()) {
rv = LaunchModernSettingsDialogDefaultApps();
} else {
rv = LaunchControlPanelDefaultsSelectionUI();
}
// The above call should never really fail, but just in case
// fall back to showing the HTTP association screen only.
if (NS_FAILED(rv)) {
rv = LaunchHTTPHandlerPane();
if (IsWin10OrLater()) {
rv = InvokeHTTPOpenAsVerb();
} else {
rv = LaunchHTTPHandlerPane();
}
}
} else {
// Windows 10 blocks attempts to load the
@@ -730,8 +948,10 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
// The above call should never really fail, but just in case
// fall back to showing control panel for all defaults
if (NS_FAILED(rv)) {
rv = LaunchControlPanelDefaultPrograms();
rv = LaunchControlPanelDefaultsSelectionUI();
}
bool isDefault;
SaveWin8RegistryHashes(aClaimAllTypes, &isDefault);
}
}
@@ -746,39 +966,6 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
return rv;
}
NS_IMETHODIMP
nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// If we've already checked, the browser has been started and this is a
// new window open, and we don't want to check again.
if (mCheckedThisSession) {
*aResult = false;
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
}
NS_IMETHODIMP
nsWindowsShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
return prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
}
static nsresult
WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
{
@@ -1120,8 +1307,7 @@ nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor)
return regKey->Close();
}
nsWindowsShellService::nsWindowsShellService() :
mCheckedThisSession(false)
nsWindowsShellService::nsWindowsShellService()
{
}
@@ -16,9 +16,10 @@
class nsWindowsShellService : public nsIWindowsShellService
{
virtual ~nsWindowsShellService();
public:
nsWindowsShellService();
virtual ~nsWindowsShellService();
NS_DECL_ISUPPORTS
NS_DECL_NSISHELLSERVICE
@@ -26,12 +27,10 @@ public:
protected:
bool IsDefaultBrowserVista(bool aCheckAllTypes, bool* aIsDefaultBrowser);
nsresult LaunchControlPanelDefaultPrograms();
nsresult LaunchControlPanelDefaultsSelectionUI();
nsresult LaunchModernSettingsDialogDefaultApps();
nsresult InvokeHTTPOpenAsVerb();
nsresult LaunchHTTPHandlerPane();
private:
bool mCheckedThisSession;
};
#endif // nswindowsshellservice_h____
@@ -0,0 +1,7 @@
Components.utils.import("resource:///modules/ShellService.jsm");
function test() {
ShellService.setDefaultBrowser(true, false);
ok(ShellService.isDefaultBrowser(true, false), "we got here and are the default browser");
ok(ShellService.isDefaultBrowser(true, true), "we got here and are the default browser");
}
@@ -650,6 +650,24 @@ e10s.accessibilityNotice.acceptButton.accesskey = O
e10s.accessibilityNotice.enableAndRestart.label = Enable (Requires Restart)
e10s.accessibilityNotice.enableAndRestart.accesskey = E
# LOCALIZATION NOTE (usercontext.personal.label,
# usercontext.work.label,
# usercontext.shopping.label,
# usercontext.banking.label):
# These strings specify the four predefined contexts included in support of the
# Contextual Identity / Containers project. Each context is meant to represent
# the context that the user is in when interacting with the site. Different
# contexts will store cookies and other information from those sites in
# different, isolated locations. You can enable the feature by typing
# about:config in the URL bar and changing privacy.userContext.enabled to true.
# Once enabled, you can open a new tab in a specific context by clicking
# File > New Container Tab > (1 of 4 contexts). Once opened, you will see these
# strings on the right-hand side of the URL bar.
usercontext.personal.label = Personal
usercontext.work.label = Work
usercontext.shopping.label = Shopping
usercontext.banking.label = Banking
muteTab.label = Mute Tab
muteTab.accesskey = M
unmuteTab.label = Unmute Tab
@@ -7,11 +7,13 @@
<!ENTITY cookiesonsystem.label "The following cookies are stored on your computer:">
<!ENTITY cookiename.label "Cookie Name">
<!ENTITY cookiedomain.label "Site">
<!ENTITY button.removecookies.label "Remove Cookies">
<!ENTITY button.removecookie.label "Remove Cookie">
<!ENTITY button.removecookie.accesskey "R">
<!ENTITY button.removeallcookies.label "Remove All Cookies">
<!ENTITY button.removeallcookies.accesskey "A">
<!-- LOCALIZATION NOTE (button.removeSelectedCookies.accesskey):
The label associated with this accesskey can be found in
preferences.properties as removeSelectedCookies.
-->
<!ENTITY button.removeSelectedCookies.accesskey "R">
<!ENTITY button.removeAllCookies.label "Remove All">
<!ENTITY button.removeAllCookies.accesskey "A">
<!ENTITY props.name.label "Name:">
<!ENTITY props.value.label "Content:">
@@ -19,6 +21,7 @@
<!ENTITY props.path.label "Path:">
<!ENTITY props.secure.label "Send For:">
<!ENTITY props.expires.label "Expires:">
<!ENTITY props.container.label "Container:">
<!ENTITY window.title "Cookies">
<!ENTITY windowClose.key "w">
@@ -92,6 +92,15 @@ cannot=Block
noCookieSelected=<no cookie selected>
cookiesAll=The following cookies are stored on your computer:
cookiesFiltered=The following cookies match your search:
# LOCALIZATION NOTE (removeSelectedCookies):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# If you need to display the number of selected elements in your language,
# you can use #1 in your localization as a placeholder for the number.
# For example this is the English string with numbers:
# removeSelectedCookied=Remove #1 Selected;Remove #1 Selected
removeSelectedCookies=Remove Selected;Remove Selected
defaultUserContextLabel=None
#### Offline apps
offlineAppRemoveTitle=Remove offline website data
+32
View File
@@ -0,0 +1,32 @@
/* 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/. */
this.EXPORTED_SYMBOLS = ["UserContextUI"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm")
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
return Services.strings.createBundle("chrome://browser/locale/browser.properties");
});
this.UserContextUI = {
getUserContextLabel(userContextId) {
switch (userContextId) {
// No UserContext:
case 0: return "";
case 1: return gBrowserBundle.GetStringFromName("usercontext.personal.label");
case 2: return gBrowserBundle.GetStringFromName("usercontext.work.label");
case 3: return gBrowserBundle.GetStringFromName("usercontext.shopping.label");
case 4: return gBrowserBundle.GetStringFromName("usercontext.banking.label");
// Display the context IDs for values outside the pre-defined range.
// Used for debugging, no localization necessary.
default: return "Context " + userContextId;
}
}
}
+1
View File
@@ -40,6 +40,7 @@ EXTRA_JS_MODULES += [
'TabCrashReporter.jsm',
'TabGroupsMigrator.jsm',
'TransientPrefs.jsm',
'UserContextUI.jsm',
'WebappManager.jsm',
'webrtcUI.jsm',
]
+22
View File
@@ -30,6 +30,7 @@ PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
const nsAString& aCallerOrigin,
nsGlobalWindow* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
nsIDocument* aSourceDocument,
bool aTrustedCaller)
: StructuredCloneHolder(CloningSupported, TransferringSupported,
SameProcessSameThread),
@@ -37,6 +38,7 @@ PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
mCallerOrigin(aCallerOrigin),
mTargetWindow(aTargetWindow),
mProvidedPrincipal(aProvidedPrincipal),
mSourceDocument(aSourceDocument),
mTrustedCaller(aTrustedCaller)
{
MOZ_COUNT_CTOR(PostMessageEvent);
@@ -59,6 +61,12 @@ PostMessageEvent::Run()
jsapi.Init();
JSContext* cx = jsapi.cx();
// The document is just used for the principal mismatch error message below.
// Use a stack variable so mSourceDocument is not held onto after this method
// finishes, regardless of the method outcome.
nsCOMPtr<nsIDocument> sourceDocument;
sourceDocument.swap(mSourceDocument);
// If we bailed before this point we're going to leak mMessage, but
// that's probably better than crashing.
@@ -94,6 +102,20 @@ PostMessageEvent::Run()
// now. Long-term, we want HTML5 to address this so that we can
// be compliant while being safer.
if (!targetPrin->Equals(mProvidedPrincipal)) {
nsAutoString providedOrigin, targetOrigin;
nsresult rv = nsContentUtils::GetUTFOrigin(targetPrin, targetOrigin);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsContentUtils::GetUTFOrigin(mProvidedPrincipal, providedOrigin);
NS_ENSURE_SUCCESS(rv, rv);
const char16_t* params[] = { providedOrigin.get(), targetOrigin.get() };
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("DOM Window"), sourceDocument,
nsContentUtils::eDOM_PROPERTIES,
"TargetPrincipalDoesNotMatch",
params, ArrayLength(params));
return NS_OK;
}
}
+2
View File
@@ -33,6 +33,7 @@ public:
const nsAString& aCallerOrigin,
nsGlobalWindow* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
nsIDocument* aSourceDocument,
bool aTrustedCaller);
private:
@@ -42,6 +43,7 @@ private:
nsString mCallerOrigin;
RefPtr<nsGlobalWindow> mTargetWindow;
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
nsCOMPtr<nsIDocument> mSourceDocument;
bool mTrustedCaller;
};
+6
View File
@@ -2343,6 +2343,7 @@ CreateNativeGlobalForInner(JSContext* aCx,
if (aNewInner->GetOuterWindow()) {
top = aNewInner->GetTopInternal();
}
JS::CompartmentOptions options;
// Sometimes add-ons load their own XUL windows, either as separate top-level
@@ -2356,6 +2357,8 @@ CreateNativeGlobalForInner(JSContext* aCx,
options.creationOptions().setSameZoneAs(top->GetGlobalJSObject());
}
xpc::InitGlobalObjectOptions(options, aPrincipal);
// Determine if we need the Components object.
bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
TreatAsRemoteXUL(aPrincipal);
@@ -8071,6 +8074,9 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessa
origin,
this,
providedPrincipal,
callerInnerWin
? callerInnerWin->GetDoc()
: nullptr,
nsContentUtils::IsCallerChrome());
JS::Rooted<JS::Value> message(aCx, aMessage);
+5
View File
@@ -3040,6 +3040,11 @@ RegisterDOMNames();
// The return value is whatever the ProtoHandleGetter we used
// returned. This should be the DOM prototype for the global.
//
// Typically this method's caller will want to ensure that
// xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
// called after, this method, to ensure that this global object and its
// compartment are consistent with other global objects.
template <class T, ProtoHandleGetter GetProto>
JS::Handle<JSObject*>
CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
@@ -191,6 +191,8 @@ InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passe
InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'.
ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.
PatternAttributeCompileFailure=Unable to check <input pattern='%S'> because the pattern is not a valid regexp: %S
# LOCALIZATION NOTE: Do not translate "postMessage" or DOMWindow. %S values are origins, like https://domain.com:port
TargetPrincipalDoesNotMatch=Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('%S') does not match the recipient window's origin ('%S').
# LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port
RewriteYoutubeEmbed=Rewriting old-style Youtube Flash embed (%S) to iframe embed (%S). Please update page to use iframe instead of embed/object, if possible.
# LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port
+36 -23
View File
@@ -392,12 +392,44 @@ CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
return global;
}
void
InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
nsIPrincipal* aPrincipal)
{
bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
bool isSystem = false;
if (shouldDiscardSystemSource || extraWarningsForSystemJS)
isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
if (shouldDiscardSystemSource) {
bool discardSource = isSystem;
if (!discardSource) {
short status = aPrincipal->GetAppStatus();
discardSource = status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
status == nsIPrincipal::APP_STATUS_CERTIFIED;
}
aOptions.behaviors().setDiscardSource(discardSource);
}
if (extraWarningsForSystemJS) {
if (isSystem)
aOptions.behaviors().extraWarningsOverride().set(true);
}
}
bool
InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
{
// Immediately enter the global's compartment, so that everything else we
// create ends up there.
// Immediately enter the global's compartment so that everything we create
// ends up there.
JSAutoCompartment ac(aJSContext, aGlobal);
// Stuff coming through this path always ends up as a DOM global.
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
// XPCCallContext gives us an active request needed to save/restore.
if (!CompartmentPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
@@ -406,27 +438,6 @@ InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t
}
}
if (ShouldDiscardSystemSource()) {
nsIPrincipal* prin = GetObjectPrincipal(aGlobal);
bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
if (!isSystem) {
short status = prin->GetAppStatus();
isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
status == nsIPrincipal::APP_STATUS_CERTIFIED;
}
JS::CompartmentBehaviorsRef(aGlobal).setDiscardSource(isSystem);
}
if (ExtraWarningsForSystemJS()) {
nsIPrincipal* prin = GetObjectPrincipal(aGlobal);
bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
if (isSystem)
JS::CompartmentBehaviorsRef(aGlobal).extraWarningsOverride().set(true);
}
// Stuff coming through this path always ends up as a DOM global.
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
JS_FireOnNewGlobalObject(aJSContext, aGlobal);
@@ -451,6 +462,8 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
// we need to have a principal.
MOZ_ASSERT(aPrincipal);
InitGlobalObjectOptions(aOptions, aPrincipal);
// Call into XPCWrappedNative to make a new global object, scope, and global
// prototype.
xpcObjectHelper helper(aCOMObj);
+17 -2
View File
@@ -3599,8 +3599,23 @@ JSObject*
CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
JS::CompartmentOptions& aOptions);
// InitGlobalObject enters the compartment of aGlobal, so it doesn't matter what
// compartment aJSContext is in.
// Modify the provided compartment options, consistent with |aPrincipal| and
// with globally-cached values of various preferences.
//
// Call this function *before* |aOptions| is used to create the corresponding
// global object, as not all of the options it sets can be modified on an
// existing global object. (The type system should make this obvious, because
// you can't get a *mutable* JS::CompartmentOptions& from an existing global
// object.)
void
InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
nsIPrincipal* aPrincipal);
// Finish initializing an already-created, not-yet-exposed-to-script global
// object. This will attach a Components object (if necessary) and call
// |JS_FireOnNewGlobalObject| (if necessary).
//
// If you must modify compartment options, see InitGlobalObjectOptions above.
bool
InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal,
uint32_t aFlags);
+15 -3
View File
@@ -3,10 +3,11 @@
* 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/. */
#include "mozilla/dom/ToJSValue.h"
#include "nsAutoPtr.h"
#include "nsCookie.h"
#include "nsUTF8ConverterService.h"
#include <stdlib.h>
#include "nsAutoPtr.h"
static const int64_t kCookieStaleThreshold = 60 * PR_USEC_PER_SEC; // 1 minute in microseconds
@@ -79,7 +80,8 @@ nsCookie::Create(const nsACString &aName,
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly)
bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes)
{
// Ensure mValue contains a valid UTF-8 sequence. Otherwise XPConnect will
// truncate the string after the first invalid octet.
@@ -111,7 +113,8 @@ nsCookie::Create(const nsACString &aName,
// construct the cookie. placement new, oh yeah!
return new (place) nsCookie(name, value, host, path, end,
aExpiry, aLastAccessed, aCreationTime,
aIsSession, aIsSecure, aIsHttpOnly);
aIsSession, aIsSecure, aIsHttpOnly,
aOriginAttributes);
}
size_t
@@ -151,6 +154,15 @@ NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = 0;
NS_IMETHODIMP nsCookie::GetCreationTime(int64_t *aCreation){ *aCreation = CreationTime(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetLastAccessed(int64_t *aTime) { *aTime = LastAccessed(); return NS_OK; }
NS_IMETHODIMP
nsCookie::GetOriginAttributes(JSContext *aCx, JS::MutableHandle<JS::Value> aVal)
{
if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// compatibility method, for use with the legacy nsICookie interface.
// here, expires == 0 denotes a session cookie.
NS_IMETHODIMP
+9 -2
View File
@@ -11,6 +11,9 @@
#include "nsString.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/BasePrincipal.h"
using mozilla::OriginAttributes;
/**
* The nsCookie class is the main cookie storage medium for use within cookie
@@ -43,7 +46,8 @@ class nsCookie : public nsICookie2
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly)
bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes)
: mName(aName)
, mValue(aValue)
, mHost(aHost)
@@ -55,6 +59,7 @@ class nsCookie : public nsICookie2
, mIsSession(aIsSession != false)
, mIsSecure(aIsSecure != false)
, mIsHttpOnly(aIsHttpOnly != false)
, mOriginAttributes(aOriginAttributes)
{
}
@@ -74,7 +79,8 @@ class nsCookie : public nsICookie2
int64_t aCreationTime,
bool aIsSession,
bool aIsSecure,
bool aIsHttpOnly);
bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@@ -123,6 +129,7 @@ class nsCookie : public nsICookie2
bool mIsSession;
bool mIsSecure;
bool mIsHttpOnly;
mozilla::OriginAttributes mOriginAttributes;
};
#endif // nsCookie_h__
+16 -9
View File
@@ -490,7 +490,8 @@ public:
row->GetUTF8String(IDX_ORIGIN_ATTRIBUTES, suffix);
tuple->key.mOriginAttributes.PopulateFromSuffix(suffix);
tuple->cookie = gCookieService->GetCookieFromRow(row);
tuple->cookie =
gCookieService->GetCookieFromRow(row, tuple->key.mOriginAttributes);
}
return NS_OK;
@@ -2282,6 +2283,7 @@ nsCookieService::Add(const nsACString &aHost,
NS_ENSURE_SUCCESS(rv, rv);
int64_t currentTimeInUsec = PR_Now();
nsCookieKey key = DEFAULT_APP_KEY(baseDomain);
RefPtr<nsCookie> cookie =
nsCookie::Create(aName, aValue, host, aPath,
@@ -2290,12 +2292,13 @@ nsCookieService::Add(const nsACString &aHost,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
aIsSession,
aIsSecure,
aIsHttpOnly);
aIsHttpOnly,
key.mOriginAttributes);
if (!cookie) {
return NS_ERROR_OUT_OF_MEMORY;
}
AddInternal(DEFAULT_APP_KEY(baseDomain), cookie, currentTimeInUsec, nullptr, nullptr, true);
AddInternal(key, cookie, currentTimeInUsec, nullptr, nullptr, true);
return NS_OK;
}
@@ -2430,7 +2433,7 @@ nsCookieService::Read()
// Extract data from a single result row and create an nsCookie.
// This is templated since 'T' is different for sync vs async results.
template<class T> nsCookie*
nsCookieService::GetCookieFromRow(T &aRow)
nsCookieService::GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttributes)
{
// Skip reading 'baseDomain' -- up to the caller.
nsCString name, value, host, path;
@@ -2456,7 +2459,8 @@ nsCookieService::GetCookieFromRow(T &aRow)
creationTime,
false,
isSecure,
isHttpOnly);
isHttpOnly,
aOriginAttributes);
}
void
@@ -2603,7 +2607,8 @@ nsCookieService::EnsureReadDomain(const nsCookieKey &aKey)
if (!hasResult)
break;
array.AppendElement(GetCookieFromRow(mDefaultDBState->stmtReadDomain));
array.AppendElement(GetCookieFromRow(mDefaultDBState->stmtReadDomain,
aKey.mOriginAttributes));
}
// Add the cookies to the table in a single operation. This makes sure that
@@ -2693,7 +2698,7 @@ nsCookieService::EnsureReadComplete()
CookieDomainTuple* tuple = array.AppendElement();
tuple->key = key;
tuple->cookie = GetCookieFromRow(stmt);
tuple->cookie = GetCookieFromRow(stmt, attrs);
}
// Add the cookies to the table in a single operation. This makes sure that
@@ -2847,7 +2852,8 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
false,
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
isHttpOnly);
isHttpOnly,
key.mOriginAttributes);
if (!newCookie) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -3213,7 +3219,8 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
cookieAttributes.isSession,
cookieAttributes.isSecure,
cookieAttributes.isHttpOnly);
cookieAttributes.isHttpOnly,
aKey.mOriginAttributes);
if (!cookie)
return newCookie;
+2 -1
View File
@@ -33,6 +33,7 @@
#include "mozilla/MemoryReporting.h"
using mozilla::NeckoOriginAttributes;
using mozilla::OriginAttributes;
class nsICookiePermission;
class nsIEffectiveTLDService;
@@ -283,7 +284,7 @@ class nsCookieService final : public nsICookieService
void HandleCorruptDB(DBState* aDBState);
void RebuildCorruptDB(DBState* aDBState);
OpenDBResult Read();
template<class T> nsCookie* GetCookieFromRow(T &aRow);
template<class T> nsCookie* GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttributes);
void AsyncReadComplete();
void CancelAsyncRead(bool aPurgeReadSet);
void EnsureReadDomain(const nsCookieKey &aKey);
+6 -2
View File
@@ -14,8 +14,7 @@
typedef long nsCookieStatus;
typedef long nsCookiePolicy;
[scriptable, uuid(8684966b-1877-4f0f-8155-be4490b96bf7)]
[scriptable, uuid(adf0db5e-211e-45a3-be14-4486ac430a58)]
interface nsICookie : nsISupports {
/**
@@ -78,4 +77,9 @@ interface nsICookie : nsISupports {
const nsCookiePolicy POLICY_NO_II=5;
readonly attribute nsCookiePolicy policy;
/**
* The origin attributes for this cookie
*/
[implicit_jscontext]
readonly attribute jsval originAttributes;
};
+1
View File
@@ -92,6 +92,7 @@ def build_dict(config, env=os.environ):
d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
d['addon_signing'] = substs.get('MOZ_ADDON_SIGNING') == '1'
d['require_signing'] = substs.get('MOZ_REQUIRE_SIGNING') == '1'
d['official'] = bool(substs.get('MOZILLA_OFFICIAL'))
def guess_platform():
+5 -11
View File
@@ -280,7 +280,7 @@
"GC_REASON_2": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 10,
"n_values": 100,
"description": "Reason (enum value) for initiating a GC"
},
"GC_IS_COMPARTMENTAL": {
@@ -407,13 +407,13 @@
"GC_MINOR_REASON": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": "10",
"n_values": 100,
"description": "Reason (enum value) for initiating a minor GC"
},
"GC_MINOR_REASON_LONG": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": "10",
"n_values": 100,
"description": "Reason (enum value) that caused a long (>1ms) minor GC"
},
"GC_MINOR_US": {
@@ -3077,7 +3077,7 @@
"STARTUP_MEASUREMENT_ERRORS": {
"expires_in_version": "default",
"kind": "enumerated",
"n_values": "mozilla::StartupTimeline::MAX_EVENT_ID",
"n_values": 16,
"description": "Flags errors in startup calculation()"
},
"NETWORK_DISK_CACHE_OPEN": {
@@ -5445,13 +5445,7 @@
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'detach' request to go round trip."
},
"MEDIA_WMF_DECODE_ERROR": {
"expires_in_version": "50",
"kind": "enumerated",
"n_values": 256,
"description": "WMF media decoder error or success (0) codes."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPESANDPROPERTIES_MS": {
"DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
+18 -2
View File
@@ -1960,6 +1960,23 @@ mFailedLockCount(0)
// histograms) using InitHistogramRecordingEnabled() will happen after instantiating
// sTelemetry since it depends on the static GetKeyedHistogramById(...) - which
// uses the singleton instance at sTelemetry.
// Some Telemetry histograms depend on the value of C++ constants and hardcode
// their values in Histograms.json.
// We add static asserts here for those values to match so that future changes
// don't go unnoticed.
// TODO: Compare explicitly with gHistograms[<histogram id>].bucketCount here
// once we can make gHistograms constexpr (requires VS2015).
/*static_assert((JS::gcreason::NUM_TELEMETRY_REASONS == 100),
"NUM_TELEMETRY_REASONS is assumed to be a fixed value in Histograms.json."
" If this was an intentional change, update this assert with its value "
"and update the n_values for the following in Histograms.json: "
"GC_MINOR_REASON, GC_MINOR_REASON_LONG, GC_REASON_2");*/
static_assert((mozilla::StartupTimeline::MAX_EVENT_ID == 16),
"MAX_EVENT_ID is assumed to be a fixed value in Histograms.json. If this"
" was an intentional change, update this assert with its value and update"
" the n_values for the following in Histograms.json:"
" STARTUP_MEASUREMENT_ERRORS");
}
TelemetryImpl::~TelemetryImpl() {
@@ -3559,7 +3576,6 @@ static MOZ_CONSTEXPR_VAR TrackedDBEntry kTrackedDBs[] = {
TRACKEDDB_ENTRY("downloads.sqlite"),
TRACKEDDB_ENTRY("extensions.sqlite"),
TRACKEDDB_ENTRY("formhistory.sqlite"),
TRACKEDDB_ENTRY("healthreport.sqlite"),
TRACKEDDB_ENTRY("index.sqlite"),
TRACKEDDB_ENTRY("netpredictions.sqlite"),
TRACKEDDB_ENTRY("permissions.sqlite"),
@@ -3646,7 +3662,7 @@ void
TelemetryImpl::RecordIceCandidates(const uint32_t iceCandidateBitmask,
const bool success, const bool loop)
{
if (!sTelemetry)
if (!sTelemetry || !sTelemetry->mCanRecordExtended)
return;
sTelemetry->mWebrtcTelemetry.RecordIceCandidateMask(iceCandidateBitmask, success, loop);
@@ -185,5 +185,8 @@
"LOOP_VIDEO_QUALITY_OUTBOUND_RTT",
"LOOP_AUDIO_QUALITY_OUTBOUND_RTT",
"LOOP_CALL_DURATION",
"GFX_CRASH"
"GFX_CRASH",
"GC_REASON_2",
"GC_MINOR_REASON",
"GC_MINOR_REASON_LONG"
]
@@ -170,6 +170,10 @@ function loadAddonManager(id, name, version, platformVersion) {
let uri = ns.Services.io.newFileURI(file);
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
createAppInfo(id, name, version, platformVersion);
// As we're not running in application, we need to setup the features directory
// used by system add-ons.
const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
registerDirectory("XREAppFeat", distroDir);
startupManager();
}
@@ -30,7 +30,6 @@ const PREF_BRANCH = "toolkit.telemetry.";
const PREF_ENABLED = PREF_BRANCH + "enabled";
const PREF_ARCHIVE_ENABLED = PREF_BRANCH + "archive.enabled";
const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
const PREF_FHR_SERVICE_ENABLED = "datareporting.healthreport.service.enabled";
const PREF_UNIFIED = PREF_BRANCH + "unified";
const PREF_OPTOUT_SAMPLE = PREF_BRANCH + "optoutSample";
@@ -10,12 +10,12 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://testing-common/AddonManagerTesting.jsm");
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://testing-common/MockRegistrar.jsm", this);
Cu.import("resource://gre/modules/FileUtils.jsm");
// Lazy load |LightweightThemeManager|, we won't be using it on Gonk.
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
// Lazy load |ProfileAge| as it is not available on Android.
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
"resource://gre/modules/ProfileAge.jsm");
@@ -69,6 +69,9 @@ const PERSONA_DESCRIPTION = "A nice theme/persona description.";
const PLUGIN_UPDATED_TOPIC = "plugins-list-updated";
// system add-ons are enabled at startup, so record date when the test starts
const SYSTEM_ADDON_INSTALL_DATE = Date.now();
/**
* Used to mock plugin tags in our fake plugin host.
*/
@@ -149,11 +152,6 @@ function spoofGfxAdapter() {
}
function spoofProfileReset() {
if (gIsAndroid) {
// ProfileAge is not available on Android.
return true;
}
let profileAccessor = new ProfileAge();
return profileAccessor.writeTimes({
@@ -319,7 +317,7 @@ function checkPartnerSection(data, isInitial) {
if (isInitial) {
Assert.equal(data.partner.partnerNames.length, 0);
} else {
Assert.ok(data.partner.partnerNames.indexOf(PARTNER_NAME) >= 0);
Assert.ok(data.partner.partnerNames.includes(PARTNER_NAME));
}
}
@@ -484,6 +482,11 @@ function checkSystemSection(data) {
}
function checkActiveAddon(data){
let signedState = mozinfo.addon_signing ? "number" : "undefined";
// system add-ons have an undefined signState
if (data.isSystem)
signedState = "undefined";
const EXPECTED_ADDON_FIELDS_TYPES = {
blocklisted: "boolean",
name: "string",
@@ -496,7 +499,8 @@ function checkActiveAddon(data){
hasBinaryComponents: "boolean",
installDay: "number",
updateDay: "number",
signedState: mozinfo.addon_signing ? "number" : "undefined",
signedState: signedState,
isSystem: "boolean",
};
for (let f in EXPECTED_ADDON_FIELDS_TYPES) {
@@ -626,6 +630,13 @@ function run_test() {
do_test_pending();
spoofGfxAdapter();
do_get_profile();
// The system add-on must be installed before AddonManager is started.
const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
do_get_file("system.xpi").copyTo(distroDir, "tel-system-xpi@tests.mozilla.org.xpi");
let system_addon = FileUtils.File(distroDir.path);
system_addon.append("tel-system-xpi@tests.mozilla.org.xpi");
system_addon.lastModifiedTime = SYSTEM_ADDON_INSTALL_DATE;
loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
// Spoof the persona ID, but not on Gonk.
@@ -659,6 +670,7 @@ function isRejected(promise) {
add_task(function* asyncSetup() {
yield spoofProfileReset();
TelemetryEnvironment.delayedInit();
});
add_task(function* test_checkEnvironment() {
@@ -915,7 +927,25 @@ add_task(function* test_addonsAndPlugins() {
hasBinaryComponents: false,
installDay: ADDON_INSTALL_DATE,
updateDay: ADDON_INSTALL_DATE,
signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
isSystem: false,
};
const SYSTEM_ADDON_ID = "tel-system-xpi@tests.mozilla.org";
const EXPECTED_SYSTEM_ADDON_DATA = {
blocklisted: false,
description: "A system addon which is shipped with Firefox.",
name: "XPI Telemetry System Add-on Test",
userDisabled: false,
appDisabled: false,
version: "1.0",
scope: 1,
type: "extension",
foreignInstall: false,
hasBinaryComponents: false,
installDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
updateDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
signedState: undefined,
isSystem: true,
};
const EXPECTED_PLUGIN_DATA = {
@@ -940,6 +970,13 @@ add_task(function* test_addonsAndPlugins() {
Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value.");
}
// Check system add-on data.
Assert.ok(SYSTEM_ADDON_ID in data.addons.activeAddons, "We must have one active system addon.");
let targetSystemAddon = data.addons.activeAddons[SYSTEM_ADDON_ID];
for (let f in EXPECTED_SYSTEM_ADDON_DATA) {
Assert.equal(targetSystemAddon[f], EXPECTED_SYSTEM_ADDON_DATA[f], f + " must have the correct value.");
}
// Check theme data.
let theme = data.addons.theme;
Assert.equal(theme.id, (PERSONA_ID + PERSONA_ID_SUFFIX));
@@ -1180,6 +1217,31 @@ add_task(function* test_defaultSearchEngine() {
Assert.equal(data.settings.searchCohort, "testcohort");
});
add_task(function* test_environmentShutdown() {
// Define and reset the test preference.
const PREF_TEST = "toolkit.telemetry.test.pref1";
const PREFS_TO_WATCH = new Map([
[PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
]);
Preferences.reset(PREF_TEST);
gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
fakeNow(gNow);
// Set up the preferences and listener, then the trigger shutdown
TelemetryEnvironment._watchPreferences(PREFS_TO_WATCH);
TelemetryEnvironment.registerChangeListener("test_environmentShutdownChange", () => {
// Register a new change listener that asserts if change is propogated
Assert.ok(false, "No change should be propagated after shutdown.");
});
TelemetryEnvironment.shutdown();
// Flipping the test preference after shutdown should not trigger the listener
Preferences.set(PREF_TEST, 1);
// Unregister the listener.
TelemetryEnvironment.unregisterChangeListener("test_environmentShutdownChange");
});
add_task(function*() {
do_test_finished();
});
@@ -17,7 +17,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
const PREF_BRANCH = "toolkit.telemetry.";
const PREF_SERVER = PREF_BRANCH + "server";
const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled";
const TEST_CHANNEL = "TestChannelABC";
@@ -47,8 +46,6 @@ function run_test() {
loadAddonManager("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
// We need to disable FHR in order to use the policy from telemetry.
Services.prefs.setBoolPref(PREF_DRS_ENABLED, false);
// Don't bypass the notifications in this test, we'll fake it.
Services.prefs.setBoolPref(PREF_BYPASS_NOTIFICATION, false);
@@ -63,7 +63,6 @@ const MS_IN_ONE_DAY = 24 * MS_IN_ONE_HOUR;
const PREF_BRANCH = "toolkit.telemetry.";
const PREF_SERVER = PREF_BRANCH + "server";
const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
const PREF_FHR_SERVICE_ENABLED = "datareporting.healthreport.service.enabled";
const DATAREPORTING_DIR = "datareporting";
const ABORTED_PING_FILE_NAME = "aborted-session-ping";
@@ -12,6 +12,7 @@ support-files =
experiment.xpi
extension.xpi
extension-2.xpi
system.xpi
restartless.xpi
theme.xpi
generated-files =
@@ -19,6 +20,7 @@ generated-files =
experiment.xpi
extension.xpi
extension-2.xpi
system.xpi
restartless.xpi
theme.xpi
@@ -1636,6 +1636,9 @@ function shouldVerifySignedState(aAddon) {
return ADDON_SIGNING && SIGNED_TYPES.has(aAddon.type);
}
let gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
/**
* Verifies that a zip file's contents are all correctly signed by an
* AMO-issued certificate
@@ -1650,19 +1653,23 @@ function verifyZipSignedState(aFile, aAddon) {
if (!shouldVerifySignedState(aAddon))
return Promise.resolve(AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
let root = Ci.nsIX509CertDB.AddonsPublicRoot;
if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
root = Ci.nsIX509CertDB.AddonsStageRoot;
return new Promise(resolve => {
certDB.openSignedAppFileAsync(root, aFile, (aRv, aZipReader, aCert) => {
if (aZipReader)
aZipReader.close();
resolve(getSignedStatus(aRv, aCert, aAddon.id));
});
let callback = {
openSignedAppFileFinished: function(aRv, aZipReader, aCert) {
if (aZipReader)
aZipReader.close();
resolve(getSignedStatus(aRv, aCert, aAddon.id));
}
};
// This allows the certificate DB to get the raw JS callback object so the
// test code can pass through objects that XPConnect would reject.
callback.wrappedJSObject = callback;
gCertDB.openSignedAppFileAsync(root, aFile, callback);
});
}
@@ -1680,17 +1687,21 @@ function verifyDirSignedState(aDir, aAddon) {
if (!shouldVerifySignedState(aAddon))
return Promise.resolve(AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
let root = Ci.nsIX509CertDB.AddonsPublicRoot;
if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
root = Ci.nsIX509CertDB.AddonsStageRoot;
return new Promise(resolve => {
certDB.verifySignedDirectoryAsync(root, aDir, (aRv, aCert) => {
resolve(getSignedStatus(aRv, aCert, aAddon.id));
});
let callback = {
verifySignedDirectoryFinished: function(aRv, aCert) {
resolve(getSignedStatus(aRv, aCert, aAddon.id));
}
};
// This allows the certificate DB to get the raw JS callback object so the
// test code can pass through objects that XPConnect would reject.
callback.wrappedJSObject = callback;
gCertDB.verifySignedDirectoryAsync(root, aDir, callback);
});
}
@@ -1640,10 +1640,12 @@ this.XPIDatabaseReconcile = {
// Remove the invalid add-on from the install location if the install
// location isn't locked, no restart will be necessary
if (!aInstallLocation.locked)
aInstallLocation.uninstallAddon(aId);
else
if (aInstallLocation.isLinkedAddon(aId))
logger.warn("Not uninstalling invalid item because it is a proxy file");
else if (aInstallLocation.locked)
logger.warn("Could not uninstall invalid item from locked install location");
else
aInstallLocation.uninstallAddon(aId);
return null;
}
@@ -0,0 +1 @@
Components.utils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
@@ -7,6 +7,8 @@ var AM_Ci = Components.interfaces;
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
const CERTDB_CONTRACTID = "@mozilla.org/security/x509certdb;1";
const CERTDB_CID = Components.ID("{fb0bbc5c-452e-4783-b32c-80124693d871}");
const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity";
const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility";
@@ -295,6 +297,179 @@ function createAppInfo(id, name, version, platformVersion) {
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
}
function getManifestURIForBundle(file) {
if (file.isDirectory()) {
file.append("install.rdf");
if (file.exists()) {
return NetUtil.newURI(file);
}
file.leafName = "manifest.json";
if (file.exists()) {
return NetUtil.newURI(file);
}
throw new Error("No manifest file present");
}
let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(AM_Ci.nsIZipReader);
zip.open(file);
try {
let uri = NetUtil.newURI(file);
if (zip.hasEntry("install.rdf")) {
return NetUtil.newURI("jar:" + uri.spec + "!/" + "install.rdf");
}
if (zip.hasEntry("manifest.json")) {
return NetUtil.newURI("jar:" + uri.spec + "!/" + "manifest.json");
}
throw new Error("No manifest file present");
}
finally {
zip.close();
}
}
let getIDForManifest = Task.async(function*(manifestURI) {
// Load it
let inputStream = yield new Promise((resolve, reject) => {
NetUtil.asyncFetch({
uri: manifestURI,
loadUsingSystemPrincipal: true,
}, (inputStream, status) => {
if (status != Components.results.NS_OK)
reject(status);
resolve(inputStream);
});
});
// Get the data as a string
let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
if (manifestURI.spec.endsWith(".rdf")) {
let rdfParser = AM_Cc["@mozilla.org/rdf/xml-parser;1"].
createInstance(AM_Ci.nsIRDFXMLParser)
let ds = AM_Cc["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].
createInstance(AM_Ci.nsIRDFDataSource);
rdfParser.parseString(ds, manifestURI, data);
let rdfService = AM_Cc["@mozilla.org/rdf/rdf-service;1"].
getService(AM_Ci.nsIRDFService);
let rdfID = ds.GetTarget(rdfService.GetResource("urn:mozilla:install-manifest"),
rdfService.GetResource("http://www.mozilla.org/2004/em-rdf#id"),
true);
return rdfID.QueryInterface(AM_Ci.nsIRDFLiteral).Value;
}
else {
let manifest = JSON.parse(data);
return manifest.applications.gecko.id;
}
});
let gUseRealCertChecks = false;
function overrideCertDB(handler) {
// Unregister the real database. This only works because the add-ons manager
// hasn't started up and grabbed the certificate database yet.
let registrar = Components.manager.QueryInterface(AM_Ci.nsIComponentRegistrar);
let factory = registrar.getClassObject(CERTDB_CID, AM_Ci.nsIFactory);
registrar.unregisterFactory(CERTDB_CID, factory);
// Get the real DB
let realCertDB = factory.createInstance(null, AM_Ci.nsIX509CertDB);
let verifyCert = Task.async(function*(caller, file, result, cert, callback) {
// If this isn't a callback we can get directly to through JS then just
// pass on the results
if (!callback.wrappedJSObject) {
caller(callback, result, cert);
return;
}
// Bypassing XPConnect allows us to create a fake x509 certificate from
// JS
callback = callback.wrappedJSObject;
if (gUseRealCertChecks || result != Components.results.NS_ERROR_SIGNED_JAR_NOT_SIGNED) {
// If the real DB found a useful result of some kind then pass it on.
caller(callback, result, cert);
return;
}
try {
let manifestURI = getManifestURIForBundle(file);
let id = yield getIDForManifest(manifestURI);
// Make sure to close the open zip file or it will be locked.
if (file.isFile()) {
Services.obs.notifyObservers(file, "flush-cache-entry", "cert-override");
}
let fakeCert = {
commonName: id
}
caller(callback, Components.results.NS_OK, fakeCert);
}
catch (e) {
// If there is any error then just pass along the original results
caller(callback, result, cert);
}
});
let fakeCertDB = {
openSignedAppFileAsync(root, file, callback) {
// First try calling the real cert DB
realCertDB.openSignedAppFileAsync(root, file, (result, zipReader, cert) => {
function call(callback, result, cert) {
callback.openSignedAppFileFinished(result, zipReader, cert);
}
verifyCert(call, file.clone(), result, cert, callback);
});
},
verifySignedDirectoryAsync(root, dir, callback) {
// First try calling the real cert DB
realCertDB.verifySignedDirectoryAsync(root, dir, (result, cert) => {
function call(callback, result, cert) {
callback.verifySignedDirectoryFinished(result, cert);
}
verifyCert(call, dir.clone(), result, cert, callback);
});
},
QueryInterface: XPCOMUtils.generateQI([AM_Ci.nsIX509CertDB])
};
for (let property of Object.keys(realCertDB)) {
if (property in fakeCertDB) {
continue;
}
if (typeof realCertDB[property] == "function") {
fakeCertDB[property] = realCertDB[property].bind(realCertDB);
}
}
let certDBFactory = {
createInstance: function(outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return fakeCertDB.QueryInterface(iid);
}
};
registrar.registerFactory(CERTDB_CID, "CertDB",
CERTDB_CONTRACTID, certDBFactory);
}
overrideCertDB();
/**
* Tests that an add-on does appear in the crash report annotations, if
* crash reporting is enabled. The test will fail if the add-on is not in the
@@ -2112,3 +2287,36 @@ var promiseConsoleOutput = Task.async(function*(aTask) {
Services.console.unregisterListener(listener);
}
});
/**
* Creates an extension proxy file.
* See: https://developer.mozilla.org/en-US/Add-ons/Setting_up_extension_development_environment#Firefox_extension_proxy_file
* @param aDir
* The directory to add the proxy file to.
* @param aAddon
* An nsIFile for the add-on file that this is a proxy file for.
* @param aId
* A string to use for the add-on ID.
* @return An nsIFile for the proxy file.
*/
function writeProxyFileToDir(aDir, aAddon, aId) {
let dir = aDir.clone();
if (!dir.exists())
dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let file = dir.clone();
file.append(aId);
let addonPath = aAddon.path;
let fos = AM_Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(AM_Ci.nsIFileOutputStream);
fos.init(file,
FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
FileUtils.PERMS_FILE, 0);
fos.write(addonPath, addonPath.length);
fos.close();
return file;
}
@@ -11,6 +11,9 @@ var CacheFlushObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic != "flush-cache-entry")
return;
// Ignore flushes triggered by the fake cert DB
if (aData == "cert-override")
return;
do_check_true(gExpectedFile != null);
do_check_true(aSubject instanceof AM_Ci.nsIFile);
@@ -285,6 +285,7 @@ add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = true;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", true);
Services.prefs.setCharPref("extensions.hotfix.id", ID);
Services.prefs.setBoolPref("extensions.hotfix.cert.checkAttributes", false);
yield check_normal();
});
@@ -0,0 +1,106 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const ID = "proxy1@tests.mozilla.org";
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
startupManager();
BootstrapMonitor.init();
// Ensure that a proxy file to an add-on with a valid manifest works.
add_task(function*() {
let tempdir = gTmpD.clone();
writeInstallRDFToDir({
id: ID,
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Bootstrap 1 (proxy)",
}, tempdir, ID, "bootstrap.js");
let unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_proxy/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();
extensionsDir.append("extensions");
let proxyFile = writeProxyFileToDir(extensionsDir, unpackedAddon, ID);
yield promiseRestartManager();
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
BootstrapMonitor.checkAddonStarted(ID, "1.0");
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_eq(addon.version, "1.0");
do_check_eq(addon.name, "Test Bootstrap 1 (proxy)");
do_check_true(addon.isCompatible);
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_true(proxyFile.exists());
addon.uninstall();
unpackedAddon.remove(true);
yield promiseRestartManager();
});
// Ensure that a proxy file to an add-on is not removed even
// if the manifest file is invalid. See bug 1195353.
add_task(function*() {
let tempdir = gTmpD.clone();
// use a mismatched ID to make this install.rdf invalid
writeInstallRDFToDir({
id: "bad-proxy1@tests.mozilla.org",
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Bootstrap 1 (proxy)",
}, tempdir, ID, "bootstrap.js");
let unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_proxy/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();
extensionsDir.append("extensions");
let proxyFile = writeProxyFileToDir(extensionsDir, unpackedAddon, ID);
yield promiseRestartManager();
BootstrapMonitor.checkAddonNotInstalled(ID, "1.0");
BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
let addon = yield promiseAddonByID(ID);
do_check_eq(addon, null);
do_check_true(proxyFile.exists());
unpackedAddon.remove(true);
proxyFile.remove(true);
yield promiseRestartManager();
});
@@ -6,6 +6,8 @@ Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
// The test add-ons were signed by the dev root
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, true);
gUseRealCertChecks = true;
const DATA = "data/signing_checks/";
const ID_63 = "123456789012345678901234567890123456789012345@tests.mozilla.org"
@@ -35,17 +37,18 @@ add_task(function* test_working() {
}
});
// Installs the cases that should be broken
// Checks the cases that should be broken
add_task(function* test_broken() {
yield promiseInstallAllFiles([do_get_file(DATA + "long_63_hash.xpi"),
do_get_file(DATA + "long_64_hash.xpi")]);
function promiseInstallForFile(file) {
return new Promise(resolve => AddonManager.getInstallForFile(file, resolve));
}
let addons = yield promiseAddonsByIDs([ID_63, ID_64]);
let promises = [promiseInstallForFile(do_get_file(DATA + "long_63_hash.xpi")),
promiseInstallForFile(do_get_file(DATA + "long_64_hash.xpi"))];
let installs = yield Promise.all(promises);
for (let addon of addons) {
do_check_neq(addon, null);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
addon.uninstall();
for (let install of installs) {
do_check_eq(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
do_check_eq(install.error, AddonManager.ERROR_CORRUPT_FILE);
}
});
@@ -1,5 +1,5 @@
// Enable signature checks for these tests
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
gUseRealCertChecks = true;
// Disable update security
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
@@ -1,5 +1,6 @@
// Disable update security
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
gUseRealCertChecks = true;
const DATA = "data/signing_checks/";
const ID = "test@tests.mozilla.org";
@@ -54,6 +55,7 @@ function run_test() {
// Updating the pref without changing the app version won't disable add-ons
// immediately but will after a signing check
add_task(function*() {
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
startupManager();
// Install the signed add-on
@@ -57,7 +57,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
yield promiseRestartManager();
@@ -87,7 +87,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
// test that an unpacked add-on works too
let tempdir = gTmpD.clone();
@@ -125,7 +125,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
restartManager();
@@ -142,7 +142,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
unpacked_addon.remove(true);
addon.uninstall();
@@ -226,7 +226,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
addon.uninstall();
@@ -243,7 +243,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
unpacked_addon.remove(true);
addon.uninstall();
@@ -314,7 +314,7 @@ add_task(function*() {
do_check_false(tempAddon.appDisabled);
do_check_true(tempAddon.isActive);
do_check_eq(tempAddon.type, "extension");
do_check_eq(tempAddon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(tempAddon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
tempAddon.uninstall();
unpacked_addon.remove(true);
@@ -333,7 +333,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
addon.uninstall();
@@ -368,7 +368,7 @@ add_task(function*(){
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let tempdir = gTmpD.clone();
writeInstallRDFToDir({
@@ -423,7 +423,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
try {
yield AddonManager.installTemporaryAddon(do_get_addon("test_bootstrap1_1"));
@@ -55,7 +55,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let uri = do_get_addon_root_uri(profileDir, ID);
@@ -82,7 +82,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let file = getFileForAddon(profileDir, ID);
do_check_true(file.exists());
@@ -135,7 +135,7 @@ add_task(function*() {
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.type, "extension");
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
let file = getFileForAddon(profileDir, ID);
do_check_true(file.exists());
@@ -239,6 +239,8 @@ fail-if = buildapp == "mulet" || os == "android"
[test_registry.js]
[test_safemode.js]
[test_signed_updatepref.js]
run-if = addon_signing
skip-if = require_signing
[test_signed_verify.js]
[test_signed_inject.js]
skip-if = true
@@ -30,6 +30,7 @@ skip-if = appname != "firefox"
[test_XPIcancel.js]
[test_XPIStates.js]
[test_temporary.js]
[test_proxy.js]
[include:xpcshell-shared.ini]