Bug 1254194: Apply a content security policy to all WebExtension documents. r?gabor
MozReview-Commit-ID: HsFFbWdq00b
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -511,16 +511,23 @@ BasePrincipal::GetAppId(uint32_t* aAppId
return NS_OK;
}
*aAppId = AppId();
return NS_OK;
}
NS_IMETHODIMP
+BasePrincipal::GetAddonId(nsAString& aAddonId)
+{
+ aAddonId.Assign(mOriginAttributes.mAddonId);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
BasePrincipal::GetUserContextId(uint32_t* aUserContextId)
{
*aUserContextId = UserContextId();
return NS_OK;
}
NS_IMETHODIMP
BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -210,31 +210,33 @@ public:
NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final;
NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
+ NS_IMETHOD GetAddonId(nsAString& aAddonId) final;
NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
virtual bool IsCodebasePrincipal() const { return false; };
static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
static already_AddRefed<BasePrincipal>
CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs);
static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin);
const PrincipalOriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
uint32_t AppId() const { return mOriginAttributes.mAppId; }
+ inline const nsAString& AddonId() const { return mOriginAttributes.mAddonId; }
uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
enum PrincipalKind {
eNullPrincipal,
eCodebasePrincipal,
eExpandedPrincipal,
eSystemPrincipal
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -291,16 +291,21 @@ interface nsIPrincipal : nsISerializable
* origin as the app.
*
* If you're doing a security check based on appId, you must check
* appStatus as well.
*/
[infallible] readonly attribute unsigned long appId;
/**
+ * Gets the ID of the add-on this principal belongs to.
+ */
+ readonly attribute AString addonId;
+
+ /**
* Gets the id of the user context this principal is inside. If this
* principal is inside the default userContext, this returns
* nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID.
*/
[infallible] readonly attribute unsigned long userContextId;
/**
* Returns true iff the principal is inside an isolated mozbrowser element.
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -195,16 +195,17 @@
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/Preferences.h"
#include "imgILoader.h"
#include "imgRequestProxy.h"
#include "nsWrapperCacheInlines.h"
#include "nsSandboxFlags.h"
+#include "nsIAddonPolicyService.h"
#include "nsIAppsService.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnonymousContent.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/HTMLBodyElement.h"
@@ -2811,22 +2812,26 @@ nsDocument::InitCSP(nsIChannel* aChannel
}
appsService->GetDefaultCSPByLocalId(appId, appDefaultCSP);
if (!appDefaultCSP.IsEmpty()) {
applyAppDefaultCSP = true;
}
}
}
- // Check if this is part of the Loop/Hello service
- bool applyLoopCSP = IsLoopDocument(aChannel);
+ // Check if this is a document from a WebExtension.
+ bool applyAddonCSP = !BasePrincipal::Cast(principal)->AddonId().IsEmpty();
+
+ // Check if this is part of the Loop/Hello service
+ bool applyLoopCSP = IsLoopDocument(aChannel);
// If there's no CSP to apply, go ahead and return early
if (!applyAppDefaultCSP &&
!applyAppManifestCSP &&
+ !applyAddonCSP &&
!applyLoopCSP &&
cspHeaderValue.IsEmpty() &&
cspROHeaderValue.IsEmpty()) {
if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
nsCOMPtr<nsIURI> chanURI;
aChannel->GetURI(getter_AddRefs(chanURI));
nsAutoCString aspec;
chanURI->GetAsciiSpec(aspec);
@@ -2874,16 +2879,32 @@ nsDocument::InitCSP(nsIChannel* aChannel
csp->AppendPolicy(appDefaultCSP, false, false);
}
// ----- if the doc is an app and specifies a CSP in its manifest, apply it.
if (applyAppManifestCSP) {
csp->AppendPolicy(appManifestCSP, false, false);
}
+ // ----- if the doc is an addon, apply its CSP.
+ if (applyAddonCSP) {
+ nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
+
+ nsAutoString addonCSP;
+ rv = aps->GetBaseCSP(addonCSP);
+ if (NS_SUCCEEDED(rv)) {
+ csp->AppendPolicy(addonCSP, false, false);
+ }
+
+ rv = aps->GetAddonCSP(BasePrincipal::Cast(principal)->AddonId(), addonCSP);
+ if (NS_SUCCEEDED(rv)) {
+ csp->AppendPolicy(addonCSP, false, false);
+ }
+ }
+
// ----- if the doc is part of Loop, apply the loop CSP
if (applyLoopCSP) {
nsAdoptingString loopCSP;
loopCSP = Preferences::GetString("loop.CSP");
NS_ASSERTION(loopCSP, "Missing loop.CSP preference");
// If the pref has been removed, we continue without setting a CSP
if (loopCSP) {
csp->AppendPolicy(loopCSP, false, false);