content/canvas/src/CanvasUtils.cpp

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

mercurial