Skip to content

Loading…

A @nosandbox Option . . . #1701

Closed
wants to merge 3 commits into from

2 participants

@komichi

These two commits add:

(1) a @nosandbox option to user scripts which, when enabled, allows execution with full DOM and xmlHttpRequest access
(2) a per-script userNosandbox option (similar to User Includes/Excludes) that a user must check in order to allow the @nosandbox option before it is actually enabled

In other words, the first commit enables @nosandbox in user scripts and any script with @nosandbox set to true runs without the typical access wrapping (i.e., window == unsafeWindow) and has full access to all granted GM_* functions. The second commit makes @nosandbox a per-script user option that is off by default; if both @nosandbox and the script.userNosandbox options are not true, the current ("as safe as possible") behavior holds.

Having followed some of the discussions here and on the mailing list, I understand the need for sandboxing user scripts and respect your efforts at implementing better GM security. However, there are many cases when full DOM and AJAX request access is a requirement and I do not see a better way than the above two commits at allowing this and still pleasing everyone (please correct me if I am wrong here).

For instance, the main use case is typically something like: you fully trust the site you are running GM on (e.g., you may even have full source access) but for corporate, administrative or political reasons, you simply cannot get any changes to the site implemented.

Please consider these two commits for addition into a future GreaseMonkey release.

Thanks!

John

@arantius
Collaborator

I haven't even gotten around to reading the patch yet, but:

I'm not likely to merge this. Security holes are bad bad things. The existing compromise (no sandbox, or powerful+dangerous APIs) is pretty good. This use case seems rare enough that the right solution, if you really need both, is to make your own extension.

@komichi

I'm sorry to hear that, as I think this can be done securely; still, I would like to understand the official GreaseMonkey position on this ... two questions:

(1) From reading your response, my understanding is that no patch to GreaseMonkey that would allow full access to both the DOM and GM_xmlHttpRequest would ever be acceptable, regardless of any security mechanisms in place to prevent these two features from being inadvertently enabled simultaneously by average users. Is this correct?

(2) What about allowing CORS-style includes/excludes as a means for enhancing GM_xmlHttpRequest security? That is, a per-script list of In/Excludes which users could set that would restrict the set of hosts/ports GM_xmlHttpRequest will interact with. Assuming the default "CORS" policy on (unsandboxed) GM_xmlHttpRequest was origin-only, this would allow script users to manually broaden the list -- securely allowing the freedom to make calls to specific non-origin hosts without compromising generally on security. (Actually, in a sense, this could represent an improvement over the present unrestricted model.) If a patch were submitted to allow (unsandboxed) access to both the DOM and a CORS-restricted GM_xmlHttpRequest, would this still be unacceptable for GreaseMonkey?

Thanks!

@komichi

The latest commit adds support for CORS in/exclude lists (as described above in Question 2) via an "Advanced" script preferences dialog (reachable from the main script preferences dialog). As noted above, this improves overall security by allowing both script authors and users to explicitly specify which URLs should and should not be reachable via AJAX calls.

@arantius arantius closed this
@komichi

Given that the security concerns you raised have been addressed completely, it is difficult to understand why you are closing this without so much as a comment?

@arantius
Collaborator

I'm not comfortable bringing GM_xhr any closer to content than it already is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 26, 2013
  1. addition of a nosandbox option

    John Lane committed
  2. changes to make nosandbox mode a per-script user option (i.e., to mak…

    John Lane committed
    …e it opt-in _only_)
Commits on Feb 16, 2013
  1. Added support for script/user CORS in/exclude lists to enhance GM_xml…

    John Lane committed
    …httpRequest security
