Bug 1396449: Part 1 - Use WebExtensionPolicy objects in extension content principals. r?krizsa draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 03 Sep 2017 19:33:00 -0700
changeset 658391 4d814343271560be5a5a6f697019b68136735e39
parent 658377 c20875102c11af757c5736e5c07deb1c92ebe223
child 658392 569a9c310bc72a301b7c37034cec9dede62a1505
push id77743
push usermaglione.k@gmail.com
push dateMon, 04 Sep 2017 02:46:32 +0000
reviewerskrizsa
bugs1396449
milestone57.0a1
Bug 1396449: Part 1 - Use WebExtensionPolicy objects in extension content principals. r?krizsa Going through the extension policy service rather than using WebExtensionPolicy objects directly adds a lot of unnecessary overhead to common operations on extension principals, and also makes the code more complicated than it needs to be. We also use weak references to policy objects here, since principals should ideally lose as much of their elevated privileges as possible once the extension instance that created them has been destroyed (which is something we couldn't handle easily when we simply tracked ID strings). MozReview-Commit-ID: KDNvVdvLkIt
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/ContentPrincipal.cpp
caps/ContentPrincipal.h
caps/nsIPrincipal.idl
caps/nsScriptSecurityManager.cpp
caps/nsScriptSecurityManager.h
dom/base/nsDocument.cpp
dom/base/nsGlobalWindow.cpp
js/xpconnect/src/XPCJSContext.cpp
toolkit/components/extensions/ExtensionPolicyService.cpp
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=2 sw=2 et 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 "mozilla/BasePrincipal.h"
 
 #include "nsDocShell.h"
-#include "nsIAddonPolicyService.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIStandardURL.h"
 
 #include "ContentPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsIURIWithPrincipal.h"
@@ -326,34 +325,40 @@ BasePrincipal::GetPrivateBrowsingId(uint
 
 NS_IMETHODIMP
 BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
 {
   *aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement();
   return NS_OK;
 }
 
+nsresult
+BasePrincipal::GetAddonPolicy(nsISupports** aResult)
+{
+  *aResult = AddonPolicy();
+  return NS_OK;
+}
+
+extensions::WebExtensionPolicy*
+BasePrincipal::AddonPolicy()
+{
+  if (Is<ContentPrincipal>()) {
+    return As<ContentPrincipal>()->AddonPolicy();
+  }
+  return nullptr;
+}
+
 bool
 BasePrincipal::AddonHasPermission(const nsAString& aPerm)
 {
-  nsAutoString addonId;
-  NS_ENSURE_SUCCESS(GetAddonId(addonId), false);
-
-  if (addonId.IsEmpty()) {
-    return false;
+  auto policy = AddonPolicy();
+  if (policy) {
+    return policy->HasPermission(aPerm);
   }
-
-  nsCOMPtr<nsIAddonPolicyService> aps =
-    do_GetService("@mozilla.org/addons/policy-service;1");
-  NS_ENSURE_TRUE(aps, false);
-
-  bool retval = false;
-  nsresult rv = aps->AddonHasPermission(addonId, aPerm, &retval);
-  NS_ENSURE_SUCCESS(rv, false);
-  return retval;
+  return false;
 }
 
 already_AddRefed<BasePrincipal>
 BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI,
                                        const OriginAttributes& aAttrs)
 {
   MOZ_ASSERT(aURI);
 
@@ -443,29 +448,21 @@ BasePrincipal::CloneStrippingUserContext
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return BasePrincipal::CreateCodebasePrincipal(uri, attrs);
 }
 
 bool
 BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
 {
-  nsAutoString addonId;
-  NS_ENSURE_SUCCESS(GetAddonId(addonId), false);
-
-  if (addonId.IsEmpty()) {
-    return false;
+  auto policy = AddonPolicy();
+  if (policy) {
+    return policy->CanAccessURI(aURI, aExplicit);
   }
-
-  nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
-  NS_ENSURE_TRUE(aps, false);
-
-  bool allowed = false;
-  nsresult rv = aps->AddonMayLoadURI(addonId, aURI, aExplicit, &allowed);
-  return NS_SUCCEEDED(rv) && allowed;
+  return false;
 }
 
 void
 BasePrincipal::FinishInit(const nsACString& aOriginNoSuffix,
                           const OriginAttributes& aOriginAttributes)
 {
   mInitialized = true;
   mOriginAttributes = aOriginAttributes;
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -59,16 +59,17 @@ public:
   NS_IMETHOD GetOrigin(nsACString& aOrigin) final;
   NS_IMETHOD GetOriginNoSuffix(nsACString& aOrigin) final;
   NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
+  NS_IMETHOD GetAddonPolicy(nsISupports** aResult) final;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
   NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
   NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
@@ -94,16 +95,17 @@ public:
   // not possible to generate a correct origin from the passed URI. If this
   // happens, a NullPrincipal is returned.
 
   static already_AddRefed<BasePrincipal>
   CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs);
 
   const OriginAttributes& OriginAttributesRef() final { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
+  extensions::WebExtensionPolicy* AddonPolicy();
   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
   uint32_t PrivateBrowsingId() const { return mOriginAttributes.mPrivateBrowsingId; }
   bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
 
   PrincipalKind Kind() const { return mKind; }
 
   already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
 
--- a/caps/ContentPrincipal.cpp
+++ b/caps/ContentPrincipal.cpp
@@ -25,16 +25,17 @@
 #include "nsError.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsNetCID.h"
 #include "jswrapper.h"
 
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ExtensionPolicyService.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/HashFunctions.h"
 
 using namespace mozilla;
 
 static bool gCodeBasePrincipalSupport = false;
 
 static bool URIIsImmutable(nsIURI* aURI)
@@ -42,27 +43,20 @@ static bool URIIsImmutable(nsIURI* aURI)
   nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(aURI));
   bool isMutable;
   return
     mutableObj &&
     NS_SUCCEEDED(mutableObj->GetMutable(&isMutable)) &&
     !isMutable;
 }
 
-static nsIAddonPolicyService*
-GetAddonPolicyService(nsresult* aRv)
+static inline ExtensionPolicyService&
+EPS()
 {
-  static nsCOMPtr<nsIAddonPolicyService> addonPolicyService;
-
-  *aRv = NS_OK;
-  if (!addonPolicyService) {
-    addonPolicyService = do_GetService("@mozilla.org/addons/policy-service;1", aRv);
-    ClearOnShutdown(&addonPolicyService);
-  }
-  return addonPolicyService;
+  return ExtensionPolicyService::GetSingleton();
 }
 
 NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
                   NS_PRINCIPAL_CID)
 NS_IMPL_QUERY_INTERFACE_CI(ContentPrincipal,
                            nsIPrincipal,
                            nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER(ContentPrincipal,
@@ -420,44 +414,44 @@ ContentPrincipal::GetBaseDomain(nsACStri
     do_GetService(THIRDPARTYUTIL_CONTRACTID);
   if (thirdPartyUtil) {
     return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain);
   }
 
   return NS_OK;
 }
 
+WebExtensionPolicy*
+ContentPrincipal::AddonPolicy()
+{
+  if (!mAddon.isSome()) {
+    NS_ENSURE_TRUE(mCodebase, nullptr);
+
+    bool isMozExt;
+    if (NS_SUCCEEDED(mCodebase->SchemeIs("moz-extension", &isMozExt)) && isMozExt) {
+      mAddon.emplace(EPS().GetByURL(mCodebase.get()));
+    } else {
+      mAddon.emplace(nullptr);
+    }
+  }
+
+  return mAddon.value();
+}
+
 NS_IMETHODIMP
 ContentPrincipal::GetAddonId(nsAString& aAddonId)
 {
-  if (mAddonIdCache.isSome()) {
-    aAddonId.Assign(mAddonIdCache.ref());
-    return NS_OK;
+  auto policy = AddonPolicy();
+  if (policy) {
+    policy->GetId(aAddonId);
+  } else {
+    aAddonId.Truncate();
   }
-
-  NS_ENSURE_TRUE(mCodebase, NS_ERROR_FAILURE);
-
-  nsresult rv;
-  bool isMozExt;
-  if (NS_SUCCEEDED(mCodebase->SchemeIs("moz-extension", &isMozExt)) && isMozExt) {
-    nsIAddonPolicyService* addonPolicyService = GetAddonPolicyService(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsAutoString addonId;
-    rv = addonPolicyService->ExtensionURIToAddonId(mCodebase, addonId);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mAddonIdCache.emplace(addonId);
-  } else {
-    mAddonIdCache.emplace();
-  }
-
-  aAddonId.Assign(mAddonIdCache.ref());
   return NS_OK;
-};
+}
 
 NS_IMETHODIMP
 ContentPrincipal::Read(nsIObjectInputStream* aStream)
 {
   nsCOMPtr<nsISupports> supports;
   nsCOMPtr<nsIURI> codebase;
   nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
   if (NS_FAILED(rv)) {
--- a/caps/ContentPrincipal.h
+++ b/caps/ContentPrincipal.h
@@ -9,16 +9,17 @@
 #include "nsCOMPtr.h"
 #include "nsJSPrincipals.h"
 #include "nsTArray.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIProtocolHandler.h"
 #include "nsNetUtil.h"
 #include "nsScriptSecurityManager.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/extensions/WebExtensionPolicy.h"
 
 class ContentPrincipal final : public mozilla::BasePrincipal
 {
 public:
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
@@ -42,31 +43,33 @@ public:
   /**
    * Called at startup to setup static data, e.g. about:config pref-observers.
    */
   static void InitializeStatics();
 
   static nsresult
   GenerateOriginNoSuffixFromURI(nsIURI* aURI, nsACString& aOrigin);
 
+  mozilla::extensions::WebExtensionPolicy* AddonPolicy();
+
   nsCOMPtr<nsIURI> mDomain;
   nsCOMPtr<nsIURI> mCodebase;
   // If mCodebaseImmutable is true, mCodebase is non-null and immutable
   bool mCodebaseImmutable;
   bool mDomainImmutable;
 
 protected:
   virtual ~ContentPrincipal();
 
   bool SubsumesInternal(nsIPrincipal* aOther,
                         DocumentDomainConsideration aConsideration) override;
   bool MayLoadInternal(nsIURI* aURI) override;
 
 private:
-  mozilla::Maybe<nsString> mAddonIdCache;
+  mozilla::Maybe<mozilla::WeakPtr<mozilla::extensions::WebExtensionPolicy>> mAddon;
 };
 
 #define NS_PRINCIPAL_CONTRACTID "@mozilla.org/principal;1"
 #define NS_PRINCIPAL_CID \
 { 0x653e0e4d, 0x3ee4, 0x45fa, \
   { 0xb2, 0x72, 0x97, 0xc2, 0x0b, 0xc0, 0x1e, 0xb8 } }
 
 #endif // ContentPrincipal_h
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -9,16 +9,19 @@
 
 %{C++
 struct JSPrincipals;
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "mozilla/DebugOnly.h"
 namespace mozilla {
 class OriginAttributes;
+namespace extensions {
+class WebExtensionPolicy;
+}
 }
 
 /**
  * Some methods have a fast path for the case when we're comparing a principal
  * to itself. The situation may happen for example with about:blank documents.
  */
 
 #define DECL_FAST_INLINE_HELPER(method_)                       \
@@ -269,16 +272,18 @@ interface nsIPrincipal : nsISerializable
      */
     [infallible] readonly attribute unsigned long appId;
 
     /**
      * Gets the ID of the add-on this principal belongs to.
      */
     readonly attribute AString addonId;
 
+    readonly attribute nsISupports addonPolicy;
+
     /**
      * 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;
 
     /**
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -764,23 +764,18 @@ nsScriptSecurityManager::CheckLoadURIWit
     }
 
     // Check for webextension
     rv = NS_URIChainHasFlags(aTargetURI,
                              nsIProtocolHandler::URI_LOADABLE_BY_EXTENSIONS,
                              &hasFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (hasFlags) {
-      nsString addonId;
-      aPrincipal->GetAddonId(addonId);
-
-      if (!addonId.IsEmpty()) {
-        return NS_OK;
-      }
+    if (hasFlags && BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
+      return NS_OK;
     }
 
     // If we get here, check all the schemes can link to each other, from the top down:
     nsCaseInsensitiveCStringComparator stringComparator;
     nsCOMPtr<nsIURI> currentURI = sourceURI;
     nsCOMPtr<nsIURI> currentOtherURI = aTargetURI;
 
     bool denySameSchemeLinks = false;
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -4,19 +4,17 @@
  * 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/. */
 
 #ifndef nsScriptSecurityManager_h__
 #define nsScriptSecurityManager_h__
 
 #include "nsIScriptSecurityManager.h"
 
-#include "nsIAddonPolicyService.h"
 #include "mozilla/Maybe.h"
-#include "nsIAddonPolicyService.h"
 #include "nsIPrincipal.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringFwd.h"
 #include "plstr.h"
 #include "js/TypeDecls.h"
 
@@ -131,27 +129,16 @@ private:
     // access to file: URIs.  Lazily initialized; isNothing() when not yet
     // initialized.
     mozilla::Maybe<nsTArray<nsCOMPtr<nsIURI>>> mFileURIWhitelist;
 
     // This machinery controls new-style domain policies. The old-style
     // policy machinery will be removed soon.
     nsCOMPtr<nsIDomainPolicy> mDomainPolicy;
 
-    // Cached addon policy service. We can't generate this in Init() because
-    // that's too early to get a service.
-    mozilla::Maybe<nsCOMPtr<nsIAddonPolicyService>> mAddonPolicyService;
-    nsIAddonPolicyService* GetAddonPolicyService()
-    {
-        if (mAddonPolicyService.isNothing()) {
-            mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1"));
-        }
-        return mAddonPolicyService.ref();
-    }
-
     static bool sStrictFileOriginPolicy;
 
     static nsIIOService    *sIOService;
     static nsIStringBundle *sStrBundle;
     static JSContext       *sContext;
 };
 
 #endif // nsScriptSecurityManager_h__
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -204,17 +204,16 @@
 #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 "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"
 #include "mozilla/dom/HTMLInputElement.h"
@@ -222,16 +221,17 @@
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/NodeFilterBinding.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WebComponentsBinding.h"
 #include "mozilla/dom/CustomElementRegistryBinding.h"
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/dom/TimeoutManager.h"
+#include "mozilla/ExtensionPolicyService.h"
 #include "nsFrame.h"
 #include "nsDOMCaretPosition.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsViewportInfo.h"
 #include "mozilla/StaticPtr.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIEditor.h"
@@ -2867,30 +2867,28 @@ nsDocument::InitCSP(nsIChannel* aChannel
     Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy-report-only"),
         tCspROHeaderValue);
   }
   NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
   NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
 
   // Check if this is a document from a WebExtension.
-  nsString addonId;
   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
-  principal->GetAddonId(addonId);
-  bool applyAddonCSP = !addonId.IsEmpty();
+  auto addonPolicy = BasePrincipal::Cast(principal)->AddonPolicy();
 
   // Check if this is a signed content to apply default CSP.
   bool applySignedContentCSP = false;
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   if (loadInfo && loadInfo->GetVerifySignedContent()) {
     applySignedContentCSP = true;
   }
 
   // If there's no CSP to apply, go ahead and return early
-  if (!applyAddonCSP &&
+  if (!addonPolicy &&
       !applySignedContentCSP &&
       cspHeaderValue.IsEmpty() &&
       cspROHeaderValue.IsEmpty()) {
     if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
       nsCOMPtr<nsIURI> chanURI;
       aChannel->GetURI(getter_AddRefs(chanURI));
       nsAutoCString aspec;
       chanURI->GetAsciiSpec(aspec);
@@ -2904,29 +2902,24 @@ nsDocument::InitCSP(nsIChannel* aChannel
 
   MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an add-on or CSP header specified %p", this));
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = principal->EnsureCSP(this, getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ----- if the doc is an addon, apply its CSP.
-  if (applyAddonCSP) {
+  if (addonPolicy) {
     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(addonId, addonCSP);
-    if (NS_SUCCEEDED(rv)) {
-      csp->AppendPolicy(addonCSP, false, false);
-    }
+    Unused << ExtensionPolicyService::GetSingleton().GetBaseCSP(addonCSP);
+    csp->AppendPolicy(addonCSP, false, false);
+
+    csp->AppendPolicy(addonPolicy->ContentSecurityPolicy(), false, false);
   }
 
   // ----- if the doc is a signed content, apply the default CSP.
   // Note that when the content signing becomes a standard, we might have
   // to restrict this enforcement to "remote content" only.
   if (applySignedContentCSP) {
     nsAutoString signedContentCSP;
     Preferences::GetString("security.signed_content.CSP.default",
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3338,19 +3338,18 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     // doesn't have one).
     newInnerWindow->mChromeEventHandler = mChromeEventHandler;
   }
 
   // Ask the JS engine to assert that it's valid to access our DocGroup whenever
   // it runs JS code for this compartment. We skip the check if this window is
   // for chrome JS or an add-on.
   nsCOMPtr<nsIPrincipal> principal = mDoc->NodePrincipal();
-  nsString addonId;
-  principal->GetAddonId(addonId);
-  if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) && addonId.IsEmpty()) {
+  if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) &&
+      !BasePrincipal::Cast(principal)->AddonPolicy()) {
     js::SetCompartmentValidAccessPtr(cx, newInnerGlobal,
                                      newInnerWindow->GetDocGroup()->GetValidAccessPtr());
   }
 
   kungFuDeathGrip->DidInitializeContext();
 
   // We wait to fire the debugger hook until the window is all set up and hooked
   // up with the outer. See bug 969156.
@@ -9785,18 +9784,17 @@ public:
           NS_ENSURE_TRUE(currentInner, NS_OK);
 
           AutoSafeJSContext cx;
           JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
           if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
             JSCompartment* cpt = js::GetObjectCompartment(obj);
             nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));
 
-            nsAutoString addonId;
-            if (NS_SUCCEEDED(pc->GetAddonId(addonId)) && !addonId.IsEmpty()) {
+            if (BasePrincipal::Cast(pc)->AddonPolicy()) {
               // We want to nuke all references to the add-on compartment.
               xpc::NukeAllWrappersForCompartment(cx, cpt,
                                                  win->IsInnerWindow() ? js::DontNukeWindowReferences
                                                                       : js::NukeWindowReferences);
             } else {
               // We only want to nuke wrappers for the chrome->content case
               js::NukeCrossCompartmentWrappers(cx, BrowserCompartmentMatcher(), cpt,
                                                win->IsInnerWindow() ? js::DontNukeWindowReferences
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -554,18 +554,17 @@ XPCJSContext::ActivityCallback(void* arg
 
     XPCJSContext* self = static_cast<XPCJSContext*>(arg);
     self->mWatchdogManager->RecordContextActivity(self, active);
 }
 
 static inline bool
 IsWebExtensionPrincipal(nsIPrincipal* principal, nsAString& addonId)
 {
-    return (NS_SUCCEEDED(principal->GetAddonId(addonId)) &&
-            !addonId.IsEmpty());
+    return BasePrincipal::Cast(principal)->AddonPolicy();
 }
 
 static bool
 IsWebExtensionContentScript(BasePrincipal* principal, nsAString& addonId)
 {
     if (!principal->Is<ExpandedPrincipal>()) {
         return false;
     }
--- a/toolkit/components/extensions/ExtensionPolicyService.cpp
+++ b/toolkit/components/extensions/ExtensionPolicyService.cpp
@@ -245,20 +245,17 @@ ExtensionPolicyService::CheckDocument(ns
   nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
   if (win) {
     if (win->GetDocumentURI()) {
       CheckContentScripts(win.get(), false);
     }
 
     nsIPrincipal* principal = aDocument->NodePrincipal();
 
-    nsAutoString addonId;
-    Unused << principal->GetAddonId(addonId);
-
-    RefPtr<WebExtensionPolicy> policy = GetByID(addonId);
+    RefPtr<WebExtensionPolicy> policy = BasePrincipal::Cast(principal)->AddonPolicy();
     if (policy) {
       nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
       ProcessScript().InitExtensionDocument(policy, doc);
     }
   }
 }
 
 // Checks for loads of about:blank into new window globals, and loads any