dom/indexedDB/CheckPermissionsHelper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/indexedDB/CheckPermissionsHelper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,222 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "CheckPermissionsHelper.h"
    1.11 +
    1.12 +#include "nsIDOMWindow.h"
    1.13 +#include "nsILoadContext.h"
    1.14 +#include "nsIWebNavigation.h"
    1.15 +#include "nsIObserverService.h"
    1.16 +#include "nsIPermissionManager.h"
    1.17 +#include "nsIPrincipal.h"
    1.18 +#include "nsIScriptObjectPrincipal.h"
    1.19 +#include "nsIURI.h"
    1.20 +
    1.21 +#include "CheckQuotaHelper.h"
    1.22 +#include "nsContentUtils.h"
    1.23 +#include "nsNetUtil.h"
    1.24 +#include "nsThreadUtils.h"
    1.25 +#include "mozilla/Services.h"
    1.26 +
    1.27 +#include "IndexedDatabaseManager.h"
    1.28 +
    1.29 +#define PERMISSION_INDEXEDDB "indexedDB"
    1.30 +#define TOPIC_PERMISSIONS_PROMPT "indexedDB-permissions-prompt"
    1.31 +#define TOPIC_PERMISSIONS_RESPONSE "indexedDB-permissions-response"
    1.32 +
    1.33 +// This is a little confusing, but our default behavior (UNKNOWN_ACTION) is to
    1.34 +// allow access without a prompt. If the "indexedDB" permission is set to
    1.35 +// ALLOW_ACTION then we will issue a prompt before allowing access. Otherwise
    1.36 +// (DENY_ACTION) we deny access.
    1.37 +#define PERMISSION_ALLOWED nsIPermissionManager::UNKNOWN_ACTION
    1.38 +#define PERMISSION_DENIED nsIPermissionManager::DENY_ACTION
    1.39 +#define PERMISSION_PROMPT nsIPermissionManager::ALLOW_ACTION
    1.40 +
    1.41 +USING_INDEXEDDB_NAMESPACE
    1.42 +using namespace mozilla::services;
    1.43 +using mozilla::dom::quota::CheckQuotaHelper;
    1.44 +
    1.45 +namespace {
    1.46 +
    1.47 +inline
    1.48 +uint32_t
    1.49 +GetIndexedDBPermissions(nsIDOMWindow* aWindow)
    1.50 +{
    1.51 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1.52 +
    1.53 +  NS_ASSERTION(aWindow, "Chrome shouldn't check the permission!");
    1.54 +
    1.55 +  nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
    1.56 +  NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
    1.57 +
    1.58 +  NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()),
    1.59 +               "Chrome windows shouldn't check the permission!");
    1.60 +
    1.61 +  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
    1.62 +  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
    1.63 +  if (loadContext && loadContext->UsePrivateBrowsing()) {
    1.64 +    // TODO Support private browsing indexedDB?
    1.65 +    NS_WARNING("IndexedDB may not be used while in private browsing mode!");
    1.66 +    return PERMISSION_DENIED;
    1.67 +  }
    1.68 +
    1.69 +  nsCOMPtr<nsIPermissionManager> permissionManager =
    1.70 +    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
    1.71 +  NS_ENSURE_TRUE(permissionManager, PERMISSION_DENIED);
    1.72 +
    1.73 +  uint32_t permission;
    1.74 +  nsresult rv =
    1.75 +    permissionManager->TestPermissionFromPrincipal(sop->GetPrincipal(),
    1.76 +                                                   PERMISSION_INDEXEDDB,
    1.77 +                                                   &permission);
    1.78 +  NS_ENSURE_SUCCESS(rv, PERMISSION_DENIED);
    1.79 +
    1.80 +  return permission;
    1.81 +}
    1.82 +
    1.83 +} // anonymous namespace
    1.84 +
    1.85 +NS_IMPL_ISUPPORTS(CheckPermissionsHelper, nsIRunnable,
    1.86 +                  nsIInterfaceRequestor,
    1.87 +                  nsIObserver)
    1.88 +
    1.89 +NS_IMETHODIMP
    1.90 +CheckPermissionsHelper::Run()
    1.91 +{
    1.92 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1.93 +
    1.94 +  uint32_t permission = mHasPrompted ?
    1.95 +                        mPromptResult :
    1.96 +                        GetIndexedDBPermissions(mWindow);
    1.97 +
    1.98 +  nsresult rv;
    1.99 +  if (mHasPrompted) {
   1.100 +    // Add permissions to the database, but only if we are in the parent
   1.101 +    // process (if we are in the child process, we have already
   1.102 +    // set the permission when the prompt was shown in the parent, as
   1.103 +    // we cannot set the permission from the child).
   1.104 +    if (permission != PERMISSION_PROMPT &&
   1.105 +        IndexedDatabaseManager::IsMainProcess()) {
   1.106 +      NS_ASSERTION(mWindow, "Null window!");
   1.107 +
   1.108 +      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
   1.109 +      NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
   1.110 +
   1.111 +      nsIPrincipal* windowPrincipal = sop->GetPrincipal();
   1.112 +      NS_ASSERTION(windowPrincipal, "Null principal!");
   1.113 +
   1.114 +      nsCOMPtr<nsIPermissionManager> permissionManager =
   1.115 +        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   1.116 +      NS_ENSURE_STATE(permissionManager);
   1.117 +
   1.118 +      rv = permissionManager->AddFromPrincipal(windowPrincipal,
   1.119 +                                               PERMISSION_INDEXEDDB, permission,
   1.120 +                                               nsIPermissionManager::EXPIRE_NEVER,
   1.121 +                                               0);
   1.122 +      NS_ENSURE_SUCCESS(rv, rv);
   1.123 +    }
   1.124 +  }
   1.125 +  else if (permission == PERMISSION_PROMPT && mPromptAllowed) {
   1.126 +    nsCOMPtr<nsIObserverService> obs = GetObserverService();
   1.127 +    rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
   1.128 +                              TOPIC_PERMISSIONS_PROMPT, nullptr);
   1.129 +    NS_ENSURE_SUCCESS(rv, rv);
   1.130 +
   1.131 +    return NS_OK;
   1.132 +  }
   1.133 +
   1.134 +  nsRefPtr<OpenDatabaseHelper> helper;
   1.135 +  helper.swap(mHelper);
   1.136 +
   1.137 +  nsCOMPtr<nsIDOMWindow> window;
   1.138 +  window.swap(mWindow);
   1.139 +
   1.140 +  if (permission == PERMISSION_ALLOWED) {
   1.141 +    // If we're running from a window then we should check the quota permission
   1.142 +    // as well. If we don't have a window then we're opening a chrome database
   1.143 +    // and the quota will be unlimited already.
   1.144 +    if (window) {
   1.145 +      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
   1.146 +      NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
   1.147 +
   1.148 +      nsIPrincipal* windowPrincipal = sop->GetPrincipal();
   1.149 +      NS_ASSERTION(windowPrincipal, "Null principal!");
   1.150 +
   1.151 +      uint32_t quotaPermission =
   1.152 +        CheckQuotaHelper::GetQuotaPermission(windowPrincipal);
   1.153 +
   1.154 +      if (quotaPermission == nsIPermissionManager::ALLOW_ACTION) {
   1.155 +        helper->SetUnlimitedQuotaAllowed();
   1.156 +      }
   1.157 +    }
   1.158 +
   1.159 +    return helper->DispatchToIOThread();
   1.160 +  }
   1.161 +
   1.162 +  NS_ASSERTION(permission == PERMISSION_PROMPT ||
   1.163 +               permission == PERMISSION_DENIED,
   1.164 +               "Unknown permission!");
   1.165 +
   1.166 +  helper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   1.167 +
   1.168 +  return helper->RunImmediately();
   1.169 +}
   1.170 +
   1.171 +NS_IMETHODIMP
   1.172 +CheckPermissionsHelper::GetInterface(const nsIID& aIID,
   1.173 +                                     void** aResult)
   1.174 +{
   1.175 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.176 +  if (aIID.Equals(NS_GET_IID(nsIObserver))) {
   1.177 +    return QueryInterface(aIID, aResult);
   1.178 +  }
   1.179 +
   1.180 +  if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
   1.181 +    return mWindow->QueryInterface(aIID, aResult);
   1.182 +  }
   1.183 +
   1.184 +  *aResult = nullptr;
   1.185 +  return NS_ERROR_NOT_AVAILABLE;
   1.186 +}
   1.187 +
   1.188 +NS_IMETHODIMP
   1.189 +CheckPermissionsHelper::Observe(nsISupports* aSubject,
   1.190 +                                const char* aTopic,
   1.191 +                                const char16_t* aData)
   1.192 +{
   1.193 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.194 +  NS_ASSERTION(!strcmp(aTopic, TOPIC_PERMISSIONS_RESPONSE), "Bad topic!");
   1.195 +  NS_ASSERTION(mPromptAllowed, "How did we get here?");
   1.196 +
   1.197 +  mHasPrompted = true;
   1.198 +
   1.199 +  nsresult rv;
   1.200 +  uint32_t promptResult = nsDependentString(aData).ToInteger(&rv);
   1.201 +  NS_ENSURE_SUCCESS(rv, rv);
   1.202 +
   1.203 +  // Have to convert the permission we got from the user to our weird reversed
   1.204 +  // permission type.
   1.205 +  switch (promptResult) {
   1.206 +    case nsIPermissionManager::ALLOW_ACTION:
   1.207 +      mPromptResult = PERMISSION_ALLOWED;
   1.208 +      break;
   1.209 +    case nsIPermissionManager::DENY_ACTION:
   1.210 +      mPromptResult = PERMISSION_DENIED;
   1.211 +      break;
   1.212 +    case nsIPermissionManager::UNKNOWN_ACTION:
   1.213 +      mPromptResult = PERMISSION_PROMPT;
   1.214 +      break;
   1.215 +
   1.216 +    default:
   1.217 +      NS_NOTREACHED("Unknown permission type!");
   1.218 +      mPromptResult = PERMISSION_DENIED;
   1.219 +  }
   1.220 +
   1.221 +  rv = NS_DispatchToCurrentThread(this);
   1.222 +  NS_ENSURE_SUCCESS(rv, rv);
   1.223 +
   1.224 +  return NS_OK;
   1.225 +}

mercurial