View
59 components/greasemonkey.js
@@ -107,41 +107,37 @@ function GM_apiLeakCheck(apiName) {
function createSandbox(
aScript, aContentWin, aChromeWin, aFirebugConsole, aUrl
) {
- if (GM_util.inArray(aScript.grants, 'none')) {
- // If there is an explicit none grant, use a plain unwrapped sandbox
- // with no other content.
- var contentSandbox = new Components.utils.Sandbox(
- aContentWin,
- {
- 'sandboxName': aScript.id,
- 'sandboxPrototype': aContentWin,
- 'wantXrays': false,
- });
- // GM_info is always provided.
- Components.utils.evalInSandbox(
- 'const GM_info = ' + uneval(aScript.info()), contentSandbox);
+ var sandbox = null;
+ if (GM_util.inArray(aScript.grants, 'none')
+ || (aScript.nosandbox && aScript.userNosandbox)) {
+ // If there is an explicit none grant or nosandbox is set,
+ // use a plain unwrapped sandbox with no other content.
+ sandbox = new Components.utils.Sandbox(
+ aContentWin,
+ {
+ 'sandboxName': aScript.id,
+ 'sandboxPrototype': aContentWin,
+ 'wantXrays': false,
+ });
// Alias unsafeWindow for compatibility.
Components.utils.evalInSandbox(
- 'const unsafeWindow = window;', contentSandbox);
-
- if (GM_util.compareFirefoxVersion("16.0") < 0) {
- // See #1350. The upstream bug was fixed in Firefox 16; apply workaround
- // only in older versions.
- contentSandbox.alert = alert;
- }
-
- return contentSandbox;
- }
-
- var sandbox = new Components.utils.Sandbox(
+ 'const unsafeWindow = window;', sandbox);
+ } else { // Otherwise, create a wrapped object
+ sandbox = new Components.utils.Sandbox(
aContentWin,
{
'sandboxName': aScript.id,
'sandboxPrototype': aContentWin,
'wantXrays': true,
});
- sandbox.unsafeWindow = aContentWin.wrappedJSObject;
- if (aFirebugConsole) sandbox.console = aFirebugConsole;
+ sandbox.unsafeWindow = aContentWin.wrappedJSObject;
+ // FIXME: why is this only done for the wrapped object?
+ if (aFirebugConsole) sandbox.console = aFirebugConsole;
+ }
+
+ // GM_info is always provided.
+ Components.utils.evalInSandbox(
+ 'const GM_info = ' + uneval(aScript.info()), sandbox);
if (GM_util.compareFirefoxVersion("16.0") < 0) {
// See #1350. The upstream bug was fixed in Firefox 16; apply workaround
@@ -149,6 +145,10 @@ function createSandbox(
sandbox.alert = alert;
}
+ // if there are no grants, return now
+ if (GM_util.inArray(aScript.grants, 'none'))
+ return sandbox;
+
var imp = sandbox.importFunction;
if (GM_util.inArray(aScript.grants, 'GM_addStyle')) {
imp(function(css) { GM_addStyle(aContentWin.document, css); },
@@ -196,13 +196,10 @@ function createSandbox(
}
if (GM_util.inArray(aScript.grants, 'GM_xmlhttpRequest')) {
sandbox.GM_xmlhttpRequest = GM_util.hitch(
- new GM_xmlhttpRequester(aContentWin, aChromeWin, aUrl),
+ new GM_xmlhttpRequester(aContentWin, aChromeWin, aUrl, aScript),
'contentStartRequest');
}
- Components.utils.evalInSandbox(
- 'const GM_info = ' + uneval(aScript.info()), sandbox);
-
return sandbox;
}
View
60 content/advancedscriptprefs.js
@@ -0,0 +1,60 @@
+Components.utils.import('resource://greasemonkey/util.js'); // ref'd in XUL
+
+var gScriptId = location.hash.substring(1);
+var gScript = GM_util.getService().config.getMatchingScripts(function(script) {
+ return script.id == gScriptId;
+})[0];
+
+var gUserTabEl;
+var gUserNoSandboxEl;
+var gScriptNoSandboxEl;
+var gCorsScriptIncludesEl;
+var gCorsScriptExcludesEl;
+var gCorsUserIncludesEl;
+var gCorsUserExcludesEl;
+
+function onAdvancedDialogLoad() {
+ // I wanted "%s" but % is reserved in a DTD and I don't know the literal.
+ document.title = document.title.replace('!!', gScript.name);
+
+ var gTabboxEl = document.getElementsByTagName('tabbox')[0];
+ gUserTabEl = gTabboxEl.tabs.getItemAtIndex(0);
+
+ gCorsUserIncludesEl = document.getElementById('cors-user-includes');
+ gCorsUserExcludesEl = document.getElementById('cors-user-excludes');
+ gUserNoSandboxEl = document.getElementById('user-nosandbox');
+
+ gCorsScriptIncludesEl = document.getElementById('cors-script-includes');
+ gCorsScriptExcludesEl = document.getElementById('cors-script-excludes');
+ gScriptNoSandboxEl = document.getElementById('script-nosandbox');
+
+ gCorsScriptIncludesEl.pages = gScript.corsIncludes;
+ gCorsScriptIncludesEl.onAddUserExclude = function(url) {
+ gCorsUserExcludesEl.addPage(url);
+ gTabboxEl.selectedTab = gUserTabEl;
+ };
+ gCorsUserIncludesEl.pages = gScript.corsUserIncludes;
+
+ gUserNoSandboxEl.checked = gScript.userNosandbox;
+ gScriptNoSandboxEl.checked = gScript.nosandbox;
+
+ gCorsScriptExcludesEl.pages = gScript.corsExcludes;
+ gCorsScriptExcludesEl.onAddUserInclude = function(url) {
+ gCorsUserIncludesEl.addPage(url);
+ gTabboxEl.selectedTab = gUserTabEl;
+ };
+
+ gCorsUserExcludesEl.pages = gScript.corsUserExcludes;
+}
+
+function onAdvancedDialogAccept() {
+ gScript.corsExcludes = gCorsScriptExcludesEl.pages;
+ gScript.corsIncludes = gCorsScriptIncludesEl.pages;
+ gScript.corsUserExcludes = gCorsUserExcludesEl.pages;
+ gScript.corsUserIncludes = gCorsUserIncludesEl.pages;
+ gScript.userNosandbox = gUserNoSandboxEl.checked;
+ gScript.nosandbox = gScriptNoSandboxEl.checked;
+ GM_util.getService().config._changed(gScript, "cludes");
+ return true;
+}
+
View
61 content/advancedscriptprefs.xul
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://greasemonkey/skin/bindings.css" type="text/css"?>
+<?xml-stylesheet href="chrome://greasemonkey/skin/scriptprefs.css" type="text/css"?>
+
+<!DOCTYPE prefwindow [
+<!ENTITY % addonsDTD SYSTEM "chrome://greasemonkey/locale/gm-addons.dtd">
+<!ENTITY % cludesDTD SYSTEM "chrome://greasemonkey/locale/gm-cludes.dtd">
+<!ENTITY % greasemonkeyDTD SYSTEM "chrome://greasemonkey/locale/greasemonkey.dtd">
+%addonsDTD;
+%cludesDTD;
+%greasemonkeyDTD;
+]>
+
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ buttons="accept,cancel"
+ title="&advancedscriptprefs.title;"
+ onload="return onAdvancedDialogLoad();"
+ ondialogaccept="return onAdvancedDialogAccept();"
+>
+<script type="application/x-javascript" src="chrome://greasemonkey/content/advancedscriptprefs.js" />
+
+<tabbox>
+ <tabs>
+ <tab label="&advancedscriptprefs.usersettings;" />
+ <tab label="&advancedscriptprefs.scriptsettings;" />
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <vbox flex="1">
+ <label value="&label.corsIncluded;" />
+ <cludes id="cors-user-includes"/>
+ <label value="&label.corsExcluded;" />
+ <cludes id="cors-user-excludes" />
+ <groupbox>
+ <caption label="&UnsafeScripting;" />
+ <checkbox id="user-nosandbox" label="&NoSandboxMode;" />
+ </groupbox>
+ </vbox>
+ </tabpanel>
+ <tabpanel>
+ <vbox flex="1">
+ <vbox flex="1" class="in">
+ <label value="&label.corsIncluded;" />
+ <cludes id="cors-script-includes" class="readonly" />
+ </vbox>
+ <vbox flex="1" class="ex">
+ <label value="&label.corsExcluded;" />
+ <cludes id="cors-script-excludes" class="readonly" />
+ </vbox>
+ <groupbox>
+ <caption label="&UnsafeScripting;" />
+ <checkbox id="script-nosandbox" label="&NoSandboxMode;" />
+ </groupbox>
+ </vbox>
+ </tabpanel>
+ </tabpanels>
+</tabbox>
+
+</dialog>
View
4 content/scriptprefs.js
@@ -46,3 +46,7 @@ function onDialogAccept() {
gScript.userExcludes = gUserExcludesEl.pages;
GM_util.getService().config._changed(gScript, "cludes");
}
+
+function onDisplayAdvancedDialog() {
+ openDialog('chrome://greasemonkey/content/advancedscriptprefs.xul#' + gScript.id, null, 'modal');
+}
View
4 content/scriptprefs.xul
@@ -14,9 +14,11 @@
]>
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- buttons="accept,cancel"
+ buttons="extra1,accept,cancel"
title="&scriptprefs.title;"
ondialogaccept="return onDialogAccept();"
+ buttonlabelextra1="Advanced"
+ ondialogextra1="return onDisplayAdvancedDialog();"
>
<script type="application/x-javascript" src="chrome://greasemonkey/content/scriptprefs.js" />
View
17 content/xmlhttprequester.js
@@ -1,9 +1,14 @@
Components.utils.import("resource://greasemonkey/util.js");
-function GM_xmlhttpRequester(wrappedContentWin, chromeWindow, originUrl) {
+function GM_xmlhttpRequester(wrappedContentWin, chromeWindow, originUrl, script) {
this.wrappedContentWin = wrappedContentWin;
this.chromeWindow = chromeWindow;
this.originUrl = originUrl;
+ this.script = script;
+ this.stringBundle = Components
+ .classes["@mozilla.org/intl/stringbundle;1"]
+ .getService(Components.interfaces.nsIStringBundleService)
+ .createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
}
// this function gets called by user scripts in content security scope to
@@ -27,10 +32,18 @@ GM_xmlhttpRequester.prototype.contentStartRequest = function(details) {
// A malformed URL won't be parsed properly.
throw new Error(
this.stringBundle.GetStringFromName('error.invalidUrl')
- .replace('%1', name)
+ .replace('%1', url)
);
}
+ // Ensure that the CORS policy allows this script to make the call
+ if (! this.script.corsAllowsURL(url)) {
+ throw new Error(
+ this.stringBundle.GetStringFromName('error.corsAccessDenied')
+ .replace('%1', url)
+ );
+ }
+
// This is important - without it, GM_xmlhttpRequest can be used to get
// access to things like files and chrome. Careful.
switch (uri.scheme) {
View
2 locale/en-US/gm-cludes.dtd
@@ -10,3 +10,5 @@
<!ENTITY button.remove "Remove">
<!ENTITY label.grpIncluded "Included Pages">
<!ENTITY label.grpExcluded "Excluded Pages">
+<!ENTITY label.corsIncluded "CORS Included URL's">
+<!ENTITY label.corsExcluded "CORS Excluded URL's">
View
5 locale/en-US/greasemonkey.dtd
@@ -37,6 +37,8 @@
<!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
<!ENTITY AlsoUninstallPrefs "Also uninstall associated preferences">
<!ENTITY UpdateChecking "Update Checking">
+<!ENTITY UnsafeScripting "Insecure Mode (allow full, unrestricted DOM and xmlHttpRequest access)">
+<!ENTITY NoSandboxMode "Warning: you should not enable this unless you fully understand the risk.">
<!ENTITY RequireSecureUpdates "Require secure updates">
<!ENTITY greasemonkey.noscriptshere "No installed scripts run on this page.">
<!ENTITY greasemonkey.youhavenoscripts "You don't have any user scripts installed">
@@ -44,3 +46,6 @@
<!ENTITY scriptprefs.title "Greasemonkey User Script Preferences - !!">
<!ENTITY scriptprefs.usersettings "User Settings">
<!ENTITY scriptprefs.scriptsettings "Script Settings">
+<!ENTITY advancedscriptprefs.title "Greasemonkey Advanced User Script Preferences - !!">
+<!ENTITY advancedscriptprefs.usersettings "Advanced User Settings">
+<!ENTITY advancedscriptprefs.scriptsettings "Advanced Script Settings">
View
1 locale/en-US/greasemonkey.properties
@@ -2,6 +2,7 @@ extensions.{e4a8a97b-f2ed-450b-b12d-ee082ba24781}.description=A User Script Mana
error.access-violation=Greasemonkey access violation: unsafeWindow cannot call %1.
error.args.getValue=Unsupported type for GM_setValue. Supported types are: string, bool, and 32 bit integers.
error.args.setValue=GM_setValue must specify two arguments: name and value.
+error.corsAccessDenied=Greasemonkey access violation: CORS policy does not permit access to URL %1.
error.disallowedScheme=Disallowed scheme in URL: %1
error.downloadingUrl=Error downloading URL:
error.invalidUrl=Invalid URL: %1
View
10 modules/parseScript.js
@@ -65,6 +65,12 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
script['_' + header] = value;
break;
+ case 'corsExclude':
+ script._corsExcludes.push(value);
+ break;
+ case 'corsInclude':
+ script._corsIncludes.push(value);
+ break;
case 'installURL':
header = 'downloadURL';
case 'downloadURL':
@@ -105,6 +111,10 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
);
}
break;
+ case 'nosandbox':
+ script['_' + header] = typeof(value) === 'undefined' ?
+ true : value == true.toString();
+ break;
case 'require':
try {
var reqUri = GM_util.uriFromUrl(value, aUri);
View
88 modules/script.js
@@ -28,6 +28,10 @@ function Script(configNode) {
this._observers = [];
this._basedir = null;
+ this._corsExcludes = [];
+ this._corsIncludes = [];
+ this._corsUserExcludes = [];
+ this._corsUserIncludes = [];
this._dependFail = false;
this._dependhash = null;
this._description = '';
@@ -44,6 +48,8 @@ function Script(configNode) {
this._modifiedTime = null;
this._name = 'user-script';
this._namespace = '';
+ this._nosandbox = false;
+ this._userNosandbox = false;
this._prefroot = null;
this._rawMeta = '';
this._requires = [];
@@ -95,6 +101,29 @@ Script.prototype.matchesURL = function(url) {
return (this._includes.some(testClude) || this._matches.some(testMatch));
};
+Script.prototype.corsAllowsURL = function(url) {
+ // For backwards-compatibility, we always allow access in cases where no
+ // in/excludes have been specified by either the script author or the user.
+ if (this._corsUserExcludes.length === 0 &&
+ this._corsUserIncludes.length === 0 &&
+ this._corsExcludes.length === 0 &&
+ this._corsIncludes.length === 0) return true;
+
+ var uri = GM_util.uriFromUrl(url);
+
+ function testClude(glob) {
+ return GM_convert2RegExp(glob, uri).test(url);
+ }
+
+ // Allow based on user cludes.
+ if (this._corsUserExcludes.some(testClude)) return false;
+ if (this._corsUserIncludes.some(testClude)) return true;
+
+ // Finally allow based on script cludes
+ if (this._corsExcludes.some(testClude)) return false;
+ return this._corsIncludes.some(testClude);
+};
+
Script.prototype._changed = function(event, data) {
GM_util.getService().config._changed(this, event, data);
};
@@ -111,6 +140,16 @@ function Script_getName() { return this._name; });
Script.prototype.__defineGetter__('namespace',
function Script_getNamespace() { return this._namespace; });
+Script.prototype.__defineGetter__('nosandbox',
+ function Script_getNosandbox() { return this._nosandbox; });
+Script.prototype.__defineSetter__('nosandbox',
+ function Script_setNosandbox(nosandbox) { this._nosandbox = nosandbox; });
+
+Script.prototype.__defineGetter__('userNosandbox',
+ function Script_getUserNosandbox() { return this._userNosandbox; });
+Script.prototype.__defineSetter__('userNosandbox',
+ function Script_setUserNosandbox(userNosandbox) { this._userNosandbox = userNosandbox; });
+
Script.prototype.__defineGetter__('id',
function Script_getId() {
if (!this._id) this._id = this._namespace + "/" + this._name;
@@ -179,6 +218,26 @@ function Script_getUserExcludes() { return this._userExcludes.concat(); });
Script.prototype.__defineSetter__('userExcludes',
function Script_setUserExcludes(excludes) { this._userExcludes = excludes.concat(); });
+Script.prototype.__defineGetter__('corsExcludes',
+ function Script_getCorsExcludes() { return this._corsExcludes.concat(); });
+Script.prototype.__defineSetter__('corsExcludes',
+ function Script_setCorsExcludes(excludes) { this._corsExcludes = excludes.concat(); });
+
+Script.prototype.__defineGetter__('corsIncludes',
+ function Script_getCorsIncludes() { return this._corsIncludes.concat(); });
+Script.prototype.__defineSetter__('corsIncludes',
+ function Script_setCorsIncludes(includes) { this._corsIncludes = includes.concat(); });
+
+Script.prototype.__defineGetter__('corsUserExcludes',
+ function Script_getCorsUserExcludes() { return this._corsUserExcludes.concat(); });
+Script.prototype.__defineSetter__('corsUserExcludes',
+ function Script_setCorsUserExcludes(excludes) { this._corsUserExcludes = excludes.concat(); });
+
+Script.prototype.__defineGetter__('corsUserIncludes',
+ function Script_getCorsUserIncludes() { return this._corsUserIncludes.concat(); });
+Script.prototype.__defineSetter__('corsUserIncludes',
+ function Script_setCorsUserIncludes(includes) { this._corsUserIncludes = includes.concat(); });
+
Script.prototype.__defineGetter__('matches',
function Script_getMatches() { return this._matches.concat(); });
@@ -314,6 +373,18 @@ Script.prototype._loadFromConfigNode = function(node) {
for (var i = 0, childNode; childNode = node.childNodes[i]; i++) {
switch (childNode.nodeName) {
+ case "CorsExclude":
+ this._corsExcludes.push(childNode.textContent);
+ break;
+ case "CorsInclude":
+ this._corsIncludes.push(childNode.textContent);
+ break;
+ case "CorsUserExclude":
+ this._corsUserExcludes.push(childNode.textContent);
+ break;
+ case "CorsUserInclude":
+ this._corsUserIncludes.push(childNode.textContent);
+ break;
case "Exclude":
this._excludes.push(childNode.textContent);
break;
@@ -355,6 +426,8 @@ Script.prototype._loadFromConfigNode = function(node) {
this._runAt = node.getAttribute("runAt") || "document-end"; // legacy default
this.icon.fileURL = node.getAttribute("icon");
this._enabled = node.getAttribute("enabled") == true.toString();
+ this._nosandbox = node.getAttribute("nosandbox") == true.toString();
+ this._userNosandbox = node.getAttribute("userNosandbox") == true.toString();
};
Script.prototype.toConfigNode = function(doc) {
@@ -373,6 +446,10 @@ Script.prototype.toConfigNode = function(doc) {
}
}
+ addArrayNodes('CorsExclude', this._corsExcludes);
+ addArrayNodes('CorsInclude', this._corsIncludes);
+ addArrayNodes('CorsUserExclude', this._corsUserExcludes);
+ addArrayNodes('CorsUserInclude', this._corsUserIncludes);
addArrayNodes('Exclude', this._excludes);
addArrayNodes('Grant', this._grants);
addArrayNodes('Include', this._includes);
@@ -423,6 +500,8 @@ Script.prototype.toConfigNode = function(doc) {
scriptNode.setAttribute("runAt", this._runAt);
scriptNode.setAttribute("uuid", this._uuid);
scriptNode.setAttribute("version", this._version);
+ scriptNode.setAttribute("nosandbox", this._nosandbox);
+ scriptNode.setAttribute("userNosandbox", this._userNosandbox);
if (this._downloadURL) {
scriptNode.setAttribute("installurl", this._downloadURL);
@@ -467,6 +546,8 @@ Script.prototype.info = function() {
'version': gGreasemonkeyVersion,
'scriptWillUpdate': this.isRemoteUpdateAllowed(),
'script': {
+ 'corsIncludes': this.corsIncludes,
+ 'corsExcludes': this.corsExcludes,
'description': this.description,
'excludes': this.excludes,
// 'icon': ???,
@@ -474,6 +555,8 @@ Script.prototype.info = function() {
'matches': matches,
'name': this.name,
'namespace': this.namespace,
+ 'nosandbox': this.nosandbox,
+ 'userNosandbox': this.userNosandbox, // FIXME: this likely needs removing
// 'requires': ???,
'resources': resources,
'run-at': this.runAt,
@@ -559,7 +642,9 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin) {
}
// Copy new values.
- // NOTE: User 'cludes are _not_ copied! They should remain as-is.
+ // NOTE: User 'cludes / nosandbox are _not_ copied! They should remain as-is.
+ this._corsExcludes = newScript._corsExcludes;
+ this._corsIncludes = newScript._corsIncludes;
this._excludes = newScript._excludes;
this._grants = newScript._grants;
this._includes = newScript._includes;
@@ -568,6 +653,7 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin) {
this._runAt = newScript._runAt;
this._version = newScript._version;
this._downloadURL = newScript._downloadURL;
+ this._nosandbox = newScript._nosandbox;
this.updateURL = newScript.updateURL;
this.showGrantWarning();
Something went wrong with that request. Please try again.