mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1213632: Prevent WebExtensions from using versioned JavaScript. r=billm
--HG-- extra : commitid : 3aQ4wS5I7LP extra : rebase_source : 252277140f700ab305877f3bfd0ba9b582ff0b7a
This commit is contained in:
parent
db0f60ba3d
commit
9768c79d20
@ -89,6 +89,9 @@
|
||||
"@mozilla.org/updates/update-processor;1"
|
||||
#endif
|
||||
|
||||
#define NS_ADDONCONTENTPOLICY_CONTRACTID \
|
||||
"@mozilla.org/addons/content-policy;1"
|
||||
|
||||
#define NS_ADDONPATHSERVICE_CONTRACTID \
|
||||
"@mozilla.org/addon-path-service;1"
|
||||
|
||||
@ -178,5 +181,8 @@
|
||||
#define NS_APPLICATION_REPUTATION_SERVICE_CID \
|
||||
{ 0x8576c950, 0xf4a2, 0x11e2, { 0xb7, 0x78, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
|
||||
|
||||
#define NS_ADDONCONTENTPOLICY_CID \
|
||||
{ 0xc26a8241, 0xecf4, 0x4aed, { 0x9f, 0x3c, 0xf1, 0xf5, 0xc7, 0x13, 0xb9, 0xa5 } }
|
||||
|
||||
#define NS_ADDON_PATH_SERVICE_CID \
|
||||
{ 0xa39f39d0, 0xdfb6, 0x11e3, { 0x8b, 0x68, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nsBrowserStatusFilter.h"
|
||||
#include "mozilla/FinalizationWitnessService.h"
|
||||
#include "mozilla/NativeOSFileInternals.h"
|
||||
#include "mozilla/AddonContentPolicy.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
@ -125,6 +126,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(FinalizationWitnessService, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(NativeOSFileInternalsService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID);
|
||||
@ -158,6 +160,7 @@ NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
|
||||
|
||||
@ -192,6 +195,7 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
||||
#endif
|
||||
{ &kFINALIZATIONWITNESSSERVICE_CID, false, nullptr, FinalizationWitnessServiceConstructor },
|
||||
{ &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor },
|
||||
{ &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
|
||||
{ &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
|
||||
{ &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
|
||||
{ nullptr }
|
||||
@ -228,15 +232,22 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
|
||||
#endif
|
||||
{ FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID },
|
||||
{ NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID },
|
||||
{ NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID },
|
||||
{ NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID },
|
||||
{ NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::CategoryEntry kToolkitCategories[] = {
|
||||
{ "content-policy", NS_ADDONCONTENTPOLICY_CONTRACTID, NS_ADDONCONTENTPOLICY_CONTRACTID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const Module kToolkitModule = {
|
||||
Module::kVersion,
|
||||
kToolkitCIDs,
|
||||
kToolkitContracts
|
||||
kToolkitContracts,
|
||||
kToolkitCategories
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsToolkitCompsModule) = &kToolkitModule;
|
||||
|
@ -33,3 +33,5 @@ support-files =
|
||||
[test_ext_bookmarks.html]
|
||||
[test_ext_alarms.html]
|
||||
[test_ext_background_window_properties.html]
|
||||
[test_ext_jsversion.html]
|
||||
skip-if = e10s # Uses a console monitor which doesn't work from a content process. The code being tested doesn't run in a tab content process in any case.
|
||||
|
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for simple WebExtension</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
add_task(function* test_versioned_js() {
|
||||
// We need to deal with escaping the close script tags.
|
||||
// May as well consolidate it into one place.
|
||||
let script = attrs => `<script ${attrs}></${'script'}>`;
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"background": {"page": "background.html"}
|
||||
},
|
||||
|
||||
files: {
|
||||
"background.html": `
|
||||
<meta charset="utf-8">
|
||||
${script('src="background.js" type="application/javascript"')}
|
||||
${script('src="background-1.js" type="application/javascript;version=1.8"')}
|
||||
${script('src="background-2.js" type="application/javascript;version=latest"')}
|
||||
${script('src="background-3.js" type="application/javascript"')}
|
||||
`,
|
||||
|
||||
"background.js": "new " + function () {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.assertEq(
|
||||
msg, "background-script-3",
|
||||
"Expected a message only from the unversioned background script.");
|
||||
|
||||
browser.test.sendMessage("finished");
|
||||
});
|
||||
},
|
||||
|
||||
"background-1.js": "new " + function () {
|
||||
browser.runtime.sendMessage("background-script-1");
|
||||
},
|
||||
"background-2.js": "new " + function () {
|
||||
browser.runtime.sendMessage("background-script-2");
|
||||
},
|
||||
"background-3.js": "new " + function () {
|
||||
browser.runtime.sendMessage("background-script-3");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let messages = [/Versioned JavaScript.*not supported in WebExtension.*developer\.mozilla\.org/,
|
||||
/Versioned JavaScript.*not supported in WebExtension.*developer\.mozilla\.org/];
|
||||
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, messages);
|
||||
});
|
||||
|
||||
info("loading extension");
|
||||
|
||||
yield Promise.all([extension.startup(),
|
||||
extension.awaitMessage("finished")]);
|
||||
|
||||
info("waiting for console");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
|
||||
info("unloading extension");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
info("test complete");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
145
toolkit/mozapps/extensions/AddonContentPolicy.cpp
Normal file
145
toolkit/mozapps/extensions/AddonContentPolicy.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "AddonContentPolicy.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
/* Enforces content policies for WebExtension scopes. Currently:
|
||||
*
|
||||
* - Prevents loading scripts with a non-default JavaScript version.
|
||||
*/
|
||||
|
||||
#define VERSIONED_JS_BLOCKED_MESSAGE \
|
||||
MOZ_UTF16("Versioned JavaScript is a non-standard, deprecated extension, and is ") \
|
||||
MOZ_UTF16("not supported in WebExtension code. For alternatives, please see: ") \
|
||||
MOZ_UTF16("https://developer.mozilla.org/Add-ons/WebExtensions/Tips")
|
||||
|
||||
AddonContentPolicy::AddonContentPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
AddonContentPolicy::~AddonContentPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(AddonContentPolicy, nsIContentPolicy)
|
||||
|
||||
static nsresult
|
||||
GetWindowIDFromContext(nsISupports* aContext, uint64_t *aResult)
|
||||
{
|
||||
NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aContext);
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDocument> document = content->OwnerDoc();
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = document->GetInnerWindow();
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
|
||||
|
||||
*aResult = window->WindowID();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
LogMessage(const nsAString &aMessage, nsIURI* aSourceURI, const nsAString &aSourceSample,
|
||||
nsISupports* aContext)
|
||||
{
|
||||
nsCOMPtr<nsIScriptError> error = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
||||
NS_ENSURE_TRUE(error, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoCString sourceName;
|
||||
nsresult rv = aSourceURI->GetSpec(sourceName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint64_t windowID = 0;
|
||||
GetWindowIDFromContext(aContext, &windowID);
|
||||
|
||||
rv = error->InitWithWindowID(aMessage, NS_ConvertUTF8toUTF16(sourceName),
|
||||
aSourceSample, 0, 0, nsIScriptError::errorFlag,
|
||||
"JavaScript", windowID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIConsoleService> console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(console, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
console->LogMessage(error);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AddonContentPolicy::ShouldLoad(uint32_t aContentType,
|
||||
nsIURI* aContentLocation,
|
||||
nsIURI* aRequestOrigin,
|
||||
nsISupports* aContext,
|
||||
const nsACString& aMimeTypeGuess,
|
||||
nsISupports* aExtra,
|
||||
nsIPrincipal* aRequestPrincipal,
|
||||
int16_t* aShouldLoad)
|
||||
{
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
*aShouldLoad = nsIContentPolicy::ACCEPT;
|
||||
|
||||
if (!aRequestOrigin) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Only apply this policy to requests from documents loaded from
|
||||
// moz-extension URLs, or to resources being loaded from moz-extension URLs.
|
||||
bool equals;
|
||||
if (!((NS_SUCCEEDED(aContentLocation->SchemeIs("moz-extension", &equals)) && equals) ||
|
||||
(NS_SUCCEEDED(aRequestOrigin->SchemeIs("moz-extension", &equals)) && equals))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aContentType == nsIContentPolicy::TYPE_SCRIPT) {
|
||||
NS_ConvertUTF8toUTF16 typeString(aMimeTypeGuess);
|
||||
nsContentTypeParser mimeParser(typeString);
|
||||
|
||||
// Reject attempts to load JavaScript scripts with a non-default version.
|
||||
nsAutoString mimeType, version;
|
||||
if (NS_SUCCEEDED(mimeParser.GetType(mimeType)) &&
|
||||
nsContentUtils::IsJavascriptMIMEType(mimeType) &&
|
||||
NS_SUCCEEDED(mimeParser.GetParameter("version", version))) {
|
||||
*aShouldLoad = nsIContentPolicy::REJECT_REQUEST;
|
||||
|
||||
LogMessage(NS_MULTILINE_LITERAL_STRING(VERSIONED_JS_BLOCKED_MESSAGE),
|
||||
aRequestOrigin, typeString, aContext);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AddonContentPolicy::ShouldProcess(uint32_t aContentType,
|
||||
nsIURI* aContentLocation,
|
||||
nsIURI* aRequestOrigin,
|
||||
nsISupports* aRequestingContext,
|
||||
const nsACString& aMimeTypeGuess,
|
||||
nsISupports* aExtra,
|
||||
nsIPrincipal* aRequestPrincipal,
|
||||
int16_t* aShouldProcess)
|
||||
{
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
*aShouldProcess = nsIContentPolicy::ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
19
toolkit/mozapps/extensions/AddonContentPolicy.h
Normal file
19
toolkit/mozapps/extensions/AddonContentPolicy.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsIContentPolicy.h"
|
||||
|
||||
class AddonContentPolicy : public nsIContentPolicy
|
||||
{
|
||||
protected:
|
||||
virtual ~AddonContentPolicy();
|
||||
|
||||
public:
|
||||
AddonContentPolicy();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPOLICY
|
||||
};
|
@ -49,11 +49,13 @@ if CONFIG['MOZ_EM_DEBUG']:
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AddonContentPolicy.h',
|
||||
'AddonPathService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AddonPathService.cpp'
|
||||
'AddonContentPolicy.cpp',
|
||||
'AddonPathService.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
Loading…
Reference in New Issue
Block a user