LCOV - code coverage report
Current view: top level - toolkit/components/extensions - ExtensionPolicyService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 179 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/ExtensionPolicyService.h"
       7             : #include "mozilla/extensions/WebExtensionContentScript.h"
       8             : #include "mozilla/extensions/WebExtensionPolicy.h"
       9             : 
      10             : #include "mozilla/ClearOnShutdown.h"
      11             : #include "mozilla/Preferences.h"
      12             : #include "mozilla/Services.h"
      13             : #include "mozilla/dom/ContentChild.h"
      14             : #include "mozilla/dom/ContentParent.h"
      15             : #include "mozIExtensionProcessScript.h"
      16             : #include "nsEscape.h"
      17             : #include "nsGkAtoms.h"
      18             : #include "nsIChannel.h"
      19             : #include "nsIContentPolicy.h"
      20             : #include "nsIDOMDocument.h"
      21             : #include "nsIDocument.h"
      22             : #include "nsILoadInfo.h"
      23             : #include "nsNetUtil.h"
      24             : #include "nsPIDOMWindow.h"
      25             : #include "nsXULAppAPI.h"
      26             : 
      27             : namespace mozilla {
      28             : 
      29             : using namespace extensions;
      30             : 
      31             : #define DEFAULT_BASE_CSP \
      32             :     "script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; " \
      33             :     "object-src 'self' https://* moz-extension: blob: filesystem:;"
      34             : 
      35             : #define DEFAULT_DEFAULT_CSP \
      36             :     "script-src 'self'; object-src 'self';"
      37             : 
      38             : 
      39             : #define OBS_TOPIC_PRELOAD_SCRIPT "web-extension-preload-content-script"
      40             : #define OBS_TOPIC_LOAD_SCRIPT "web-extension-load-content-script"
      41             : 
      42             : 
      43             : static mozIExtensionProcessScript&
      44           0 : ProcessScript()
      45             : {
      46           0 :   static nsCOMPtr<mozIExtensionProcessScript> sProcessScript;
      47             : 
      48           0 :   if (MOZ_UNLIKELY(!sProcessScript)) {
      49           0 :     sProcessScript = do_GetService("@mozilla.org/webextensions/extension-process-script;1");
      50           0 :     MOZ_RELEASE_ASSERT(sProcessScript);
      51           0 :     ClearOnShutdown(&sProcessScript);
      52             :   }
      53           0 :   return *sProcessScript;
      54             : }
      55             : 
      56             : /*****************************************************************************
      57             :  * ExtensionPolicyService
      58             :  *****************************************************************************/
      59             : 
      60             : /* static */ bool ExtensionPolicyService::sRemoteExtensions;
      61             : 
      62             : /* static */ ExtensionPolicyService&
      63           0 : ExtensionPolicyService::GetSingleton()
      64             : {
      65           0 :   static RefPtr<ExtensionPolicyService> sExtensionPolicyService;
      66             : 
      67           0 :   if (MOZ_UNLIKELY(!sExtensionPolicyService)) {
      68           0 :     sExtensionPolicyService = new ExtensionPolicyService();
      69           0 :     ClearOnShutdown(&sExtensionPolicyService);
      70             :   }
      71           0 :   return *sExtensionPolicyService.get();
      72             : }
      73             : 
      74           0 : ExtensionPolicyService::ExtensionPolicyService()
      75             : {
      76           0 :   mObs = services::GetObserverService();
      77           0 :   MOZ_RELEASE_ASSERT(mObs);
      78             : 
      79           0 :   Preferences::AddBoolVarCache(&sRemoteExtensions, "extensions.webextensions.remote", false);
      80             : 
      81           0 :   RegisterObservers();
      82           0 : }
      83             : 
      84             : 
      85             : bool
      86           0 : ExtensionPolicyService::IsExtensionProcess() const
      87             : {
      88           0 :   if (sRemoteExtensions && XRE_IsContentProcess()) {
      89           0 :     auto& remoteType = dom::ContentChild::GetSingleton()->GetRemoteType();
      90           0 :     return remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE);
      91             :   }
      92           0 :   return XRE_IsParentProcess();
      93             : }
      94             : 
      95             : 
      96             : WebExtensionPolicy*
      97           0 : ExtensionPolicyService::GetByURL(const URLInfo& aURL)
      98             : {
      99           0 :   if (aURL.Scheme() == nsGkAtoms::moz_extension) {
     100           0 :     return GetByHost(aURL.Host());
     101             :   }
     102           0 :   return nullptr;
     103             : }
     104             : 
     105             : void
     106           0 : ExtensionPolicyService::GetAll(nsTArray<RefPtr<WebExtensionPolicy>>& aResult)
     107             : {
     108           0 :   for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
     109           0 :     aResult.AppendElement(iter.Data());
     110             :   }
     111           0 : }
     112             : 
     113             : bool
     114           0 : ExtensionPolicyService::RegisterExtension(WebExtensionPolicy& aPolicy)
     115             : {
     116           0 :   bool ok = (!GetByID(aPolicy.Id()) &&
     117           0 :              !GetByHost(aPolicy.MozExtensionHostname()));
     118           0 :   MOZ_ASSERT(ok);
     119             : 
     120           0 :   if (!ok) {
     121           0 :     return false;
     122             :   }
     123             : 
     124           0 :   mExtensions.Put(aPolicy.Id(), &aPolicy);
     125           0 :   mExtensionHosts.Put(aPolicy.MozExtensionHostname(), &aPolicy);
     126           0 :   return true;
     127             : }
     128             : 
     129             : bool
     130           0 : ExtensionPolicyService::UnregisterExtension(WebExtensionPolicy& aPolicy)
     131             : {
     132           0 :   bool ok = (GetByID(aPolicy.Id()) == &aPolicy &&
     133           0 :              GetByHost(aPolicy.MozExtensionHostname()) == &aPolicy);
     134           0 :   MOZ_ASSERT(ok);
     135             : 
     136           0 :   if (!ok) {
     137           0 :     return false;
     138             :   }
     139             : 
     140           0 :   mExtensions.Remove(aPolicy.Id());
     141           0 :   mExtensionHosts.Remove(aPolicy.MozExtensionHostname());
     142           0 :   return true;
     143             : }
     144             : 
     145             : 
     146             : void
     147           0 : ExtensionPolicyService::BaseCSP(nsAString& aBaseCSP) const
     148             : {
     149             :   nsresult rv;
     150             : 
     151           0 :   rv = Preferences::GetString("extensions.webextensions.base-content-security-policy", &aBaseCSP);
     152           0 :   if (NS_FAILED(rv)) {
     153           0 :     aBaseCSP.AssignLiteral(DEFAULT_BASE_CSP);
     154             :   }
     155           0 : }
     156             : 
     157             : void
     158           0 : ExtensionPolicyService::DefaultCSP(nsAString& aDefaultCSP) const
     159             : {
     160             :   nsresult rv;
     161             : 
     162           0 :   rv = Preferences::GetString("extensions.webextensions.default-content-security-policy", &aDefaultCSP);
     163           0 :   if (NS_FAILED(rv)) {
     164           0 :     aDefaultCSP.AssignLiteral(DEFAULT_DEFAULT_CSP);
     165             :   }
     166           0 : }
     167             : 
     168             : 
     169             : /*****************************************************************************
     170             :  * Content script management
     171             :  *****************************************************************************/
     172             : 
     173             : void
     174           0 : ExtensionPolicyService::RegisterObservers()
     175             : {
     176           0 :   mObs->AddObserver(this, "content-document-global-created", false);
     177           0 :   mObs->AddObserver(this, "document-element-inserted", false);
     178           0 :   if (XRE_IsContentProcess()) {
     179           0 :     mObs->AddObserver(this, "http-on-opening-request", false);
     180             :   }
     181           0 : }
     182             : 
     183             : void
     184           0 : ExtensionPolicyService::UnregisterObservers()
     185             : {
     186           0 :   mObs->RemoveObserver(this, "content-document-global-created");
     187           0 :   mObs->RemoveObserver(this, "document-element-inserted");
     188           0 :   if (XRE_IsContentProcess()) {
     189           0 :     mObs->RemoveObserver(this, "http-on-opening-request");
     190             :   }
     191           0 : }
     192             : 
     193             : nsresult
     194           0 : ExtensionPolicyService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
     195             : {
     196           0 :   if (!strcmp(aTopic, "content-document-global-created")) {
     197           0 :     nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(aSubject);
     198           0 :     if (win) {
     199           0 :       CheckWindow(win);
     200             :     }
     201           0 :   } else if (!strcmp(aTopic, "document-element-inserted")) {
     202           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
     203           0 :     if (doc) {
     204           0 :       CheckDocument(doc);
     205             :     }
     206           0 :   } else if (!strcmp(aTopic, "http-on-opening-request")) {
     207           0 :     nsCOMPtr<nsIChannel> chan = do_QueryInterface(aSubject);
     208           0 :     if (chan) {
     209           0 :       CheckRequest(chan);
     210             :     }
     211             :   }
     212           0 :   return NS_OK;
     213             : }
     214             : 
     215             : // Checks a request for matching content scripts, and begins pre-loading them
     216             : // if necessary.
     217             : void
     218           0 : ExtensionPolicyService::CheckRequest(nsIChannel* aChannel)
     219             : {
     220           0 :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     221           0 :   if (!loadInfo) {
     222           0 :     return;
     223             :   }
     224             : 
     225           0 :   auto loadType = loadInfo->GetExternalContentPolicyType();
     226           0 :   if (loadType != nsIContentPolicy::TYPE_DOCUMENT &&
     227             :       loadType != nsIContentPolicy::TYPE_SUBDOCUMENT) {
     228           0 :     return;
     229             :   }
     230             : 
     231           0 :   nsCOMPtr<nsIURI> uri;
     232           0 :   if (NS_FAILED(aChannel->GetURI(getter_AddRefs(uri)))) {
     233           0 :     return;
     234             :   }
     235             : 
     236           0 :   CheckContentScripts({uri.get(), loadInfo}, true);
     237             : }
     238             : 
     239             : // Checks a document, just after the document element has been inserted, for
     240             : // matching content scripts or extension principals, and loads them if
     241             : // necessary.
     242             : void
     243           0 : ExtensionPolicyService::CheckDocument(nsIDocument* aDocument)
     244             : {
     245           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
     246           0 :   if (win) {
     247           0 :     if (win->GetDocumentURI()) {
     248           0 :       CheckContentScripts(win.get(), false);
     249             :     }
     250             : 
     251           0 :     nsIPrincipal* principal = aDocument->NodePrincipal();
     252             : 
     253           0 :     nsAutoString addonId;
     254           0 :     Unused << principal->GetAddonId(addonId);
     255             : 
     256           0 :     RefPtr<WebExtensionPolicy> policy = GetByID(addonId);
     257           0 :     if (policy) {
     258           0 :       nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
     259           0 :       ProcessScript().InitExtensionDocument(policy, doc);
     260             :     }
     261             :   }
     262           0 : }
     263             : 
     264             : // Checks for loads of about:blank into new window globals, and loads any
     265             : // matching content scripts. about:blank loads do not trigger document element
     266             : // inserted events, so they're the only load type that are special cased this
     267             : // way.
     268             : void
     269           0 : ExtensionPolicyService::CheckWindow(nsPIDOMWindowOuter* aWindow)
     270             : {
     271             :   // We only care about non-initial document loads here. The initial
     272             :   // about:blank document will usually be re-used to load another document.
     273           0 :   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
     274           0 :   if (!doc || doc->IsInitialDocument() ||
     275           0 :       doc->GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED) {
     276           0 :     return;
     277             :   }
     278             : 
     279           0 :   nsCOMPtr<nsIURI> docUri = doc->GetDocumentURI();
     280           0 :   nsCOMPtr<nsIURI> uri;
     281           0 :   if (!docUri || NS_FAILED(docUri->CloneIgnoringRef(getter_AddRefs(uri))) ||
     282           0 :       !NS_IsAboutBlank(uri)) {
     283           0 :     return;
     284             :   }
     285             : 
     286           0 :   CheckContentScripts(aWindow, false);
     287             : }
     288             : 
     289             : void
     290           0 : ExtensionPolicyService::CheckContentScripts(const DocInfo& aDocInfo, bool aIsPreload)
     291             : {
     292           0 :   for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
     293           0 :     RefPtr<WebExtensionPolicy> policy = iter.Data();
     294             : 
     295           0 :     for (auto& script : policy->ContentScripts()) {
     296           0 :       if (script->Matches(aDocInfo)) {
     297           0 :         if (aIsPreload) {
     298           0 :           ProcessScript().PreloadContentScript(script);
     299             :         } else {
     300           0 :           ProcessScript().LoadContentScript(script, aDocInfo.GetWindow());
     301             :         }
     302             :       }
     303             :     }
     304             :   }
     305           0 : }
     306             : 
     307             : 
     308             : /*****************************************************************************
     309             :  * nsIAddonPolicyService
     310             :  *****************************************************************************/
     311             : 
     312             : nsresult
     313           0 : ExtensionPolicyService::GetBaseCSP(nsAString& aBaseCSP)
     314             : {
     315           0 :   BaseCSP(aBaseCSP);
     316           0 :   return NS_OK;
     317             : }
     318             : 
     319             : nsresult
     320           0 : ExtensionPolicyService::GetDefaultCSP(nsAString& aDefaultCSP)
     321             : {
     322           0 :   DefaultCSP(aDefaultCSP);
     323           0 :   return NS_OK;
     324             : }
     325             : 
     326             : nsresult
     327           0 : ExtensionPolicyService::GetAddonCSP(const nsAString& aAddonId,
     328             :                                     nsAString& aResult)
     329             : {
     330           0 :   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
     331           0 :     policy->GetContentSecurityPolicy(aResult);
     332           0 :     return NS_OK;
     333             :   }
     334           0 :   return NS_ERROR_INVALID_ARG;
     335             : }
     336             : 
     337             : nsresult
     338           0 : ExtensionPolicyService::GetGeneratedBackgroundPageUrl(const nsACString& aHostname,
     339             :                                                       nsACString& aResult)
     340             : {
     341           0 :   if (WebExtensionPolicy* policy = GetByHost(aHostname)) {
     342           0 :     nsAutoCString url("data:text/html,");
     343             : 
     344           0 :     nsCString html = policy->BackgroundPageHTML();
     345           0 :     nsAutoCString escaped;
     346             : 
     347           0 :     url.Append(NS_EscapeURL(html, esc_Minimal, escaped));
     348             : 
     349           0 :     aResult = url;
     350           0 :     return NS_OK;
     351             :   }
     352           0 :   return NS_ERROR_INVALID_ARG;
     353             : }
     354             : 
     355             : nsresult
     356           0 : ExtensionPolicyService::AddonHasPermission(const nsAString& aAddonId,
     357             :                                            const nsAString& aPerm,
     358             :                                            bool* aResult)
     359             : {
     360           0 :   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
     361           0 :     *aResult = policy->HasPermission(aPerm);
     362           0 :     return NS_OK;
     363             :   }
     364           0 :   return NS_ERROR_INVALID_ARG;
     365             : }
     366             : 
     367             : nsresult
     368           0 : ExtensionPolicyService::AddonMayLoadURI(const nsAString& aAddonId,
     369             :                                         nsIURI* aURI,
     370             :                                         bool aExplicit,
     371             :                                         bool* aResult)
     372             : {
     373           0 :   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
     374           0 :     *aResult = policy->CanAccessURI(aURI, aExplicit);
     375           0 :     return NS_OK;
     376             :   }
     377           0 :   return NS_ERROR_INVALID_ARG;
     378             : }
     379             : 
     380             : nsresult
     381           0 : ExtensionPolicyService::ExtensionURILoadableByAnyone(nsIURI* aURI, bool* aResult)
     382             : {
     383           0 :   URLInfo url(aURI);
     384           0 :   if (WebExtensionPolicy* policy = GetByURL(url)) {
     385           0 :     *aResult = policy->IsPathWebAccessible(url.FilePath());
     386           0 :     return NS_OK;
     387             :   }
     388           0 :   return NS_ERROR_INVALID_ARG;
     389             : }
     390             : 
     391             : nsresult
     392           0 : ExtensionPolicyService::ExtensionURIToAddonId(nsIURI* aURI, nsAString& aResult)
     393             : {
     394           0 :   if (WebExtensionPolicy* policy = GetByURL(aURI)) {
     395           0 :     policy->GetId(aResult);
     396             :   } else {
     397           0 :     aResult.SetIsVoid(true);
     398             :   }
     399           0 :   return NS_OK;
     400             : }
     401             : 
     402             : 
     403           0 : NS_IMPL_CYCLE_COLLECTION(ExtensionPolicyService, mExtensions, mExtensionHosts)
     404             : 
     405           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPolicyService)
     406           0 :   NS_INTERFACE_MAP_ENTRY(nsIAddonPolicyService)
     407           0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     408           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAddonPolicyService)
     409           0 : NS_INTERFACE_MAP_END
     410             : 
     411           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPolicyService)
     412           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPolicyService)
     413             : 
     414             : } // namespace mozilla

Generated by: LCOV version 1.13