content/canvas/src/CanvasUtils.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <stdlib.h>
michael@0 7 #include <stdarg.h>
michael@0 8
michael@0 9 #include "prprf.h"
michael@0 10
michael@0 11 #include "nsIServiceManager.h"
michael@0 12
michael@0 13 #include "nsIConsoleService.h"
michael@0 14 #include "nsIDOMCanvasRenderingContext2D.h"
michael@0 15 #include "nsICanvasRenderingContextInternal.h"
michael@0 16 #include "nsIHTMLCollection.h"
michael@0 17 #include "mozilla/dom/HTMLCanvasElement.h"
michael@0 18 #include "nsIPrincipal.h"
michael@0 19
michael@0 20 #include "nsGfxCIID.h"
michael@0 21
michael@0 22 #include "nsTArray.h"
michael@0 23
michael@0 24 #include "CanvasUtils.h"
michael@0 25 #include "mozilla/gfx/Matrix.h"
michael@0 26
michael@0 27 using namespace mozilla::gfx;
michael@0 28
michael@0 29 #include "nsIScriptObjectPrincipal.h"
michael@0 30 #include "nsIPermissionManager.h"
michael@0 31 #include "nsIObserverService.h"
michael@0 32 #include "mozilla/Services.h"
michael@0 33 #include "mozIThirdPartyUtil.h"
michael@0 34 #include "nsContentUtils.h"
michael@0 35 #include "nsUnicharUtils.h"
michael@0 36 #include "nsPrintfCString.h"
michael@0 37 #include "nsIConsoleService.h"
michael@0 38 #include "jsapi.h"
michael@0 39
michael@0 40 #define TOPIC_CANVAS_PERMISSIONS_PROMPT "canvas-permissions-prompt"
michael@0 41 #define PERMISSION_CANVAS_EXTRACT_DATA "canvas/extractData"
michael@0 42
michael@0 43 namespace mozilla {
michael@0 44 namespace CanvasUtils {
michael@0 45
michael@0 46 // Check site-specific permission and display prompt if appropriate.
michael@0 47 bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx)
michael@0 48 {
michael@0 49 if (!aDocument || !aCx)
michael@0 50 return false;
michael@0 51
michael@0 52 nsPIDOMWindow *win = aDocument->GetWindow();
michael@0 53 nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
michael@0 54 if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()))
michael@0 55 return true;
michael@0 56
michael@0 57 // Don't show canvas prompt for chrome scripts (e.g. Page Inspector)
michael@0 58 if (nsContentUtils::IsCallerChrome())
michael@0 59 return true;
michael@0 60
michael@0 61 JS::AutoFilename scriptFile;
michael@0 62 unsigned scriptLine = 0;
michael@0 63 bool isScriptKnown = false;
michael@0 64 if (JS::DescribeScriptedCaller(aCx, &scriptFile, &scriptLine)) {
michael@0 65 isScriptKnown = true;
michael@0 66 // Don't show canvas prompt for PDF.js
michael@0 67 if (scriptFile.get() &&
michael@0 68 strcmp(scriptFile.get(), "resource://pdf.js/build/pdf.js") == 0)
michael@0 69 return true;
michael@0 70 }
michael@0 71 bool isAllowed = false;
michael@0 72 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
michael@0 73 do_GetService(THIRDPARTYUTIL_CONTRACTID);
michael@0 74 nsCOMPtr<nsIPermissionManager> permissionManager =
michael@0 75 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
michael@0 76 if (thirdPartyUtil && permissionManager) {
michael@0 77 nsCOMPtr<nsIURI> uri;
michael@0 78 nsresult rv = thirdPartyUtil->GetFirstPartyURI(NULL, aDocument,
michael@0 79 getter_AddRefs(uri));
michael@0 80 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
michael@0 81 if (NS_SUCCEEDED(rv)) {
michael@0 82 // Allow local files to access canvas data; check content permissions
michael@0 83 // for remote pages.
michael@0 84 bool isFileURL = false;
michael@0 85 (void)uri->SchemeIs("file", &isFileURL);
michael@0 86 if (isFileURL)
michael@0 87 permission = nsIPermissionManager::ALLOW_ACTION;
michael@0 88 else {
michael@0 89 rv = permissionManager->TestPermission(uri,
michael@0 90 PERMISSION_CANVAS_EXTRACT_DATA, &permission);
michael@0 91 }
michael@0 92 }
michael@0 93
michael@0 94 if (NS_SUCCEEDED(rv)) {
michael@0 95 isAllowed = (permission == nsIPermissionManager::ALLOW_ACTION);
michael@0 96
michael@0 97 if (!isAllowed && (permission != nsIPermissionManager::DENY_ACTION)) {
michael@0 98 // Log all attempted canvas access and block access by third parties.
michael@0 99 bool isThirdParty = true;
michael@0 100 nsIURI *docURI = aDocument->GetDocumentURI();
michael@0 101 rv = thirdPartyUtil->IsThirdPartyURI(uri, docURI, &isThirdParty);
michael@0 102 NS_ENSURE_SUCCESS(rv, false);
michael@0 103
michael@0 104 nsCString firstPartySpec;
michael@0 105 rv = uri->GetSpec(firstPartySpec);
michael@0 106 nsCString docSpec;
michael@0 107 docURI->GetSpec(docSpec);
michael@0 108 nsPrintfCString msg("On %s: blocked access to canvas image data"
michael@0 109 " from document %s, ", // L10n
michael@0 110 firstPartySpec.get(), docSpec.get());
michael@0 111 if (isScriptKnown && scriptFile.get()) {
michael@0 112 msg += nsPrintfCString("script from %s:%u", // L10n
michael@0 113 scriptFile.get(), scriptLine);
michael@0 114 } else {
michael@0 115 msg += nsPrintfCString("unknown script"); // L10n
michael@0 116 }
michael@0 117 nsCOMPtr<nsIConsoleService> console
michael@0 118 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
michael@0 119 if (console)
michael@0 120 console->LogStringMessage(NS_ConvertUTF8toUTF16(msg).get());
michael@0 121
michael@0 122 // Log every canvas access attempt to stdout if debugging:
michael@0 123 #ifdef DEBUG
michael@0 124 printf("%s\n", msg.get());
michael@0 125 #endif
michael@0 126 // Ensure URI is valid after logging, but before trying to notify the
michael@0 127 // user:
michael@0 128 NS_ENSURE_SUCCESS(rv, false);
michael@0 129
michael@0 130 if (!isThirdParty) {
michael@0 131 // Send notification so that a prompt is displayed.
michael@0 132 nsCOMPtr<nsIObserverService> obs =
michael@0 133 mozilla::services::GetObserverService();
michael@0 134 obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT,
michael@0 135 NS_ConvertUTF8toUTF16(firstPartySpec).get());
michael@0 136 }
michael@0 137 }
michael@0 138 }
michael@0 139 }
michael@0 140
michael@0 141 return isAllowed;
michael@0 142 }
michael@0 143
michael@0 144 void
michael@0 145 DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
michael@0 146 nsIPrincipal *aPrincipal,
michael@0 147 bool forceWriteOnly,
michael@0 148 bool CORSUsed)
michael@0 149 {
michael@0 150 NS_PRECONDITION(aPrincipal, "Must have a principal here");
michael@0 151
michael@0 152 // Callers should ensure that mCanvasElement is non-null before calling this
michael@0 153 if (!aCanvasElement) {
michael@0 154 NS_WARNING("DoDrawImageSecurityCheck called without canvas element!");
michael@0 155 return;
michael@0 156 }
michael@0 157
michael@0 158 if (aCanvasElement->IsWriteOnly())
michael@0 159 return;
michael@0 160
michael@0 161 // If we explicitly set WriteOnly just do it and get out
michael@0 162 if (forceWriteOnly) {
michael@0 163 aCanvasElement->SetWriteOnly();
michael@0 164 return;
michael@0 165 }
michael@0 166
michael@0 167 // No need to do a security check if the image used CORS for the load
michael@0 168 if (CORSUsed)
michael@0 169 return;
michael@0 170
michael@0 171 if (aCanvasElement->NodePrincipal()->Subsumes(aPrincipal)) {
michael@0 172 // This canvas has access to that image anyway
michael@0 173 return;
michael@0 174 }
michael@0 175
michael@0 176 aCanvasElement->SetWriteOnly();
michael@0 177 }
michael@0 178
michael@0 179 bool
michael@0 180 CoerceDouble(JS::Value v, double* d)
michael@0 181 {
michael@0 182 if (JSVAL_IS_DOUBLE(v)) {
michael@0 183 *d = JSVAL_TO_DOUBLE(v);
michael@0 184 } else if (JSVAL_IS_INT(v)) {
michael@0 185 *d = double(JSVAL_TO_INT(v));
michael@0 186 } else if (JSVAL_IS_VOID(v)) {
michael@0 187 *d = 0.0;
michael@0 188 } else {
michael@0 189 return false;
michael@0 190 }
michael@0 191 return true;
michael@0 192 }
michael@0 193
michael@0 194 } // namespace CanvasUtils
michael@0 195 } // namespace mozilla

mercurial