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/DocumentObserver.h"
8 #include "mozilla/extensions/WebExtensionContentScript.h"
9 #include "mozilla/extensions/WebExtensionPolicy.h"
10 
11 #include "mozilla/BasePrincipal.h"
12 #include "mozilla/ClearOnShutdown.h"
13 #include "mozilla/Preferences.h"
14 #include "mozilla/ResultExtensions.h"
15 #include "mozilla/Services.h"
16 #include "mozilla/SimpleEnumerator.h"
17 #include "mozilla/StaticPrefs_extensions.h"
18 #include "mozilla/dom/BrowsingContext.h"
19 #include "mozilla/dom/BrowsingContextGroup.h"
20 #include "mozilla/dom/ContentChild.h"
21 #include "mozilla/dom/ContentParent.h"
22 #include "mozilla/dom/Promise.h"
23 #include "mozilla/dom/Promise-inl.h"
24 #include "mozIExtensionProcessScript.h"
25 #include "nsEscape.h"
26 #include "nsGkAtoms.h"
27 #include "nsIChannel.h"
28 #include "nsIContentPolicy.h"
29 #include "mozilla/dom/Document.h"
30 #include "nsGlobalWindowOuter.h"
31 #include "nsILoadInfo.h"
32 #include "nsIXULRuntime.h"
33 #include "nsImportModule.h"
34 #include "nsNetUtil.h"
35 #include "nsPrintfCString.h"
36 #include "nsPIDOMWindow.h"
37 #include "nsXULAppAPI.h"
38 #include "nsQueryObject.h"
39 
40 namespace mozilla {
41 
42 using namespace extensions;
43 
44 using dom::AutoJSAPI;
45 using dom::Document;
46 using dom::Promise;
47 
48 #define DEFAULT_CSP_PREF \
49   "extensions.webextensions.default-content-security-policy"
50 #define DEFAULT_DEFAULT_CSP "script-src 'self'; object-src 'self';"
51 
52 #define OBS_TOPIC_PRELOAD_SCRIPT "web-extension-preload-content-script"
53 #define OBS_TOPIC_LOAD_SCRIPT "web-extension-load-content-script"
54 
55 static const char kDocElementInserted[] = "initial-document-element-inserted";
56 
57 /*****************************************************************************
58  * ExtensionPolicyService
59  *****************************************************************************/
60 
61 /* static */
ProcessScript()62 mozIExtensionProcessScript& ExtensionPolicyService::ProcessScript() {
63   static nsCOMPtr<mozIExtensionProcessScript> sProcessScript;
64 
65   MOZ_ASSERT(NS_IsMainThread());
66 
67   if (MOZ_UNLIKELY(!sProcessScript)) {
68     sProcessScript =
69         do_ImportModule("resource://gre/modules/ExtensionProcessScript.jsm",
70                         "ExtensionProcessScript");
71     MOZ_RELEASE_ASSERT(sProcessScript);
72     ClearOnShutdown(&sProcessScript);
73   }
74   return *sProcessScript;
75 }
76 
GetSingleton()77 /* static */ ExtensionPolicyService& ExtensionPolicyService::GetSingleton() {
78   static RefPtr<ExtensionPolicyService> sExtensionPolicyService;
79 
80   if (MOZ_UNLIKELY(!sExtensionPolicyService)) {
81     sExtensionPolicyService = new ExtensionPolicyService();
82     RegisterWeakMemoryReporter(sExtensionPolicyService);
83     ClearOnShutdown(&sExtensionPolicyService);
84   }
85   return *sExtensionPolicyService.get();
86 }
87 
ExtensionPolicyService()88 ExtensionPolicyService::ExtensionPolicyService() {
89   mObs = services::GetObserverService();
90   MOZ_RELEASE_ASSERT(mObs);
91 
92   mDefaultCSP.SetIsVoid(true);
93 
94   RegisterObservers();
95 }
96 
~ExtensionPolicyService()97 ExtensionPolicyService::~ExtensionPolicyService() {
98   UnregisterWeakMemoryReporter(this);
99 }
100 
UseRemoteExtensions() const101 bool ExtensionPolicyService::UseRemoteExtensions() const {
102   static Maybe<bool> sRemoteExtensions;
103   if (MOZ_UNLIKELY(sRemoteExtensions.isNothing())) {
104     sRemoteExtensions = Some(StaticPrefs::extensions_webextensions_remote());
105   }
106   return sRemoteExtensions.value() && BrowserTabsRemoteAutostart();
107 }
108 
IsExtensionProcess() const109 bool ExtensionPolicyService::IsExtensionProcess() const {
110   bool isRemote = UseRemoteExtensions();
111 
112   if (isRemote && XRE_IsContentProcess()) {
113     auto& remoteType = dom::ContentChild::GetSingleton()->GetRemoteType();
114     return remoteType == EXTENSION_REMOTE_TYPE;
115   }
116   return !isRemote && XRE_IsParentProcess();
117 }
118 
GetByURL(const URLInfo & aURL)119 WebExtensionPolicy* ExtensionPolicyService::GetByURL(const URLInfo& aURL) {
120   if (aURL.Scheme() == nsGkAtoms::moz_extension) {
121     return GetByHost(aURL.Host());
122   }
123   return nullptr;
124 }
125 
GetAll(nsTArray<RefPtr<WebExtensionPolicy>> & aResult)126 void ExtensionPolicyService::GetAll(
127     nsTArray<RefPtr<WebExtensionPolicy>>& aResult) {
128   AppendToArray(aResult, mExtensions.Values());
129 }
130 
RegisterExtension(WebExtensionPolicy & aPolicy)131 bool ExtensionPolicyService::RegisterExtension(WebExtensionPolicy& aPolicy) {
132   bool ok =
133       (!GetByID(aPolicy.Id()) && !GetByHost(aPolicy.MozExtensionHostname()));
134   MOZ_ASSERT(ok);
135 
136   if (!ok) {
137     return false;
138   }
139 
140   mExtensions.InsertOrUpdate(aPolicy.Id(), RefPtr{&aPolicy});
141   mExtensionHosts.InsertOrUpdate(aPolicy.MozExtensionHostname(),
142                                  RefPtr{&aPolicy});
143   return true;
144 }
145 
UnregisterExtension(WebExtensionPolicy & aPolicy)146 bool ExtensionPolicyService::UnregisterExtension(WebExtensionPolicy& aPolicy) {
147   bool ok = (GetByID(aPolicy.Id()) == &aPolicy &&
148              GetByHost(aPolicy.MozExtensionHostname()) == &aPolicy);
149   MOZ_ASSERT(ok);
150 
151   if (!ok) {
152     return false;
153   }
154 
155   mExtensions.Remove(aPolicy.Id());
156   mExtensionHosts.Remove(aPolicy.MozExtensionHostname());
157   return true;
158 }
159 
RegisterObserver(DocumentObserver & aObserver)160 bool ExtensionPolicyService::RegisterObserver(DocumentObserver& aObserver) {
161   bool inserted = false;
162   mObservers.LookupOrInsertWith(&aObserver, [&] {
163     inserted = true;
164     return RefPtr{&aObserver};
165   });
166   return inserted;
167 }
168 
UnregisterObserver(DocumentObserver & aObserver)169 bool ExtensionPolicyService::UnregisterObserver(DocumentObserver& aObserver) {
170   return mObservers.Remove(&aObserver);
171 }
172 
173 /*****************************************************************************
174  * nsIMemoryReporter
175  *****************************************************************************/
176 
177 NS_IMETHODIMP
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)178 ExtensionPolicyService::CollectReports(nsIHandleReportCallback* aHandleReport,
179                                        nsISupports* aData, bool aAnonymize) {
180   for (const auto& ext : mExtensions.Values()) {
181     nsAtomCString id(ext->Id());
182 
183     NS_ConvertUTF16toUTF8 name(ext->Name());
184     name.ReplaceSubstring("\"", "");
185     name.ReplaceSubstring("\\", "");
186 
187     nsString url;
188     MOZ_TRY_VAR(url, ext->GetURL(u""_ns));
189 
190     nsPrintfCString desc("Extension(id=%s, name=\"%s\", baseURL=%s)", id.get(),
191                          name.get(), NS_ConvertUTF16toUTF8(url).get());
192     desc.ReplaceChar('/', '\\');
193 
194     nsCString path("extensions/");
195     path.Append(desc);
196 
197     aHandleReport->Callback(""_ns, path, KIND_NONHEAP, UNITS_COUNT, 1,
198                             "WebExtensions that are active in this session"_ns,
199                             aData);
200   }
201 
202   return NS_OK;
203 }
204 
205 /*****************************************************************************
206  * Content script management
207  *****************************************************************************/
208 
RegisterObservers()209 void ExtensionPolicyService::RegisterObservers() {
210   mObs->AddObserver(this, kDocElementInserted, false);
211   if (XRE_IsContentProcess()) {
212     mObs->AddObserver(this, "http-on-opening-request", false);
213     mObs->AddObserver(this, "document-on-opening-request", false);
214   }
215 
216   Preferences::AddStrongObserver(this, DEFAULT_CSP_PREF);
217 }
218 
UnregisterObservers()219 void ExtensionPolicyService::UnregisterObservers() {
220   mObs->RemoveObserver(this, kDocElementInserted);
221   if (XRE_IsContentProcess()) {
222     mObs->RemoveObserver(this, "http-on-opening-request");
223     mObs->RemoveObserver(this, "document-on-opening-request");
224   }
225 
226   Preferences::RemoveObserver(this, DEFAULT_CSP_PREF);
227 }
228 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)229 nsresult ExtensionPolicyService::Observe(nsISupports* aSubject,
230                                          const char* aTopic,
231                                          const char16_t* aData) {
232   if (!strcmp(aTopic, kDocElementInserted)) {
233     nsCOMPtr<Document> doc = do_QueryInterface(aSubject);
234     if (doc) {
235       CheckDocument(doc);
236     }
237   } else if (!strcmp(aTopic, "http-on-opening-request") ||
238              !strcmp(aTopic, "document-on-opening-request")) {
239     nsCOMPtr<nsIChannel> chan = do_QueryInterface(aSubject);
240     if (chan) {
241       CheckRequest(chan);
242     }
243   } else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
244     const nsCString converted = NS_ConvertUTF16toUTF8(aData);
245     const char* pref = converted.get();
246     if (!strcmp(pref, DEFAULT_CSP_PREF)) {
247       mDefaultCSP.SetIsVoid(true);
248     }
249   }
250   return NS_OK;
251 }
252 
ExecuteContentScript(nsPIDOMWindowInner * aWindow,WebExtensionContentScript & aScript)253 already_AddRefed<Promise> ExtensionPolicyService::ExecuteContentScript(
254     nsPIDOMWindowInner* aWindow, WebExtensionContentScript& aScript) {
255   if (!aWindow->IsCurrentInnerWindow()) {
256     return nullptr;
257   }
258 
259   RefPtr<Promise> promise;
260   ProcessScript().LoadContentScript(&aScript, aWindow, getter_AddRefs(promise));
261   return promise.forget();
262 }
263 
ExecuteContentScripts(JSContext * aCx,nsPIDOMWindowInner * aWindow,const nsTArray<RefPtr<WebExtensionContentScript>> & aScripts)264 RefPtr<Promise> ExtensionPolicyService::ExecuteContentScripts(
265     JSContext* aCx, nsPIDOMWindowInner* aWindow,
266     const nsTArray<RefPtr<WebExtensionContentScript>>& aScripts) {
267   AutoTArray<RefPtr<Promise>, 8> promises;
268 
269   for (auto& script : aScripts) {
270     if (RefPtr<Promise> promise = ExecuteContentScript(aWindow, *script)) {
271       promises.AppendElement(std::move(promise));
272     }
273   }
274 
275   RefPtr<Promise> promise = Promise::All(aCx, promises, IgnoreErrors());
276   MOZ_RELEASE_ASSERT(promise);
277   return promise;
278 }
279 
280 // Use browser's MessageManagerGroup to decide if we care about it, to inject
281 // extension APIs or content scripts.  Tabs use "browsers", and all custom
282 // extension browsers use "webext-browsers", including popups & sidebars,
283 // background & options pages, and xpcshell tests.
IsTabOrExtensionBrowser(dom::BrowsingContext * aBC)284 static bool IsTabOrExtensionBrowser(dom::BrowsingContext* aBC) {
285   const auto& group = aBC->Top()->GetMessageManagerGroup();
286   bool rv = group == u"browsers"_ns || group == u"webext-browsers"_ns;
287 
288 #ifdef MOZ_THUNDERBIRD
289   // ...unless it's Thunderbird, which has extra groups for unrelated reasons.
290   rv = rv || group == u"single-site"_ns || group == u"single-page"_ns;
291 #endif
292 
293   return rv;
294 }
295 
GetAllInProcessContentBCs()296 static nsTArray<RefPtr<dom::BrowsingContext>> GetAllInProcessContentBCs() {
297   nsTArray<RefPtr<dom::BrowsingContext>> contentBCs;
298   nsTArray<RefPtr<dom::BrowsingContextGroup>> groups;
299   dom::BrowsingContextGroup::GetAllGroups(groups);
300   for (const auto& group : groups) {
301     for (const auto& toplevel : group->Toplevels()) {
302       if (!toplevel->IsContent() || toplevel->IsDiscarded() ||
303           !IsTabOrExtensionBrowser(toplevel)) {
304         continue;
305       }
306 
307       toplevel->PreOrderWalk([&](dom::BrowsingContext* aContext) {
308         contentBCs.AppendElement(aContext);
309       });
310     }
311   }
312   return contentBCs;
313 }
314 
InjectContentScripts(WebExtensionPolicy * aExtension)315 nsresult ExtensionPolicyService::InjectContentScripts(
316     WebExtensionPolicy* aExtension) {
317   AutoJSAPI jsapi;
318   MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
319 
320   auto contentBCs = GetAllInProcessContentBCs();
321   for (dom::BrowsingContext* bc : contentBCs) {
322     auto* win = bc->GetDOMWindow();
323 
324     if (bc->Top()->IsDiscarded() || !win || !win->GetDocumentURI()) {
325       continue;
326     }
327     DocInfo docInfo(win);
328 
329     using RunAt = dom::ContentScriptRunAt;
330     namespace RunAtValues = dom::ContentScriptRunAtValues;
331     using Scripts = AutoTArray<RefPtr<WebExtensionContentScript>, 8>;
332 
333     Scripts scripts[RunAtValues::Count];
334 
335     auto GetScripts = [&](RunAt aRunAt) -> Scripts&& {
336       static_assert(sizeof(aRunAt) == 1, "Our cast is wrong");
337       return std::move(scripts[uint8_t(aRunAt)]);
338     };
339 
340     for (const auto& script : aExtension->ContentScripts()) {
341       if (script->Matches(docInfo)) {
342         GetScripts(script->RunAt()).AppendElement(script);
343       }
344     }
345 
346     nsCOMPtr<nsPIDOMWindowInner> inner = win->GetCurrentInnerWindow();
347 
348     MOZ_TRY(ExecuteContentScripts(jsapi.cx(), inner,
349                                   GetScripts(RunAt::Document_start))
350                 ->ThenWithCycleCollectedArgs(
351                     [](JSContext* aCx, JS::HandleValue aValue,
352                        ExtensionPolicyService* aSelf,
353                        nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
354                       return aSelf->ExecuteContentScripts(aCx, aInner, aScripts)
355                           .forget();
356                     },
357                     this, inner, GetScripts(RunAt::Document_end))
358                 .andThen([&](auto aPromise) {
359                   return aPromise->ThenWithCycleCollectedArgs(
360                       [](JSContext* aCx, JS::HandleValue aValue,
361                          ExtensionPolicyService* aSelf,
362                          nsPIDOMWindowInner* aInner, Scripts&& aScripts) {
363                         return aSelf
364                             ->ExecuteContentScripts(aCx, aInner, aScripts)
365                             .forget();
366                       },
367                       this, inner, GetScripts(RunAt::Document_idle));
368                 }));
369   }
370   return NS_OK;
371 }
372 
373 // Checks a request for matching content scripts, and begins pre-loading them
374 // if necessary.
CheckRequest(nsIChannel * aChannel)375 void ExtensionPolicyService::CheckRequest(nsIChannel* aChannel) {
376   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
377   auto loadType = loadInfo->GetExternalContentPolicyType();
378   if (loadType != ExtContentPolicy::TYPE_DOCUMENT &&
379       loadType != ExtContentPolicy::TYPE_SUBDOCUMENT) {
380     return;
381   }
382 
383   nsCOMPtr<nsIURI> uri;
384   if (NS_FAILED(aChannel->GetURI(getter_AddRefs(uri)))) {
385     return;
386   }
387 
388   CheckContentScripts({uri.get(), loadInfo}, true);
389 }
390 
CheckParentFrames(nsPIDOMWindowOuter * aWindow,WebExtensionPolicy & aPolicy)391 static bool CheckParentFrames(nsPIDOMWindowOuter* aWindow,
392                               WebExtensionPolicy& aPolicy) {
393   nsCOMPtr<nsIURI> aboutAddons;
394   if (NS_FAILED(NS_NewURI(getter_AddRefs(aboutAddons), "about:addons"))) {
395     return false;
396   }
397   nsCOMPtr<nsIURI> htmlAboutAddons;
398   if (NS_FAILED(
399           NS_NewURI(getter_AddRefs(htmlAboutAddons),
400                     "chrome://mozapps/content/extensions/aboutaddons.html"))) {
401     return false;
402   }
403 
404   dom::WindowContext* wc = aWindow->GetCurrentInnerWindow()->GetWindowContext();
405   while ((wc = wc->GetParentWindowContext())) {
406     if (!wc->IsInProcess()) {
407       return false;
408     }
409 
410     nsGlobalWindowInner* win = wc->GetInnerWindow();
411 
412     auto* principal = BasePrincipal::Cast(win->GetPrincipal());
413     if (principal->IsSystemPrincipal()) {
414       // The add-on manager is a special case, since it contains extension
415       // options pages in same-type <browser> frames.
416       nsIURI* uri = win->GetDocumentURI();
417       bool equals;
418       if ((NS_SUCCEEDED(uri->Equals(aboutAddons, &equals)) && equals) ||
419           (NS_SUCCEEDED(uri->Equals(htmlAboutAddons, &equals)) && equals)) {
420         return true;
421       }
422     }
423 
424     if (principal->AddonPolicy() != &aPolicy) {
425       return false;
426     }
427   }
428 
429   return true;
430 }
431 
432 // Checks a document, just after the document element has been inserted, for
433 // matching content scripts or extension principals, and loads them if
434 // necessary.
CheckDocument(Document * aDocument)435 void ExtensionPolicyService::CheckDocument(Document* aDocument) {
436   nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
437   if (win) {
438     if (!IsTabOrExtensionBrowser(win->GetBrowsingContext())) {
439       return;
440     }
441 
442     if (win->GetDocumentURI()) {
443       CheckContentScripts(win.get(), false);
444     }
445 
446     nsIPrincipal* principal = aDocument->NodePrincipal();
447 
448     RefPtr<WebExtensionPolicy> policy =
449         BasePrincipal::Cast(principal)->AddonPolicy();
450     if (policy) {
451       bool privileged = IsExtensionProcess() && CheckParentFrames(win, *policy);
452 
453       ProcessScript().InitExtensionDocument(policy, aDocument, privileged);
454     }
455   }
456 }
457 
CheckContentScripts(const DocInfo & aDocInfo,bool aIsPreload)458 void ExtensionPolicyService::CheckContentScripts(const DocInfo& aDocInfo,
459                                                  bool aIsPreload) {
460   nsCOMPtr<nsPIDOMWindowInner> win;
461   if (!aIsPreload) {
462     win = aDocInfo.GetWindow()->GetCurrentInnerWindow();
463   }
464 
465   nsTArray<RefPtr<WebExtensionContentScript>> scriptsToLoad;
466 
467   for (RefPtr<WebExtensionPolicy> policy : mExtensions.Values()) {
468     for (auto& script : policy->ContentScripts()) {
469       if (script->Matches(aDocInfo)) {
470         if (aIsPreload) {
471           ProcessScript().PreloadContentScript(script);
472         } else {
473           // Collect the content scripts to load instead of loading them
474           // right away (to prevent a loaded content script from being
475           // able to invalidate the iterator by triggering a call to
476           // policy->UnregisterContentScript while we are still iterating
477           // over all its content scripts). See Bug 1593240.
478           scriptsToLoad.AppendElement(script);
479         }
480       }
481     }
482 
483     for (auto& script : scriptsToLoad) {
484       if (!win->IsCurrentInnerWindow()) {
485         break;
486       }
487 
488       RefPtr<Promise> promise;
489       ProcessScript().LoadContentScript(script, win, getter_AddRefs(promise));
490     }
491 
492     scriptsToLoad.ClearAndRetainStorage();
493   }
494 
495   for (RefPtr<DocumentObserver> observer : mObservers.Values()) {
496     for (auto& matcher : observer->Matchers()) {
497       if (matcher->Matches(aDocInfo)) {
498         if (aIsPreload) {
499           observer->NotifyMatch(*matcher, aDocInfo.GetLoadInfo());
500         } else {
501           observer->NotifyMatch(*matcher, aDocInfo.GetWindow());
502         }
503       }
504     }
505   }
506 }
507 
508 /*****************************************************************************
509  * nsIAddonPolicyService
510  *****************************************************************************/
511 
GetDefaultCSP(nsAString & aDefaultCSP)512 nsresult ExtensionPolicyService::GetDefaultCSP(nsAString& aDefaultCSP) {
513   if (mDefaultCSP.IsVoid()) {
514     nsresult rv = Preferences::GetString(DEFAULT_CSP_PREF, mDefaultCSP);
515     if (NS_FAILED(rv)) {
516       mDefaultCSP.AssignLiteral(DEFAULT_DEFAULT_CSP);
517     }
518     mDefaultCSP.SetIsVoid(false);
519   }
520 
521   aDefaultCSP.Assign(mDefaultCSP);
522   return NS_OK;
523 }
524 
GetBaseCSP(const nsAString & aAddonId,nsAString & aResult)525 nsresult ExtensionPolicyService::GetBaseCSP(const nsAString& aAddonId,
526                                             nsAString& aResult) {
527   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
528     policy->GetBaseCSP(aResult);
529     return NS_OK;
530   }
531   return NS_ERROR_INVALID_ARG;
532 }
533 
GetExtensionPageCSP(const nsAString & aAddonId,nsAString & aResult)534 nsresult ExtensionPolicyService::GetExtensionPageCSP(const nsAString& aAddonId,
535                                                      nsAString& aResult) {
536   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
537     policy->GetExtensionPageCSP(aResult);
538     return NS_OK;
539   }
540   return NS_ERROR_INVALID_ARG;
541 }
542 
GetGeneratedBackgroundPageUrl(const nsACString & aHostname,nsACString & aResult)543 nsresult ExtensionPolicyService::GetGeneratedBackgroundPageUrl(
544     const nsACString& aHostname, nsACString& aResult) {
545   if (WebExtensionPolicy* policy = GetByHost(aHostname)) {
546     nsAutoCString url("data:text/html,");
547 
548     nsCString html = policy->BackgroundPageHTML();
549     nsAutoCString escaped;
550 
551     url.Append(NS_EscapeURL(html, esc_Minimal, escaped));
552 
553     aResult = url;
554     return NS_OK;
555   }
556   return NS_ERROR_INVALID_ARG;
557 }
558 
AddonHasPermission(const nsAString & aAddonId,const nsAString & aPerm,bool * aResult)559 nsresult ExtensionPolicyService::AddonHasPermission(const nsAString& aAddonId,
560                                                     const nsAString& aPerm,
561                                                     bool* aResult) {
562   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
563     *aResult = policy->HasPermission(aPerm);
564     return NS_OK;
565   }
566   return NS_ERROR_INVALID_ARG;
567 }
568 
AddonMayLoadURI(const nsAString & aAddonId,nsIURI * aURI,bool aExplicit,bool * aResult)569 nsresult ExtensionPolicyService::AddonMayLoadURI(const nsAString& aAddonId,
570                                                  nsIURI* aURI, bool aExplicit,
571                                                  bool* aResult) {
572   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
573     *aResult = policy->CanAccessURI(aURI, aExplicit);
574     return NS_OK;
575   }
576   return NS_ERROR_INVALID_ARG;
577 }
578 
GetExtensionName(const nsAString & aAddonId,nsAString & aName)579 nsresult ExtensionPolicyService::GetExtensionName(const nsAString& aAddonId,
580                                                   nsAString& aName) {
581   if (WebExtensionPolicy* policy = GetByID(aAddonId)) {
582     aName.Assign(policy->Name());
583     return NS_OK;
584   }
585   return NS_ERROR_INVALID_ARG;
586 }
587 
SourceMayLoadExtensionURI(nsIURI * aSourceURI,nsIURI * aExtensionURI,bool * aResult)588 nsresult ExtensionPolicyService::SourceMayLoadExtensionURI(
589     nsIURI* aSourceURI, nsIURI* aExtensionURI, bool* aResult) {
590   URLInfo source(aSourceURI);
591   URLInfo url(aExtensionURI);
592   if (WebExtensionPolicy* policy = GetByURL(url)) {
593     *aResult = policy->SourceMayAccessPath(source, url.FilePath());
594     return NS_OK;
595   }
596   return NS_ERROR_INVALID_ARG;
597 }
598 
ExtensionURIToAddonId(nsIURI * aURI,nsAString & aResult)599 nsresult ExtensionPolicyService::ExtensionURIToAddonId(nsIURI* aURI,
600                                                        nsAString& aResult) {
601   if (WebExtensionPolicy* policy = GetByURL(aURI)) {
602     policy->GetId(aResult);
603   } else {
604     aResult.SetIsVoid(true);
605   }
606   return NS_OK;
607 }
608 
609 NS_IMPL_CYCLE_COLLECTION(ExtensionPolicyService, mExtensions, mExtensionHosts,
610                          mObservers)
611 
612 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPolicyService)
613   NS_INTERFACE_MAP_ENTRY(nsIAddonPolicyService)
614   NS_INTERFACE_MAP_ENTRY(nsIObserver)
615   NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)
616   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAddonPolicyService)
617 NS_INTERFACE_MAP_END
618 
619 NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPolicyService)
620 NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPolicyService)
621 
622 }  // namespace mozilla
623