2017-05-24 05:15:10 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
|
|
/* 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 "mozilla/ExtensionPolicyService.h"
|
2018-08-01 07:50:34 +03:00
|
|
|
#include "mozilla/extensions/DocumentObserver.h"
|
2017-06-04 08:03:19 +03:00
|
|
|
#include "mozilla/extensions/WebExtensionContentScript.h"
|
2017-05-24 05:15:10 +03:00
|
|
|
#include "mozilla/extensions/WebExtensionPolicy.h"
|
2017-06-04 03:12:14 +03:00
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
2018-01-13 03:01:18 +03:00
|
|
|
#include "mozilla/ResultExtensions.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "mozilla/Services.h"
|
2018-08-18 08:09:23 +03:00
|
|
|
#include "mozilla/SimpleEnumerator.h"
|
2017-05-26 22:07:06 +03:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2018-08-18 08:09:23 +03:00
|
|
|
#include "mozilla/dom/ContentFrameMessageManager.h"
|
2017-05-26 22:07:06 +03:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2018-08-18 08:09:23 +03:00
|
|
|
#include "mozilla/dom/Promise.h"
|
|
|
|
#include "mozilla/dom/Promise-inl.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "mozIExtensionProcessScript.h"
|
2017-06-04 03:12:14 +03:00
|
|
|
#include "nsEscape.h"
|
2017-05-24 05:15:10 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "nsIChannel.h"
|
|
|
|
#include "nsIContentPolicy.h"
|
2018-08-18 08:09:23 +03:00
|
|
|
#include "nsIDocShell.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "nsIDocument.h"
|
2018-08-18 08:30:17 +03:00
|
|
|
#include "nsGlobalWindowOuter.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "nsILoadInfo.h"
|
2017-09-15 01:12:45 +03:00
|
|
|
#include "nsIXULRuntime.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "nsNetUtil.h"
|
2018-09-28 23:54:09 +03:00
|
|
|
#include "nsPrintfCString.h"
|
2017-06-05 01:38:11 +03:00
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsXULAppAPI.h"
|
2018-08-18 08:09:23 +03:00
|
|
|
#include "nsQueryObject.h"
|
2017-05-24 05:15:10 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace extensions;
|
|
|
|
|
2018-08-18 08:09:23 +03:00
|
|
|
using dom::AutoJSAPI;
|
|
|
|
using dom::ContentFrameMessageManager;
|
|
|
|
using dom::Promise;
|
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
#define DEFAULT_BASE_CSP \
|
|
|
|
"script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; " \
|
|
|
|
"object-src 'self' https://* moz-extension: blob: filesystem:;"
|
|
|
|
|
|
|
|
#define DEFAULT_DEFAULT_CSP \
|
|
|
|
"script-src 'self'; object-src 'self';"
|
|
|
|
|
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
#define OBS_TOPIC_PRELOAD_SCRIPT "web-extension-preload-content-script"
|
|
|
|
#define OBS_TOPIC_LOAD_SCRIPT "web-extension-load-content-script"
|
|
|
|
|
|
|
|
|
|
|
|
static mozIExtensionProcessScript&
|
|
|
|
ProcessScript()
|
|
|
|
{
|
|
|
|
static nsCOMPtr<mozIExtensionProcessScript> sProcessScript;
|
|
|
|
|
|
|
|
if (MOZ_UNLIKELY(!sProcessScript)) {
|
|
|
|
sProcessScript = do_GetService("@mozilla.org/webextensions/extension-process-script;1");
|
|
|
|
MOZ_RELEASE_ASSERT(sProcessScript);
|
|
|
|
ClearOnShutdown(&sProcessScript);
|
|
|
|
}
|
|
|
|
return *sProcessScript;
|
|
|
|
}
|
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
/*****************************************************************************
|
|
|
|
* ExtensionPolicyService
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2017-05-26 22:07:06 +03:00
|
|
|
/* static */ bool ExtensionPolicyService::sRemoteExtensions;
|
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
/* static */ ExtensionPolicyService&
|
|
|
|
ExtensionPolicyService::GetSingleton()
|
|
|
|
{
|
|
|
|
static RefPtr<ExtensionPolicyService> sExtensionPolicyService;
|
|
|
|
|
|
|
|
if (MOZ_UNLIKELY(!sExtensionPolicyService)) {
|
|
|
|
sExtensionPolicyService = new ExtensionPolicyService();
|
2018-01-13 03:01:18 +03:00
|
|
|
RegisterWeakMemoryReporter(sExtensionPolicyService);
|
2017-05-24 05:15:10 +03:00
|
|
|
ClearOnShutdown(&sExtensionPolicyService);
|
|
|
|
}
|
|
|
|
return *sExtensionPolicyService.get();
|
|
|
|
}
|
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
ExtensionPolicyService::ExtensionPolicyService()
|
|
|
|
{
|
|
|
|
mObs = services::GetObserverService();
|
|
|
|
MOZ_RELEASE_ASSERT(mObs);
|
|
|
|
|
2017-05-26 22:07:06 +03:00
|
|
|
Preferences::AddBoolVarCache(&sRemoteExtensions, "extensions.webextensions.remote", false);
|
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
RegisterObservers();
|
|
|
|
}
|
|
|
|
|
2018-01-13 03:01:18 +03:00
|
|
|
ExtensionPolicyService::~ExtensionPolicyService()
|
|
|
|
{
|
|
|
|
UnregisterWeakMemoryReporter(this);
|
|
|
|
}
|
|
|
|
|
2017-09-15 01:12:45 +03:00
|
|
|
bool
|
|
|
|
ExtensionPolicyService::UseRemoteExtensions() const
|
|
|
|
{
|
|
|
|
return sRemoteExtensions && BrowserTabsRemoteAutostart();
|
|
|
|
}
|
2017-05-24 05:15:10 +03:00
|
|
|
|
2017-05-26 22:07:06 +03:00
|
|
|
bool
|
|
|
|
ExtensionPolicyService::IsExtensionProcess() const
|
|
|
|
{
|
2017-09-15 01:12:45 +03:00
|
|
|
bool isRemote = UseRemoteExtensions();
|
|
|
|
|
|
|
|
if (isRemote && XRE_IsContentProcess()) {
|
2017-05-26 22:07:06 +03:00
|
|
|
auto& remoteType = dom::ContentChild::GetSingleton()->GetRemoteType();
|
|
|
|
return remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE);
|
|
|
|
}
|
2017-09-15 01:12:45 +03:00
|
|
|
return !isRemote && XRE_IsParentProcess();
|
2017-05-26 22:07:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
WebExtensionPolicy*
|
|
|
|
ExtensionPolicyService::GetByURL(const URLInfo& aURL)
|
|
|
|
{
|
|
|
|
if (aURL.Scheme() == nsGkAtoms::moz_extension) {
|
|
|
|
return GetByHost(aURL.Host());
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::GetAll(nsTArray<RefPtr<WebExtensionPolicy>>& aResult)
|
|
|
|
{
|
|
|
|
for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
aResult.AppendElement(iter.Data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ExtensionPolicyService::RegisterExtension(WebExtensionPolicy& aPolicy)
|
|
|
|
{
|
|
|
|
bool ok = (!GetByID(aPolicy.Id()) &&
|
|
|
|
!GetByHost(aPolicy.MozExtensionHostname()));
|
|
|
|
MOZ_ASSERT(ok);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mExtensions.Put(aPolicy.Id(), &aPolicy);
|
|
|
|
mExtensionHosts.Put(aPolicy.MozExtensionHostname(), &aPolicy);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ExtensionPolicyService::UnregisterExtension(WebExtensionPolicy& aPolicy)
|
|
|
|
{
|
|
|
|
bool ok = (GetByID(aPolicy.Id()) == &aPolicy &&
|
|
|
|
GetByHost(aPolicy.MozExtensionHostname()) == &aPolicy);
|
|
|
|
MOZ_ASSERT(ok);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mExtensions.Remove(aPolicy.Id());
|
|
|
|
mExtensionHosts.Remove(aPolicy.MozExtensionHostname());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-01 07:50:34 +03:00
|
|
|
bool
|
|
|
|
ExtensionPolicyService::RegisterObserver(DocumentObserver& aObserver)
|
|
|
|
{
|
|
|
|
if (mObservers.GetWeak(&aObserver)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mObservers.Put(&aObserver, &aObserver);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ExtensionPolicyService::UnregisterObserver(DocumentObserver& aObserver)
|
|
|
|
{
|
|
|
|
if (!mObservers.GetWeak(&aObserver)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mObservers.Remove(&aObserver);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-05-24 05:15:10 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::BaseCSP(nsAString& aBaseCSP) const
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2017-07-31 03:52:51 +03:00
|
|
|
rv = Preferences::GetString("extensions.webextensions.base-content-security-policy", aBaseCSP);
|
2017-05-24 05:15:10 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aBaseCSP.AssignLiteral(DEFAULT_BASE_CSP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::DefaultCSP(nsAString& aDefaultCSP) const
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2017-07-31 03:52:51 +03:00
|
|
|
rv = Preferences::GetString("extensions.webextensions.default-content-security-policy", aDefaultCSP);
|
2017-05-24 05:15:10 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aDefaultCSP.AssignLiteral(DEFAULT_DEFAULT_CSP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-04 03:12:14 +03:00
|
|
|
|
2018-01-13 03:01:18 +03:00
|
|
|
/*****************************************************************************
|
|
|
|
* nsIMemoryReporter
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ExtensionPolicyService::CollectReports(nsIHandleReportCallback* aHandleReport,
|
|
|
|
nsISupports* aData, bool aAnonymize)
|
|
|
|
{
|
|
|
|
for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
auto& ext = iter.Data();
|
|
|
|
|
|
|
|
nsAtomCString id(ext->Id());
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 name(ext->Name());
|
|
|
|
name.ReplaceSubstring("\"", "");
|
|
|
|
name.ReplaceSubstring("\\", "");
|
|
|
|
|
|
|
|
nsString url;
|
|
|
|
MOZ_TRY_VAR(url, ext->GetURL(NS_LITERAL_STRING("")));
|
|
|
|
|
|
|
|
nsPrintfCString desc("Extension(id=%s, name=\"%s\", baseURL=%s)",
|
|
|
|
id.get(), name.get(),
|
|
|
|
NS_ConvertUTF16toUTF8(url).get());
|
|
|
|
desc.ReplaceChar('/', '\\');
|
|
|
|
|
|
|
|
nsCString path("extensions/");
|
|
|
|
path.Append(desc);
|
|
|
|
|
|
|
|
aHandleReport->Callback(
|
|
|
|
EmptyCString(), path,
|
|
|
|
KIND_NONHEAP, UNITS_COUNT, 1,
|
|
|
|
NS_LITERAL_CSTRING("WebExtensions that are active in this session"),
|
|
|
|
aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
/*****************************************************************************
|
|
|
|
* Content script management
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::RegisterObservers()
|
|
|
|
{
|
|
|
|
mObs->AddObserver(this, "content-document-global-created", false);
|
|
|
|
mObs->AddObserver(this, "document-element-inserted", false);
|
2018-08-18 08:09:23 +03:00
|
|
|
mObs->AddObserver(this, "tab-content-frameloader-created", false);
|
2017-06-05 01:38:11 +03:00
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
mObs->AddObserver(this, "http-on-opening-request", false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::UnregisterObservers()
|
|
|
|
{
|
|
|
|
mObs->RemoveObserver(this, "content-document-global-created");
|
|
|
|
mObs->RemoveObserver(this, "document-element-inserted");
|
2018-08-18 08:09:23 +03:00
|
|
|
mObs->RemoveObserver(this, "tab-content-frameloader-created");
|
2017-06-05 01:38:11 +03:00
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
mObs->RemoveObserver(this, "http-on-opening-request");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
|
|
|
{
|
|
|
|
if (!strcmp(aTopic, "content-document-global-created")) {
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(aSubject);
|
|
|
|
if (win) {
|
|
|
|
CheckWindow(win);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(aTopic, "document-element-inserted")) {
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
|
|
|
|
if (doc) {
|
|
|
|
CheckDocument(doc);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(aTopic, "http-on-opening-request")) {
|
|
|
|
nsCOMPtr<nsIChannel> chan = do_QueryInterface(aSubject);
|
|
|
|
if (chan) {
|
|
|
|
CheckRequest(chan);
|
|
|
|
}
|
2018-08-18 08:09:23 +03:00
|
|
|
} else if (!strcmp(aTopic, "tab-content-frameloader-created")) {
|
|
|
|
RefPtr<ContentFrameMessageManager> mm = do_QueryObject(aSubject);
|
|
|
|
NS_ENSURE_TRUE(mm, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
mMessageManagers.PutEntry(mm);
|
|
|
|
|
|
|
|
mm->AddSystemEventListener(NS_LITERAL_STRING("unload"), this,
|
|
|
|
false, false);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::HandleEvent(dom::Event* aEvent)
|
|
|
|
{
|
|
|
|
RefPtr<ContentFrameMessageManager> mm = do_QueryObject(aEvent->GetTarget());
|
|
|
|
MOZ_ASSERT(mm);
|
|
|
|
if (mm) {
|
|
|
|
mMessageManagers.RemoveEntry(mm);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ForEachDocShell(nsIDocShell* aDocShell,
|
|
|
|
const std::function<nsresult(nsIDocShell*)>& aCallback)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> iter;
|
|
|
|
MOZ_TRY(aDocShell->GetDocShellEnumerator(nsIDocShell::typeContent,
|
|
|
|
nsIDocShell::ENUMERATE_FORWARDS,
|
|
|
|
getter_AddRefs(iter)));
|
|
|
|
|
2018-08-25 08:31:10 +03:00
|
|
|
for (auto& docShell : SimpleEnumerator<nsIDocShell>(iter)) {
|
|
|
|
MOZ_TRY(aCallback(docShell));
|
2018-08-18 08:09:23 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
already_AddRefed<Promise>
|
|
|
|
ExtensionPolicyService::ExecuteContentScript(nsPIDOMWindowInner* aWindow,
|
|
|
|
WebExtensionContentScript& aScript)
|
|
|
|
{
|
|
|
|
if (!aWindow->IsCurrentInnerWindow()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Promise> promise;
|
|
|
|
ProcessScript().LoadContentScript(&aScript, aWindow, getter_AddRefs(promise));
|
|
|
|
return promise.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Promise>
|
|
|
|
ExtensionPolicyService::ExecuteContentScripts(JSContext* aCx, nsPIDOMWindowInner* aWindow,
|
|
|
|
const nsTArray<RefPtr<WebExtensionContentScript>>& aScripts)
|
|
|
|
{
|
|
|
|
AutoTArray<RefPtr<Promise>, 8> promises;
|
|
|
|
|
|
|
|
for (auto& script : aScripts) {
|
2018-08-26 00:02:26 +03:00
|
|
|
if (RefPtr<Promise> promise = ExecuteContentScript(aWindow, *script)) {
|
|
|
|
promises.AppendElement(std::move(promise));
|
|
|
|
}
|
2018-08-18 08:09:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Promise> promise = Promise::All(aCx, promises, IgnoreErrors());
|
|
|
|
MOZ_RELEASE_ASSERT(promise);
|
|
|
|
return promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::InjectContentScripts(WebExtensionPolicy* aExtension)
|
|
|
|
{
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
|
|
|
|
|
|
|
|
for (auto iter = mMessageManagers.ConstIter(); !iter.Done(); iter.Next()) {
|
|
|
|
ContentFrameMessageManager* mm = iter.Get()->GetKey();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShell> docShell = mm->GetDocShell(IgnoreErrors());
|
|
|
|
NS_ENSURE_TRUE(docShell, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
auto result = ForEachDocShell(docShell, [&](nsIDocShell* aDocShell) -> nsresult {
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win = aDocShell->GetWindow();
|
2018-08-26 00:00:03 +03:00
|
|
|
if (!win->GetDocumentURI()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2018-08-18 08:09:23 +03:00
|
|
|
DocInfo docInfo(win);
|
|
|
|
|
|
|
|
using RunAt = dom::ContentScriptRunAt;
|
|
|
|
using Scripts = AutoTArray<RefPtr<WebExtensionContentScript>, 8>;
|
|
|
|
|
|
|
|
constexpr uint8_t n = uint8_t(RunAt::EndGuard_);
|
|
|
|
Scripts scripts[n];
|
|
|
|
|
|
|
|
auto GetScripts = [&](RunAt aRunAt) -> Scripts&& {
|
|
|
|
return std::move(scripts[uint8_t(aRunAt)]);
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto& script : aExtension->ContentScripts()) {
|
|
|
|
if (script->Matches(docInfo)) {
|
|
|
|
GetScripts(script->RunAt()).AppendElement(script);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> inner = win->GetCurrentInnerWindow();
|
|
|
|
|
|
|
|
MOZ_TRY(ExecuteContentScripts(jsapi.cx(), inner, GetScripts(RunAt::Document_start))
|
|
|
|
->ThenWithCycleCollectedArgs([](JSContext* aCx, JS::HandleValue aValue,
|
|
|
|
ExtensionPolicyService* aSelf,
|
|
|
|
nsPIDOMWindowInner* aInner,
|
|
|
|
Scripts&& aScripts) {
|
|
|
|
return aSelf->ExecuteContentScripts(aCx, aInner, aScripts).forget();
|
|
|
|
},
|
|
|
|
this, inner, GetScripts(RunAt::Document_end))
|
|
|
|
.andThen([&](auto aPromise) {
|
|
|
|
return aPromise->ThenWithCycleCollectedArgs([](JSContext* aCx,
|
|
|
|
JS::HandleValue aValue,
|
|
|
|
ExtensionPolicyService* aSelf,
|
|
|
|
nsPIDOMWindowInner* aInner,
|
|
|
|
Scripts&& aScripts) {
|
|
|
|
return aSelf->ExecuteContentScripts(aCx, aInner, aScripts).forget();
|
|
|
|
},
|
|
|
|
this, inner, GetScripts(RunAt::Document_idle));
|
|
|
|
}));
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
});
|
|
|
|
MOZ_TRY(result);
|
2017-06-05 01:38:11 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks a request for matching content scripts, and begins pre-loading them
|
|
|
|
// if necessary.
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::CheckRequest(nsIChannel* aChannel)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
|
|
|
if (!loadInfo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto loadType = loadInfo->GetExternalContentPolicyType();
|
|
|
|
if (loadType != nsIContentPolicy::TYPE_DOCUMENT &&
|
|
|
|
loadType != nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
if (NS_FAILED(aChannel->GetURI(getter_AddRefs(uri)))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckContentScripts({uri.get(), loadInfo}, true);
|
|
|
|
}
|
|
|
|
|
2018-08-18 08:30:17 +03:00
|
|
|
static bool
|
|
|
|
CheckParentFrames(nsPIDOMWindowOuter* aWindow, WebExtensionPolicy& aPolicy)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURI> aboutAddons;
|
|
|
|
if (NS_FAILED(NS_NewURI(getter_AddRefs(aboutAddons), "about:addons"))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* piWin = aWindow;
|
|
|
|
while ((piWin = piWin->GetScriptableParentOrNull())) {
|
|
|
|
auto* win = nsGlobalWindowOuter::Cast(piWin);
|
|
|
|
|
|
|
|
auto* principal = BasePrincipal::Cast(win->GetPrincipal());
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
|
|
|
// The add-on manager is a special case, since it contains extension
|
|
|
|
// options pages in same-type <browser> frames.
|
|
|
|
bool equals;
|
|
|
|
if (NS_SUCCEEDED(win->GetDocumentURI()->Equals(aboutAddons, &equals)) &&
|
|
|
|
equals) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (principal->AddonPolicy() != &aPolicy) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
// Checks a document, just after the document element has been inserted, for
|
|
|
|
// matching content scripts or extension principals, and loads them if
|
|
|
|
// necessary.
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::CheckDocument(nsIDocument* aDocument)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
|
|
|
|
if (win) {
|
2018-08-18 08:09:23 +03:00
|
|
|
nsIDocShell* docShell = win->GetDocShell();
|
|
|
|
RefPtr<ContentFrameMessageManager> mm = docShell->GetMessageManager();
|
|
|
|
if (!mm || !mMessageManagers.Contains(mm)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-05 20:26:06 +03:00
|
|
|
if (win->GetDocumentURI()) {
|
|
|
|
CheckContentScripts(win.get(), false);
|
|
|
|
}
|
2017-05-26 22:07:06 +03:00
|
|
|
|
|
|
|
nsIPrincipal* principal = aDocument->NodePrincipal();
|
|
|
|
|
2017-09-05 21:04:43 +03:00
|
|
|
RefPtr<WebExtensionPolicy> policy = BasePrincipal::Cast(principal)->AddonPolicy();
|
2017-05-26 22:07:06 +03:00
|
|
|
if (policy) {
|
2018-08-18 08:30:17 +03:00
|
|
|
bool privileged = IsExtensionProcess() && CheckParentFrames(win, *policy);
|
|
|
|
|
|
|
|
ProcessScript().InitExtensionDocument(policy, aDocument, privileged);
|
2017-05-26 22:07:06 +03:00
|
|
|
}
|
2017-06-05 01:38:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks for loads of about:blank into new window globals, and loads any
|
|
|
|
// matching content scripts. about:blank loads do not trigger document element
|
|
|
|
// inserted events, so they're the only load type that are special cased this
|
|
|
|
// way.
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::CheckWindow(nsPIDOMWindowOuter* aWindow)
|
|
|
|
{
|
|
|
|
// We only care about non-initial document loads here. The initial
|
|
|
|
// about:blank document will usually be re-used to load another document.
|
|
|
|
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
|
2017-06-22 03:31:43 +03:00
|
|
|
if (!doc || doc->IsInitialDocument() ||
|
|
|
|
doc->GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED) {
|
2017-06-05 01:38:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-22 03:31:43 +03:00
|
|
|
nsCOMPtr<nsIURI> docUri = doc->GetDocumentURI();
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2018-07-23 14:28:47 +03:00
|
|
|
if (!docUri || NS_FAILED(NS_GetURIWithoutRef(docUri, getter_AddRefs(uri))) ||
|
2017-06-22 03:31:43 +03:00
|
|
|
!NS_IsAboutBlank(uri)) {
|
2017-06-05 01:38:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-18 08:09:23 +03:00
|
|
|
nsIDocShell* docShell = aWindow->GetDocShell();
|
|
|
|
if (RefPtr<ContentFrameMessageManager> mm = docShell->GetMessageManager()) {
|
|
|
|
if (mMessageManagers.Contains(mm)) {
|
|
|
|
CheckContentScripts(aWindow, false);
|
|
|
|
}
|
|
|
|
}
|
2017-06-05 01:38:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExtensionPolicyService::CheckContentScripts(const DocInfo& aDocInfo, bool aIsPreload)
|
|
|
|
{
|
2018-08-24 02:01:25 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> win;
|
|
|
|
if (!aIsPreload) {
|
|
|
|
win = aDocInfo.GetWindow()->GetCurrentInnerWindow();
|
|
|
|
}
|
2018-08-18 08:09:23 +03:00
|
|
|
|
2017-06-05 01:38:11 +03:00
|
|
|
for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
RefPtr<WebExtensionPolicy> policy = iter.Data();
|
|
|
|
|
|
|
|
for (auto& script : policy->ContentScripts()) {
|
|
|
|
if (script->Matches(aDocInfo)) {
|
|
|
|
if (aIsPreload) {
|
|
|
|
ProcessScript().PreloadContentScript(script);
|
|
|
|
} else {
|
2018-08-24 02:05:55 +03:00
|
|
|
if (!win->IsCurrentInnerWindow()) {
|
|
|
|
break;
|
|
|
|
}
|
2018-08-18 08:09:23 +03:00
|
|
|
RefPtr<Promise> promise;
|
|
|
|
ProcessScript().LoadContentScript(script, win, getter_AddRefs(promise));
|
2017-06-05 01:38:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-01 07:50:34 +03:00
|
|
|
|
|
|
|
for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
RefPtr<DocumentObserver> observer = iter.Data();
|
|
|
|
|
|
|
|
for (auto& matcher : observer->Matchers()) {
|
|
|
|
if (matcher->Matches(aDocInfo)) {
|
|
|
|
if (aIsPreload) {
|
|
|
|
observer->NotifyMatch(*matcher, aDocInfo.GetLoadInfo());
|
|
|
|
} else {
|
|
|
|
observer->NotifyMatch(*matcher, aDocInfo.GetWindow());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-05 01:38:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-06-04 03:12:14 +03:00
|
|
|
/*****************************************************************************
|
|
|
|
* nsIAddonPolicyService
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::GetBaseCSP(nsAString& aBaseCSP)
|
|
|
|
{
|
|
|
|
BaseCSP(aBaseCSP);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::GetDefaultCSP(nsAString& aDefaultCSP)
|
|
|
|
{
|
|
|
|
DefaultCSP(aDefaultCSP);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::GetAddonCSP(const nsAString& aAddonId,
|
|
|
|
nsAString& aResult)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
|
|
|
|
policy->GetContentSecurityPolicy(aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::GetGeneratedBackgroundPageUrl(const nsACString& aHostname,
|
|
|
|
nsACString& aResult)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByHost(aHostname)) {
|
|
|
|
nsAutoCString url("data:text/html,");
|
|
|
|
|
|
|
|
nsCString html = policy->BackgroundPageHTML();
|
|
|
|
nsAutoCString escaped;
|
|
|
|
|
|
|
|
url.Append(NS_EscapeURL(html, esc_Minimal, escaped));
|
|
|
|
|
|
|
|
aResult = url;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::AddonHasPermission(const nsAString& aAddonId,
|
|
|
|
const nsAString& aPerm,
|
|
|
|
bool* aResult)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
|
|
|
|
*aResult = policy->HasPermission(aPerm);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::AddonMayLoadURI(const nsAString& aAddonId,
|
|
|
|
nsIURI* aURI,
|
|
|
|
bool aExplicit,
|
|
|
|
bool* aResult)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
|
|
|
|
*aResult = policy->CanAccessURI(aURI, aExplicit);
|
|
|
|
return NS_OK;
|
2017-08-12 07:22:18 +03:00
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::GetExtensionName(const nsAString& aAddonId,
|
|
|
|
nsAString& aName)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
|
|
|
|
aName.Assign(policy->Name());
|
|
|
|
return NS_OK;
|
2017-06-04 03:12:14 +03:00
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::ExtensionURILoadableByAnyone(nsIURI* aURI, bool* aResult)
|
|
|
|
{
|
|
|
|
URLInfo url(aURI);
|
|
|
|
if (WebExtensionPolicy* policy = GetByURL(url)) {
|
|
|
|
*aResult = policy->IsPathWebAccessible(url.FilePath());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ExtensionPolicyService::ExtensionURIToAddonId(nsIURI* aURI, nsAString& aResult)
|
|
|
|
{
|
|
|
|
if (WebExtensionPolicy* policy = GetByURL(aURI)) {
|
|
|
|
policy->GetId(aResult);
|
|
|
|
} else {
|
|
|
|
aResult.SetIsVoid(true);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-14 22:05:11 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION(ExtensionPolicyService, mExtensions, mExtensionHosts,
|
|
|
|
mObservers)
|
2017-05-24 05:15:10 +03:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPolicyService)
|
2017-06-04 03:12:14 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIAddonPolicyService)
|
2017-06-05 01:38:11 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
2018-08-18 08:09:23 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
2018-01-13 05:52:36 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)
|
2017-06-05 01:38:11 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAddonPolicyService)
|
2017-05-24 05:15:10 +03:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPolicyService)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPolicyService)
|
|
|
|
|
|
|
|
} // namespace mozilla
|