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 +}