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