Bug 1609665 - push notifications should use registrations with an exact scope match r=dom-workers-and-storage-reviewers,asuth
authorPerry Jiang <perry@mozilla.com>
Sat, 22 Feb 2020 00:26:03 +0000
changeset 2648962 2d889781b71a59bcd9fdd77245994678d701f1da
parent 2648961 fc61eb14ceee168bd68ae4fa5720ab96b60b727c
child 2648963 a6e13b672e0f8542dc0f66d1b94fd7cc8eb023a3
push id490874
push userdvarga@mozilla.com
push dateSat, 22 Feb 2020 10:42:44 +0000
treeherdertry@64a8e247759e [default view] [failures only]
reviewersdom-workers-and-storage-reviewers, asuth
bugs1609665
milestone75.0a1
Bug 1609665 - push notifications should use registrations with an exact scope match r=dom-workers-and-storage-reviewers,asuth Also adds ScopeToPrincipal function to convert scope nsIURI/strings to principals. Differential Revision: https://phabricator.services.mozilla.com/D63736
dom/serviceworkers/ServiceWorkerManager.cpp
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -23,16 +23,18 @@
 #include "nsXULAppAPI.h"
 
 #include "jsapi.h"
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultExtensions.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ClientHandle.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientSource.h"
 #include "mozilla/dom/ConsoleUtils.h"
 #include "mozilla/dom/ContentParent.h"
@@ -367,16 +369,39 @@ already_AddRefed<nsIAsyncShutdownClient>
   nsCOMPtr<nsIAsyncShutdownClient> barrier;
   DebugOnly<nsresult> rv =
       svc->GetProfileChangeTeardown(getter_AddRefs(barrier));
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   return barrier.forget();
 }
 
+Result<nsCOMPtr<nsIPrincipal>, nsresult> ScopeToPrincipal(
+    nsIURI* aScopeURI, const OriginAttributes& aOriginAttributes) {
+  MOZ_ASSERT(aScopeURI);
+
+  nsCOMPtr<nsIPrincipal> principal =
+      BasePrincipal::CreateContentPrincipal(aScopeURI, aOriginAttributes);
+  if (NS_WARN_IF(!principal)) {
+    return Err(NS_ERROR_FAILURE);
+  }
+
+  return principal;
+}
+
+Result<nsCOMPtr<nsIPrincipal>, nsresult> ScopeToPrincipal(
+    const nsACString& aScope, const OriginAttributes& aOriginAttributes) {
+  MOZ_ASSERT(nsContentUtils::IsAbsoluteURL(aScope));
+
+  nsCOMPtr<nsIURI> scopeURI;
+  MOZ_TRY(NS_NewURI(getter_AddRefs(scopeURI), aScope));
+
+  return ScopeToPrincipal(scopeURI, aOriginAttributes);
+}
+
 }  // namespace
 
 //////////////////////////
 // ServiceWorkerManager //
 //////////////////////////
 
 NS_IMPL_ADDREF(ServiceWorkerManager)
 NS_IMPL_RELEASE(ServiceWorkerManager)
@@ -1151,25 +1176,35 @@ ServiceWorkerManager::SendPushEvent(cons
 nsresult ServiceWorkerManager::SendPushEvent(
     const nsACString& aOriginAttributes, const nsACString& aScope,
     const nsAString& aMessageId, const Maybe<nsTArray<uint8_t>>& aData) {
   OriginAttributes attrs;
   if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  ServiceWorkerInfo* serviceWorker = GetActiveWorkerInfoForScope(attrs, aScope);
+  nsCOMPtr<nsIPrincipal> principal;
+  MOZ_TRY_VAR(principal, ScopeToPrincipal(aScope, attrs));
+
+  // The registration handling a push notification must have an exact scope
+  // match. This will try to find an exact match, unlike how fetch may find the
+  // registration with the longest scope that's a prefix of the fetched URL.
+  RefPtr<ServiceWorkerRegistrationInfo> registration =
+      GetRegistration(principal, aScope);
+  if (NS_WARN_IF(!registration)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_DIAGNOSTIC_ASSERT(registration->Scope().Equals(aScope));
+
+  ServiceWorkerInfo* serviceWorker = registration->GetActive();
   if (NS_WARN_IF(!serviceWorker)) {
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<ServiceWorkerRegistrationInfo> registration =
-      GetRegistration(serviceWorker->Principal(), aScope);
-  MOZ_RELEASE_ASSERT(registration);
-
   return serviceWorker->WorkerPrivate()->SendPushEvent(aMessageId, aData,
                                                        registration);
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::SendPushSubscriptionChangeEvent(
     const nsACString& aOriginAttributes, const nsACString& aScope) {
   OriginAttributes attrs;
@@ -1324,18 +1359,24 @@ ServiceWorkerInfo* ServiceWorkerManager:
     const OriginAttributes& aOriginAttributes, const nsACString& aScope) {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIURI> scopeURI;
   nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope);
   if (NS_FAILED(rv)) {
     return nullptr;
   }
-  nsCOMPtr<nsIPrincipal> principal =
-      BasePrincipal::CreateContentPrincipal(scopeURI, aOriginAttributes);
+
+  auto result = ScopeToPrincipal(scopeURI, aOriginAttributes);
+  if (NS_WARN_IF(result.isErr())) {
+    return nullptr;
+  }
+
+  auto principal = result.unwrap();
+
   RefPtr<ServiceWorkerRegistrationInfo> registration =
       GetServiceWorkerRegistrationInfo(principal, scopeURI);
   if (!registration) {
     return nullptr;
   }
 
   return registration->GetActive();
 }
@@ -2404,30 +2445,25 @@ void ServiceWorkerManager::SoftUpdateInt
     const OriginAttributes& aOriginAttributes, const nsACString& aScope,
     ServiceWorkerUpdateFinishCallback* aCallback) {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown) {
     return;
   }
 
-  nsCOMPtr<nsIURI> scopeURI;
-  nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  auto result = ScopeToPrincipal(aScope, aOriginAttributes);
+  if (NS_WARN_IF(result.isErr())) {
     return;
   }
 
-  nsCOMPtr<nsIPrincipal> principal =
-      BasePrincipal::CreateContentPrincipal(scopeURI, aOriginAttributes);
-  if (NS_WARN_IF(!principal)) {
-    return;
-  }
+  auto principal = result.unwrap();
 
   nsAutoCString scopeKey;
-  rv = PrincipalToScopeKey(principal, scopeKey);
+  nsresult rv = PrincipalToScopeKey(principal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
       GetRegistration(scopeKey, aScope);
   if (NS_WARN_IF(!registration)) {
     return;