mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
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:
@@ -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);
|
||||
},
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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,
|
||||
®isteredApp);
|
||||
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,
|
||||
®isteredApp);
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ EXTRA_JS_MODULES += [
|
||||
'TabCrashReporter.jsm',
|
||||
'TabGroupsMigrator.jsm',
|
||||
'TransientPrefs.jsm',
|
||||
'UserContextUI.jsm',
|
||||
'WebappManager.jsm',
|
||||
'webrtcUI.jsm',
|
||||
]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user