commit 9a717351831505dff9b48b579353c043d8531fd6 Author: Arthur Edelstein arthuredelstein@gmail.com Date: Fri Nov 6 16:41:29 2015 -0800
fixup! Bug #6253: Add canvas image extraction prompt.
Ensure that third parties are never able to extract canvas image data, even if the same domain has been given permission previously as a first party.
Also, refactor slightly to clarify logic of IsImageExtractionAllowed. --- dom/canvas/CanvasUtils.cpp | 179 +++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 84 deletions(-)
diff --git a/dom/canvas/CanvasUtils.cpp b/dom/canvas/CanvasUtils.cpp index 9883a52..b3c83f6 100644 --- a/dom/canvas/CanvasUtils.cpp +++ b/dom/canvas/CanvasUtils.cpp @@ -46,99 +46,110 @@ namespace CanvasUtils { // Check site-specific permission and display prompt if appropriate. bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx) { - if (!aDocument || !aCx) - return false; + // Don't proceed if we don't have a document or JavaScript context. + if (!aDocument || !aCx) { + return false; + }
- nsPIDOMWindow *win = aDocument->GetWindow(); - nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win)); - if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) - return true; + // Documents with system principal can always extract canvas data. + nsPIDOMWindow *win = aDocument->GetWindow(); + nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win)); + if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) { + return true; + }
- // Don't show canvas prompt for chrome scripts (e.g. Page Inspector) - if (nsContentUtils::ThreadsafeIsCallerChrome()) - return true; + // Always give permission to chrome scripts (e.g. Page Inspector). + if (nsContentUtils::ThreadsafeIsCallerChrome()) { + return true; + }
- JS::AutoFilename scriptFile; - unsigned scriptLine = 0; - bool isScriptKnown = false; - if (JS::DescribeScriptedCaller(aCx, &scriptFile, &scriptLine)) { - isScriptKnown = true; - // Don't show canvas prompt for PDF.js - if (scriptFile.get() && - strcmp(scriptFile.get(), "resource://pdf.js/build/pdf.js") == 0) - return true; - } - bool isAllowed = false; - nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = - do_GetService(THIRDPARTYUTIL_CONTRACTID); - nsCOMPtr<nsIPermissionManager> permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); - if (thirdPartyUtil && permissionManager) { - nsCOMPtr<nsIURI> uri; - nsresult rv = thirdPartyUtil->GetFirstPartyURI(NULL, aDocument, - getter_AddRefs(uri)); - uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; - if (NS_SUCCEEDED(rv)) { - // Allow local files to access canvas data; check content permissions - // for remote pages. - bool isFileURL = false; - (void)uri->SchemeIs("file", &isFileURL); - if (isFileURL) - permission = nsIPermissionManager::ALLOW_ACTION; - else { - rv = permissionManager->TestPermission(uri, - PERMISSION_CANVAS_EXTRACT_DATA, &permission); - } + // Get the document URI and its spec. + nsIURI *docURI = aDocument->GetDocumentURI(); + nsCString docURISpec; + docURI->GetSpec(docURISpec); + + // Allow local files to extract canvas data. + bool isFileURL; + (void) docURI->SchemeIs("file", &isFileURL); + if (isFileURL) { + return true; }
- if (NS_SUCCEEDED(rv)) { - isAllowed = (permission == nsIPermissionManager::ALLOW_ACTION); - - if (!isAllowed && (permission != nsIPermissionManager::DENY_ACTION)) { - // Log all attempted canvas access and block access by third parties. - bool isThirdParty = true; - nsIURI *docURI = aDocument->GetDocumentURI(); - rv = thirdPartyUtil->IsThirdPartyURI(uri, docURI, &isThirdParty); - NS_ENSURE_SUCCESS(rv, false); - - nsCString firstPartySpec; - rv = uri->GetSpec(firstPartySpec); - nsCString docSpec; - docURI->GetSpec(docSpec); - nsPrintfCString msg("On %s: blocked access to canvas image data" - " from document %s, ", // L10n - firstPartySpec.get(), docSpec.get()); - if (isScriptKnown && scriptFile.get()) { - msg += nsPrintfCString("script from %s:%u", // L10n - scriptFile.get(), scriptLine); - } else { - msg += nsPrintfCString("unknown script"); // L10n + // Get calling script file and line for logging. + JS::AutoFilename scriptFile; + unsigned scriptLine = 0; + bool isScriptKnown = false; + if (JS::DescribeScriptedCaller(aCx, &scriptFile, &scriptLine)) { + isScriptKnown = true; + // Don't show canvas prompt for PDF.js + if (scriptFile.get() && + strcmp(scriptFile.get(), "resource://pdf.js/build/pdf.js") == 0) { + return true; } - nsCOMPtr<nsIConsoleService> console - (do_GetService(NS_CONSOLESERVICE_CONTRACTID)); - if (console) - console->LogStringMessage(NS_ConvertUTF8toUTF16(msg).get()); - - // Log every canvas access attempt to stdout if debugging: -#ifdef DEBUG - printf("%s\n", msg.get()); -#endif - // Ensure URI is valid after logging, but before trying to notify the - // user: - NS_ENSURE_SUCCESS(rv, false); - - if (!isThirdParty) { - // Send notification so that a prompt is displayed. - nsCOMPtr<nsIObserverService> obs = - mozilla::services::GetObserverService(); - obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT, - NS_ConvertUTF8toUTF16(firstPartySpec).get()); + } + + // Load Third Party Util service. + nsresult rv; + nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = + do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, false); + + // Get the First Party URI and its spec. + nsCOMPtr<nsIURI> firstPartyURI; + rv = thirdPartyUtil->GetFirstPartyURI(NULL, aDocument, + getter_AddRefs(firstPartyURI)); + NS_ENSURE_SUCCESS(rv, false); + nsCString firstPartySpec; + firstPartyURI->GetSpec(firstPartySpec); + + // Block all third-party attempts to extract canvas. + bool isThirdParty = true; + rv = thirdPartyUtil->IsThirdPartyURI(firstPartyURI, docURI, &isThirdParty); + NS_ENSURE_SUCCESS(rv, false); + if (isThirdParty) { + nsAutoCString message; + message.AppendPrintf("Blocked third party %s in page %s from extracting canvas data.", + docURISpec.get(), firstPartySpec.get()); + if (isScriptKnown) { + message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine); } - } + nsContentUtils::LogMessageToConsole(message.get()); + return false; + } + + // Load Permission Manager service. + nsCOMPtr<nsIPermissionManager> permissionManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + NS_ENSURE_SUCCESS(rv, false); + + // Check if the site has permission to extract canvas data. + // Either permit or block extraction if a stored permission setting exists. + uint32_t permission; + rv = permissionManager->TestPermission(firstPartyURI, + PERMISSION_CANVAS_EXTRACT_DATA, &permission); + NS_ENSURE_SUCCESS(rv, false); + if (permission == nsIPermissionManager::ALLOW_ACTION) { + return true; + } else if (permission == nsIPermissionManager::DENY_ACTION) { + return false; } - }
- return isAllowed; + // At this point, permission is unknown (nsIPermissionManager::UNKNOWN_ACTION). + nsAutoCString message; + message.AppendPrintf("Blocked %s in page %s from extracting canvas data.", + docURISpec.get(), firstPartySpec.get()); + if (isScriptKnown) { + message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine); + } + nsContentUtils::LogMessageToConsole(message.get()); + + // Prompt the user (asynchronous). + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT, + NS_ConvertUTF8toUTF16(firstPartySpec).get()); + + // We don't extract the image for now -- user may override at prompt. + return false; }
void
tbb-commits@lists.torproject.org