[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [torbrowser/master] add stable firefox patches for alpha bundles



commit 8ff89c09c4856a91cb2787af97c214bbaefe1cc7
Author: Erinn Clark <erinn@xxxxxxxxxxxxxx>
Date:   Wed Oct 24 16:32:39 2012 +0100

    add stable firefox patches for alpha bundles
---
 ...nents.interfaces-lookupMethod-from-conten.patch |   50 ++
 ...0002-Make-Permissions-Manager-memory-only.patch |   94 ++++
 ...-Make-Intermediate-Cert-Store-memory-only.patch |   43 ++
 .../firefox/0004-Add-a-string-based-cacheKey.patch |   85 +++
 .../0005-Block-all-plugins-except-flash.patch      |   85 +++
 ...ontent-pref-service-memory-only-clearable.patch |   37 ++
 ...owser-exit-when-not-launched-from-Vidalia.patch |   46 ++
 .../0008-Disable-SSL-Session-ID-tracking.patch     |   28 +
 ...observer-event-to-close-persistent-connec.patch |   40 ++
 ...ice-and-system-specific-CSS-Media-Queries.patch |  154 ++++++
 ...11-Limit-the-number-of-fonts-per-document.patch |  228 ++++++++
 .../0012-Rebrand-Firefox-to-TorBrowser.patch       |   50 ++
 .../0013-Make-Download-manager-memory-only.patch   |   57 ++
 .../0014-Add-DDG-and-StartPage-to-Omnibox.patch    |   84 +++
 ...-nsICacheService.EvictEntries-synchronous.patch |   44 ++
 .../firefox/0016-Prevent-WebSocket-DNS-leak.patch  |  132 +++++
 ...ize-HTTP-request-order-and-pipeline-depth.patch |  251 +++++++++
 ...th-headers-before-the-modify-request-obse.patch |   52 ++
 ...Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch |  532 +++++++++++++++++++
 ...d-mozIThirdPartyUtil.getFirstPartyURI-API.patch |   31 +-
 .../0021-Add-canvas-image-extraction-prompt.patch  |  551 ++++++++++++++++++++
 ...nt-window-coordinates-for-mouse-event-scr.patch |   43 ++
 ...se-physical-screen-info.-via-window-and-w.patch |  312 +++++++++++
 ...not-expose-system-colors-to-CSS-or-canvas.patch |  537 +++++++++++++++++++
 24 files changed, 3554 insertions(+), 12 deletions(-)

diff --git a/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch b/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch
new file mode 100644
index 0000000..1a82800
--- /dev/null
+++ b/src/current-patches/firefox/0001-Block-Components.interfaces-lookupMethod-from-conten.patch
@@ -0,0 +1,50 @@
+From 1c2ccbea73720db5405602e4033c69b706068a8b Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 1 Feb 2012 15:40:40 -0800
+Subject: [PATCH 01/24] Block Components.interfaces,lookupMethod from content
+
+This patch removes the ability of content script to access
+Components.interfaces.* as well as call or access Components.lookupMethod.
+
+These two interfaces seem to be exposed to content script only to make our
+lives difficult. Components.lookupMethod can undo our JS hooks, and
+Components.interfaces is useful for fingerprinting the platform, OS, and
+Firebox version.
+
+They appear to have no other legitimate use. See also:
+https://bugzilla.mozilla.org/show_bug.cgi?id=429070
+https://trac.torproject.org/projects/tor/ticket/2873
+https://trac.torproject.org/projects/tor/ticket/2874
+---
+ js/xpconnect/src/XPCComponents.cpp |    8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
+index 38bfe08..7224b9b 100644
+--- a/js/xpconnect/src/XPCComponents.cpp
++++ b/js/xpconnect/src/XPCComponents.cpp
+@@ -4502,7 +4502,9 @@ nsXPCComponents::CanCreateWrapper(const nsIID * iid, char **_retval)
+ NS_IMETHODIMP
+ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
+ {
+-    static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++    // XXX: Pref observer? Also, is this what we want? Seems like a plan
++    //static const char* allowed[] = { "isSuccessCode", "lookupMethod", nsnull };
++    static const char* allowed[] = { "isSuccessCode", nsnull };
+     *_retval = xpc_CheckAccessList(methodName, allowed);
+     return NS_OK;
+ }
+@@ -4511,7 +4513,9 @@ nsXPCComponents::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, c
+ NS_IMETHODIMP
+ nsXPCComponents::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
+ {
+-    static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++    // XXX: Pref observer? Also, is this what we want? Seems like a plan
++    //    static const char* allowed[] = { "interfaces", "interfacesByID", "results", nsnull};
++    static const char* allowed[] = { "results", nsnull};
+     *_retval = xpc_CheckAccessList(propertyName, allowed);
+     return NS_OK;
+ }
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch b/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch
new file mode 100644
index 0000000..fa23d93
--- /dev/null
+++ b/src/current-patches/firefox/0002-Make-Permissions-Manager-memory-only.patch
@@ -0,0 +1,94 @@
+From cd983b1b57b1f4ae10c8deec5aa12ec957fdc855 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 1 Feb 2012 15:45:16 -0800
+Subject: [PATCH 02/24] Make Permissions Manager memory-only
+
+This patch exposes a pref 'permissions.memory_only' that properly isolates the
+permissions manager to memory, which is responsible for all user specified
+site permissions, as well as stored STS policy.
+
+The pref does successfully clear the permissions manager memory if toggled. It
+does not need to be set in prefs.js, and can be handled by Torbutton.
+
+https://trac.torproject.org/projects/tor/ticket/2950
+---
+ extensions/cookie/nsPermissionManager.cpp |   34 ++++++++++++++++++++++++++--
+ 1 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/extensions/cookie/nsPermissionManager.cpp b/extensions/cookie/nsPermissionManager.cpp
+index 67eb216..12cc7cf 100644
+--- a/extensions/cookie/nsPermissionManager.cpp
++++ b/extensions/cookie/nsPermissionManager.cpp
+@@ -58,6 +58,10 @@
+ #include "mozStorageHelper.h"
+ #include "mozStorageCID.h"
+ #include "nsXULAppAPI.h"
++#include "nsCOMPtr.h"
++#include "nsIPrefService.h"
++#include "nsIPrefBranch.h"
++#include "nsIPrefBranch2.h"
+ 
+ static nsPermissionManager *gPermissionManager = nsnull;
+ 
+@@ -203,6 +207,11 @@ nsPermissionManager::Init()
+     mObserverService->AddObserver(this, "profile-do-change", true);
+   }
+ 
++  nsCOMPtr<nsIPrefBranch2> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
++  if (pbi) {
++    pbi->AddObserver("permissions.", this, PR_FALSE);
++  }
++
+   if (IsChildProcess()) {
+     // Get the permissions from the parent process
+     InfallibleTArray<IPC::Permission> perms;
+@@ -251,8 +260,18 @@ nsPermissionManager::InitDB(bool aRemoveFile)
+   if (!storage)
+     return NS_ERROR_UNEXPECTED;
+ 
++  bool memory_db = false;
++  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
++  if (prefs) {
++    prefs->GetBoolPref("permissions.memory_only", &memory_db); 
++  }
++
+   // cache a connection to the hosts database
+-  rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++  if (memory_db) {
++    rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++  } else {
++    rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++  }
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   bool ready;
+@@ -262,7 +281,11 @@ nsPermissionManager::InitDB(bool aRemoveFile)
+     rv = permissionsFile->Remove(false);
+     NS_ENSURE_SUCCESS(rv, rv);
+ 
+-    rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++    if (memory_db) {
++      rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn));
++    } else {
++      rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
++    }
+     NS_ENSURE_SUCCESS(rv, rv);
+ 
+     mDBConn->GetConnectionReady(&ready);
+@@ -783,7 +806,12 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
+ {
+   ENSURE_NOT_CHILD_PROCESS;
+ 
+-  if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
++  if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
++    if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("permissions.memory_only").get())) {
++      // XXX: Should we remove the file? Probably not..
++      InitDB(PR_FALSE);
++    }
++  } else if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+     // The profile is about to change,
+     // or is going away because the application is shutting down.
+     if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch b/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch
new file mode 100644
index 0000000..b10fb85
--- /dev/null
+++ b/src/current-patches/firefox/0003-Make-Intermediate-Cert-Store-memory-only.patch
@@ -0,0 +1,43 @@
+From f100a7979e1a44863a8a67a09743f0e17b5dd14e Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Fri, 19 Aug 2011 17:58:23 -0700
+Subject: [PATCH 03/24] Make Intermediate Cert Store memory-only.
+
+This patch makes the intermediate SSL cert store exist in memory only.
+
+The pref must be set before startup in prefs.js.
+https://trac.torproject.org/projects/tor/ticket/2949
+---
+ security/manager/ssl/src/nsNSSComponent.cpp |   15 ++++++++++++++-
+ 1 files changed, 14 insertions(+), 1 deletions(-)
+
+diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
+index a08c4ef..0ec3713 100644
+--- a/security/manager/ssl/src/nsNSSComponent.cpp
++++ b/security/manager/ssl/src/nsNSSComponent.cpp
+@@ -1730,8 +1730,21 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
+     // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
+     // "/usr/lib/nss/libnssckbi.so".
+     PRUint32 init_flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
+-    SECStatus init_rv = ::NSS_Initialize(profileStr.get(), "", "",
++    bool nocertdb = false;
++    mPrefBranch->GetBoolPref("security.nocertdb", &nocertdb);
++
++    // XXX: We can also do the the following to only disable the certdb.
++    // Leaving this codepath in as a fallback in case InitNODB fails
++    if (nocertdb)
++      init_flags |= NSS_INIT_NOCERTDB;
++
++    SECStatus init_rv;
++    if (nocertdb) {
++        init_rv = ::NSS_NoDB_Init(NULL);
++    } else {
++        init_rv = ::NSS_Initialize(profileStr.get(), "", "",
+                                          SECMOD_DB, init_flags);
++    }
+ 
+     if (init_rv != SECSuccess) {
+       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch b/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch
new file mode 100644
index 0000000..f3afa97
--- /dev/null
+++ b/src/current-patches/firefox/0004-Add-a-string-based-cacheKey.patch
@@ -0,0 +1,85 @@
+From d674d09bc233d200b1ebc47f8e6ac4ebd6e4225a Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Fri, 2 Sep 2011 20:47:02 -0700
+Subject: [PATCH 04/24] Add a string-based cacheKey.
+
+Used for isolating cache according to same-origin policy.
+---
+ netwerk/base/public/nsICachingChannel.idl |    7 +++++++
+ netwerk/protocol/http/nsHttpChannel.cpp   |   22 ++++++++++++++++++++++
+ netwerk/protocol/http/nsHttpChannel.h     |    1 +
+ 3 files changed, 30 insertions(+), 0 deletions(-)
+
+diff --git a/netwerk/base/public/nsICachingChannel.idl b/netwerk/base/public/nsICachingChannel.idl
+index 2da46d6..4ee5774 100644
+--- a/netwerk/base/public/nsICachingChannel.idl
++++ b/netwerk/base/public/nsICachingChannel.idl
+@@ -98,6 +98,13 @@ interface nsICachingChannel : nsICacheInfoChannel
+     attribute nsISupports cacheKey;
+ 
+     /**
++     * Set/get the cache domain... uniquely identifies the data in the cache
++     * for this channel.  Holding a reference to this key does NOT prevent
++     * the cached data from being removed.
++     */
++    attribute AUTF8String cacheDomain;
++
++    /**
+      * Specifies whether or not the data should be cached to a file.  This
+      * may fail if the disk cache is not present.  The value of this attribute
+      * is usually only settable during the processing of a channel's
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+index dec2a83..97bd84c 100644
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -2392,6 +2392,12 @@ nsHttpChannel::AssembleCacheKey(const char *spec, PRUint32 postID,
+         cacheKey.Append(buf);
+     }
+ 
++    if (strlen(mCacheDomain.get()) > 0) {
++        cacheKey.AppendLiteral("domain=");
++        cacheKey.Append(mCacheDomain.get());
++        cacheKey.AppendLiteral("&");
++    }
++
+     if (!cacheKey.IsEmpty()) {
+         cacheKey.AppendLiteral("uri=");
+     }
+@@ -4695,6 +4701,22 @@ nsHttpChannel::SetCacheForOfflineUse(bool value)
+ }
+ 
+ NS_IMETHODIMP
++nsHttpChannel::GetCacheDomain(nsACString &value)
++{
++    value = mCacheDomain;
++
++    return NS_OK;
++}
++
++NS_IMETHODIMP
++nsHttpChannel::SetCacheDomain(const nsACString &value)
++{
++    mCacheDomain = value;
++
++    return NS_OK;
++}
++
++NS_IMETHODIMP
+ nsHttpChannel::GetOfflineCacheClientID(nsACString &value)
+ {
+     value = mOfflineCacheClientID;
+diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
+index 88ce469..53538cf 100644
+--- a/netwerk/protocol/http/nsHttpChannel.h
++++ b/netwerk/protocol/http/nsHttpChannel.h
+@@ -303,6 +303,7 @@ private:
+     nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
+     nsCacheAccessMode                 mOfflineCacheAccess;
+     nsCString                         mOfflineCacheClientID;
++    nsCString                         mCacheDomain;
+ 
+     // auth specific data
+     nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider;
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch b/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch
new file mode 100644
index 0000000..e7a831e
--- /dev/null
+++ b/src/current-patches/firefox/0005-Block-all-plugins-except-flash.patch
@@ -0,0 +1,85 @@
+From 88a390822d232ba037de1f15091977ca7e1064bf Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 1 Feb 2012 15:50:15 -0800
+Subject: [PATCH 05/24] Block all plugins except flash.
+
+We cannot use the @mozilla.org/extensions/blocklist;1 service, because we
+actually want to stop plugins from ever entering the browser's process space
+and/or executing code (for example, AV plugins that collect statistics/analyse
+urls, magical toolbars that phone home or "help" the user, skype buttons that
+ruin our day, and censorship filters). Hence we rolled our own.
+
+See https://trac.torproject.org/projects/tor/ticket/3547#comment:6 for musings
+on a better way. Until then, it is delta-darwinism for us.
+---
+ dom/plugins/base/nsPluginHost.cpp |   33 +++++++++++++++++++++++++++++++++
+ dom/plugins/base/nsPluginHost.h   |    2 ++
+ 2 files changed, 35 insertions(+), 0 deletions(-)
+
+diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
+index 992bcd4..f56f231 100644
+--- a/dom/plugins/base/nsPluginHost.cpp
++++ b/dom/plugins/base/nsPluginHost.cpp
+@@ -1968,6 +1968,35 @@ bool nsPluginHost::IsDuplicatePlugin(nsPluginTag * aPluginTag)
+   return false;
+ }
+ 
++PRBool nsPluginHost::GhettoBlacklist(nsIFile *pluginFile)
++{
++    nsCString leaf;
++    const char *leafStr;
++    nsresult rv;
++    
++    rv = pluginFile->GetNativeLeafName(leaf);
++    if (NS_FAILED(rv)) {
++        return PR_TRUE; // fuck 'em. blacklist.
++    }
++
++    leafStr = leaf.get();
++
++    if (!leafStr) {
++        return PR_TRUE; // fuck 'em. blacklist.
++    }
++
++    // libgnashplugin.so, libflashplayer.so, Flash Player-10.4-10.5.plugin,
++    // NPSWF32.dll, NPSWF64.dll
++    if (strstr(leafStr, "libgnashplugin") == leafStr ||
++        strstr(leafStr, "libflashplayer") == leafStr ||
++        strstr(leafStr, "Flash Player") == leafStr ||
++        strstr(leafStr, "NPSWF") == leafStr) {
++        return PR_FALSE;
++    }
++
++    return PR_TRUE; // fuck 'em. blacklist.
++}
++
+ typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
+ 
+ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
+@@ -2101,6 +2130,10 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
+       continue;
+     }
+ 
++    if (GhettoBlacklist(localfile)) {
++        continue;
++    }
++
+     // if it is not found in cache info list or has been changed, create a new one
+     if (!pluginTag) {
+       nsPluginFile pluginFile(localfile);
+diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h
+index 39a8891..c262abf 100644
+--- a/dom/plugins/base/nsPluginHost.h
++++ b/dom/plugins/base/nsPluginHost.h
+@@ -278,6 +278,8 @@ private:
+   // Loads all cached plugins info into mCachedPlugins
+   nsresult ReadPluginInfo();
+ 
++  PRBool GhettoBlacklist(nsIFile *pluginFile);
++
+   // Given a file path, returns the plugins info from our cache
+   // and removes it from the cache.
+   void RemoveCachedPluginsInfo(const char *filePath,
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch b/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch
new file mode 100644
index 0000000..17af793
--- /dev/null
+++ b/src/current-patches/firefox/0006-Make-content-pref-service-memory-only-clearable.patch
@@ -0,0 +1,37 @@
+From 71ba98d81a6ecada62af4d2ee03be050d371d996 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Thu, 8 Sep 2011 08:40:17 -0700
+Subject: [PATCH 06/24] Make content pref service memory-only + clearable
+
+This prevents random urls from being inserted into content-prefs.sqllite in
+the profile directory as content prefs change (includes site-zoom and perhaps
+other site prefs?).
+---
+ .../contentprefs/nsContentPrefService.js           |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/toolkit/components/contentprefs/nsContentPrefService.js b/toolkit/components/contentprefs/nsContentPrefService.js
+index adfb650..1619d5f 100644
+--- a/toolkit/components/contentprefs/nsContentPrefService.js
++++ b/toolkit/components/contentprefs/nsContentPrefService.js
+@@ -1240,7 +1240,7 @@ ContentPrefService.prototype = {
+ 
+     var dbConnection;
+ 
+-    if (!dbFile.exists())
++    if (true || !dbFile.exists())
+       dbConnection = this._dbCreate(dbService, dbFile);
+     else {
+       try {
+@@ -1288,7 +1288,7 @@ ContentPrefService.prototype = {
+   },
+ 
+   _dbCreate: function ContentPrefService__dbCreate(aDBService, aDBFile) {
+-    var dbConnection = aDBService.openDatabase(aDBFile);
++    var dbConnection = aDBService.openSpecialDatabase("memory");
+ 
+     try {
+       this._dbCreateSchema(dbConnection);
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch b/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch
new file mode 100644
index 0000000..cc496d3
--- /dev/null
+++ b/src/current-patches/firefox/0007-Make-Tor-Browser-exit-when-not-launched-from-Vidalia.patch
@@ -0,0 +1,46 @@
+From 12579def59d67416b841f6b0a6eadfd94bba72e9 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Sun, 9 Oct 2011 22:50:07 -0700
+Subject: [PATCH 07/24] Make Tor Browser exit when not launched from Vidalia
+
+Turns out the Windows 7 UI encourages users to "dock" their Tor Browser app
+for easy relaunch. If they manage to do this, we should fail closed rather
+than opened. Hopefully they will get the hint and dock Vidalia instead.
+
+This is an emergency fix for
+https://trac.torproject.org/projects/tor/ticket/4192. We can do a better
+localized fix w/ a translated alert menu later, if it seems like this might
+actually be common.
+---
+ browser/base/content/browser.js |   15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
+index f16a0c5..20e3666 100644
+--- a/browser/base/content/browser.js
++++ b/browser/base/content/browser.js
+@@ -1217,6 +1217,21 @@ function BrowserStartup() {
+ 
+   prepareForStartup();
+ 
++  // If this is not a TBB profile, exit. 
++  // Solves https://trac.torproject.org/projects/tor/ticket/4192
++  var foundPref = false;
++  try {
++    foundPref = gPrefService.prefHasUserValue("torbrowser.version");
++  } catch(e) {
++    //dump("No pref: "+e);
++  }
++  if(!foundPref) {
++    var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
++                         .getService(Components.interfaces.nsIAppStartup);
++    appStartup.quit(3); // Force all windows to close, and then quit.
++  }
++
++
+   if (uriToLoad && !isLoadingBlank) {
+     if (uriToLoad instanceof Ci.nsISupportsArray) {
+       let count = uriToLoad.Count();
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch b/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch
new file mode 100644
index 0000000..39e1483
--- /dev/null
+++ b/src/current-patches/firefox/0008-Disable-SSL-Session-ID-tracking.patch
@@ -0,0 +1,28 @@
+From 7586e413761858ce705d25d4a1673e608a162bed Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Wed, 7 Dec 2011 19:36:38 -0800
+Subject: [PATCH 08/24] Disable SSL Session ID tracking.
+
+We can't easily bind SSL Session ID tracking to url bar domain,
+so we have to disable them to satisfy
+https://www.torproject.org/projects/torbrowser/design/#identifier-linkability.
+---
+ security/nss/lib/ssl/sslsock.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
+index 0c4d0c7..8d23fc0 100644
+--- a/security/nss/lib/ssl/sslsock.c
++++ b/security/nss/lib/ssl/sslsock.c
+@@ -173,7 +173,7 @@ static sslOptions ssl_defaults = {
+     PR_FALSE,	/* enableSSL2         */ /* now defaults to off in NSS 3.13 */
+     PR_TRUE,	/* enableSSL3         */
+     PR_TRUE, 	/* enableTLS          */ /* now defaults to on in NSS 3.0 */
+-    PR_FALSE,	/* noCache            */
++    PR_TRUE,	/* noCache            */
+     PR_FALSE,	/* fdx                */
+     PR_FALSE,	/* v2CompatibleHello  */ /* now defaults to off in NSS 3.13 */
+     PR_TRUE,	/* detectRollBack     */
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch b/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch
new file mode 100644
index 0000000..e693c71
--- /dev/null
+++ b/src/current-patches/firefox/0009-Provide-an-observer-event-to-close-persistent-connec.patch
@@ -0,0 +1,40 @@
+From 9c6f997dd9a44336af9a1db17f5b680cc80a0e6c Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 1 Feb 2012 15:53:28 -0800
+Subject: [PATCH 09/24] Provide an observer event to close persistent
+ connections
+
+We need to prevent linkability across "New Identity", which includes closing
+keep-alive connections.
+---
+ netwerk/protocol/http/nsHttpHandler.cpp |    7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
+index 281d6ff..8125681 100644
+--- a/netwerk/protocol/http/nsHttpHandler.cpp
++++ b/netwerk/protocol/http/nsHttpHandler.cpp
+@@ -325,6 +325,7 @@ nsHttpHandler::Init()
+         mObserverService->AddObserver(this, "net:clear-active-logins", true);
+         mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
+         mObserverService->AddObserver(this, "net:prune-dead-connections", true);
++        mObserverService->AddObserver(this, "net:prune-all-connections", PR_TRUE);
+     }
+  
+     return NS_OK;
+@@ -1504,6 +1505,12 @@ nsHttpHandler::Observe(nsISupports *subject,
+             mConnMgr->PruneDeadConnections();
+         }
+     }
++    else if (strcmp(topic, "net:prune-all-connections") == 0) {
++        if (mConnMgr) {
++           mConnMgr->ClosePersistentConnections();
++           mConnMgr->PruneDeadConnections();
++        }
++    }
+   
+     return NS_OK;
+ }
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch b/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch
new file mode 100644
index 0000000..14e584c
--- /dev/null
+++ b/src/current-patches/firefox/0010-Limit-device-and-system-specific-CSS-Media-Queries.patch
@@ -0,0 +1,154 @@
+From 8f97f2f36adb9e4416f3d19af10880c800c846c2 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade@xxxxxxxxxxxxxxxxx>
+Date: Thu, 4 Oct 2012 14:28:48 -0400
+Subject: [PATCH 10/24] Limit device and system specific CSS Media Queries.
+
+---
+ layout/style/nsMediaFeatures.cpp |   71 ++++++++++++++++++++++++-------------
+ 1 files changed, 46 insertions(+), 25 deletions(-)
+
+diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp
+index 6eca06e..5b1df7e 100644
+--- a/layout/style/nsMediaFeatures.cpp
++++ b/layout/style/nsMediaFeatures.cpp
+@@ -130,6 +130,9 @@ GetDeviceContextFor(nsPresContext* aPresContext)
+ static nsSize
+ GetDeviceSize(nsPresContext* aPresContext)
+ {
++  if (!aPresContext->IsChrome()) {
++    return GetSize(aPresContext);
++  } else {
+     nsSize size;
+     if (aPresContext->IsRootPaginatedDocument())
+         // We want the page size, including unprintable areas and margins.
+@@ -140,6 +143,7 @@ GetDeviceSize(nsPresContext* aPresContext)
+         GetDeviceContextFor(aPresContext)->
+             GetDeviceSurfaceDimensions(size.width, size.height);
+     return size;
++  }
+ }
+ 
+ static nsresult
+@@ -183,17 +187,17 @@ static nsresult
+ GetDeviceOrientation(nsPresContext* aPresContext, const nsMediaFeature*,
+                      nsCSSValue& aResult)
+ {
+-    nsSize size = GetDeviceSize(aPresContext);
+-    PRInt32 orientation;
+-    if (size.width > size.height) {
+-        orientation = NS_STYLE_ORIENTATION_LANDSCAPE;
+-    } else {
+-        // Per spec, square viewports should be 'portrait'
+-        orientation = NS_STYLE_ORIENTATION_PORTRAIT;
+-    }
+-
+-    aResult.SetIntValue(orientation, eCSSUnit_Enumerated);
+-    return NS_OK;
++  nsSize size = GetDeviceSize(aPresContext);
++  PRInt32 orientation;
++  if (size.width > size.height) {
++      orientation = NS_STYLE_ORIENTATION_LANDSCAPE;
++  } else {
++      // Per spec, square viewports should be 'portrait'
++      orientation = NS_STYLE_ORIENTATION_PORTRAIT;
++  }
++
++  aResult.SetIntValue(orientation, eCSSUnit_Enumerated);
++  return NS_OK;
+ }
+ 
+ static nsresult
+@@ -236,13 +240,17 @@ static nsresult
+ GetColor(nsPresContext* aPresContext, const nsMediaFeature*,
+          nsCSSValue& aResult)
+ {
+-    // FIXME:  This implementation is bogus.  nsDeviceContext
+-    // doesn't provide reliable information (should be fixed in bug
+-    // 424386).
+-    // FIXME: On a monochrome device, return 0!
+-    nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
+-    PRUint32 depth;
+-    dx->GetDepth(depth);
++    PRUint32 depth = 24; // Always return 24 to non-chrome callers.
++
++    if (aPresContext->IsChrome()) {
++        // FIXME:  This implementation is bogus.  nsDeviceContext
++        // doesn't provide reliable information (should be fixed in bug
++        // 424386).
++        // FIXME: On a monochrome device, return 0!
++        nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
++        dx->GetDepth(depth);
++    }
++
+     // The spec says to use bits *per color component*, so divide by 3,
+     // and round down, since the spec says to use the smallest when the
+     // color components differ.
+@@ -280,9 +288,14 @@ static nsresult
+ GetResolution(nsPresContext* aPresContext, const nsMediaFeature*,
+               nsCSSValue& aResult)
+ {
+-    // Resolution values are in device pixels, not CSS pixels.
+-    nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
+-    float dpi = float(dx->AppUnitsPerPhysicalInch()) / float(dx->AppUnitsPerDevPixel());
++    float dpi = 96; // Always return 96 to non-chrome callers.
++
++    if (aPresContext->IsChrome()) {
++      // Resolution values are in device pixels, not CSS pixels.
++      nsDeviceContext *dx = GetDeviceContextFor(aPresContext);
++      dpi = float(dx->AppUnitsPerPhysicalInch()) / float(dx->AppUnitsPerDevPixel());
++    }
++
+     aResult.SetFloatValue(dpi, eCSSUnit_Inch);
+     return NS_OK;
+ }
+@@ -311,8 +324,12 @@ static nsresult
+ GetDevicePixelRatio(nsPresContext* aPresContext, const nsMediaFeature*,
+                     nsCSSValue& aResult)
+ {
+-  float ratio = aPresContext->CSSPixelsToDevPixels(1.0f);
+-  aResult.SetFloatValue(ratio, eCSSUnit_Number);
++  if (aPresContext->IsChrome()) {
++    float ratio = aPresContext->CSSPixelsToDevPixels(1.0f);
++    aResult.SetFloatValue(ratio, eCSSUnit_Number);
++  } else {
++    aResult.SetFloatValue(1.0, eCSSUnit_Number);
++  }
+   return NS_OK;
+ }
+ 
+@@ -320,18 +337,21 @@ static nsresult
+ GetSystemMetric(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
+                 nsCSSValue& aResult)
+ {
++  if (aPresContext->IsChrome()) {
+     NS_ABORT_IF_FALSE(aFeature->mValueType == nsMediaFeature::eBoolInteger,
+                       "unexpected type");
+     nsIAtom *metricAtom = *aFeature->mData.mMetric;
+     bool hasMetric = nsCSSRuleProcessor::HasSystemMetric(metricAtom);
+     aResult.SetIntValue(hasMetric ? 1 : 0, eCSSUnit_Integer);
+-    return NS_OK;
++  }
++  return NS_OK;
+ }
+ 
+ static nsresult
+ GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
+                 nsCSSValue& aResult)
+ {
++  if (aPresContext->IsChrome()) {
+     aResult.Reset();
+ #ifdef XP_WIN
+     PRUint8 windowsThemeId =
+@@ -350,7 +370,8 @@ GetWindowsTheme(nsPresContext* aPresContext, const nsMediaFeature* aFeature,
+         }
+     }
+ #endif
+-    return NS_OK;
++  }
++  return NS_OK;
+ }
+ 
+ /*
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch b/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch
new file mode 100644
index 0000000..ff9e618
--- /dev/null
+++ b/src/current-patches/firefox/0011-Limit-the-number-of-fonts-per-document.patch
@@ -0,0 +1,228 @@
+From cb3a6f45dd2c15d6b75084e1a4dded18ed638632 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 1 Feb 2012 16:01:21 -0800
+Subject: [PATCH 11/24] Limit the number of fonts per document.
+
+We create two prefs:
+browser.display.max_font_count and browser.display.max_font_attempts.
+max_font_count sets a limit on the number of fonts actually used in the
+document, and max_font_attempts sets a limit on the total number of CSS
+queries that a document is allowed to perform.
+
+Once either limit is reached, the browser behaves as if
+browser.display.use_document_fonts was set to 0 for subsequent font queries.
+
+If a pref is not set or is negative, that limit does not apply.
+
+This is done to address:
+https://www.torproject.org/projects/torbrowser/design/#fingerprinting-linkability
+---
+ layout/base/nsPresContext.cpp |  100 +++++++++++++++++++++++++++++++++++++++++
+ layout/base/nsPresContext.h   |    9 ++++
+ layout/style/nsRuleNode.cpp   |   13 ++++-
+ 3 files changed, 119 insertions(+), 3 deletions(-)
+
+diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
+index e1587db..9690d9c 100644
+--- a/layout/base/nsPresContext.cpp
++++ b/layout/base/nsPresContext.cpp
+@@ -98,6 +98,8 @@
+ #include "FrameLayerBuilder.h"
+ #include "nsDOMMediaQueryList.h"
+ #include "nsSMILAnimationController.h"
++#include "nsString.h"
++#include "nsUnicharUtils.h"
+ 
+ #ifdef IBMBIDI
+ #include "nsBidiPresUtils.h"
+@@ -706,6 +708,10 @@ nsPresContext::GetUserPreferences()
+   // * use fonts?
+   mUseDocumentFonts =
+     Preferences::GetInt("browser.display.use_document_fonts") != 0;
++  mMaxFonts =
++    Preferences::GetInt("browser.display.max_font_count", -1);
++  mMaxFontAttempts =
++    Preferences::GetInt("browser.display.max_font_attempts", -1);
+ 
+   // * replace backslashes with Yen signs? (bug 245770)
+   mEnableJapaneseTransform =
+@@ -1300,6 +1306,100 @@ nsPresContext::GetDefaultFont(PRUint8 aFontID) const
+   return font;
+ }
+ 
++PRBool
++nsPresContext::FontUseCountReached(const nsFont &font) {
++  if (mMaxFonts < 0) {
++    return PR_FALSE;
++  }
++
++  for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
++    if (mFontsUsed[i].name.Equals(font.name,
++                                  nsCaseInsensitiveStringComparator())
++        // XXX: Style is sometimes filled with garbage??
++        /*&& mFontsUsed[i].style == font.style*/) {
++      // seen it before: OK
++      return PR_FALSE;
++    }
++  }
++
++  if (mFontsUsed.Length() >= mMaxFonts) {
++    return PR_TRUE;
++  }
++
++  return PR_FALSE;
++}
++
++PRBool
++nsPresContext::FontAttemptCountReached(const nsFont &font) {
++  if (mMaxFontAttempts < 0) {
++    return PR_FALSE;
++  }
++
++  for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
++    if (mFontsTried[i].name.Equals(font.name,
++                                  nsCaseInsensitiveStringComparator())
++        // XXX: Style is sometimes filled with garbage??
++        /*&& mFontsTried[i].style == font.style*/) {
++      // seen it before: OK
++      return PR_FALSE;
++    }
++  }
++
++  if (mFontsTried.Length() >= mMaxFontAttempts) {
++    return PR_TRUE;
++  }
++
++  return PR_FALSE;
++}
++
++void
++nsPresContext::AddFontUse(const nsFont &font) {
++  if (mMaxFonts < 0) {
++    return;
++  }
++
++  for (PRUint32 i = 0; i < mFontsUsed.Length(); i++) {
++    if (mFontsUsed[i].name.Equals(font.name,
++                                  nsCaseInsensitiveStringComparator())
++        // XXX: Style is sometimes filled with garbage??
++        /*&& mFontsUsed[i].style == font.style*/) {
++      // seen it before: OK
++      return;
++    }
++  }
++
++  if (mFontsUsed.Length() >= mMaxFonts) {
++    return;
++  }
++   
++  mFontsUsed.AppendElement(font);
++  return;
++}
++
++void
++nsPresContext::AddFontAttempt(const nsFont &font) {
++  if (mMaxFontAttempts < 0) {
++    return;
++  }
++
++  for (PRUint32 i = 0; i < mFontsTried.Length(); i++) {
++    if (mFontsTried[i].name.Equals(font.name,
++                                  nsCaseInsensitiveStringComparator())
++        // XXX: Style is sometimes filled with garbage??
++        /*&& mFontsTried[i].style == font.style*/) {
++      // seen it before: OK
++      return;
++    }
++  }
++
++  if (mFontsTried.Length() >= mMaxFontAttempts) {
++    return;
++  }
++   
++  mFontsTried.AppendElement(font);
++  return;
++}
++
+ void
+ nsPresContext::SetFullZoom(float aZoom)
+ {
+diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h
+index ecd01d8..552a69a 100644
+--- a/layout/base/nsPresContext.h
++++ b/layout/base/nsPresContext.h
+@@ -548,6 +548,13 @@ public:
+     }
+   }
+ 
++  nsTArray<nsFont> mFontsUsed; // currently for font-count limiting only
++  nsTArray<nsFont> mFontsTried; // currently for font-count limiting only
++  void AddFontUse(const nsFont &font);
++  void AddFontAttempt(const nsFont &font);
++  PRBool FontUseCountReached(const nsFont &font);
++  PRBool FontAttemptCountReached(const nsFont &font);
++
+   PRInt32 MinFontSize() const {
+     return NS_MAX(mMinFontSize, mMinimumFontSizePref);
+   }
+@@ -1117,6 +1124,8 @@ protected:
+   PRUint32              mInterruptChecksToSkip;
+ 
+   mozilla::TimeStamp    mReflowStartTime;
++  PRInt32               mMaxFontAttempts;
++  PRInt32               mMaxFonts;
+ 
+   unsigned              mHasPendingInterrupt : 1;
+   unsigned              mInterruptsEnabled : 1;
+diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
+index 27336bf..827585a 100644
+--- a/layout/style/nsRuleNode.cpp
++++ b/layout/style/nsRuleNode.cpp
+@@ -3091,6 +3091,7 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+ 
+   // See if there is a minimum font-size constraint to honor
+   nscoord minimumFontSize = mPresContext->MinFontSize();
++  PRBool isXUL = PR_FALSE;
+ 
+   if (minimumFontSize < 0)
+     minimumFontSize = 0;
+@@ -3102,10 +3103,10 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+   // We only need to know this to determine if we have to use the
+   // document fonts (overriding the useDocumentFonts flag), or to
+   // determine if we have to override the minimum font-size constraint.
+-  if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
++  if (mPresContext->IsChrome()) {
+     // if we are not using document fonts, but this is a XUL document,
+     // then we use the document fonts anyway
+-    useDocumentFonts = true;
++    isXUL = PR_TRUE;
+     minimumFontSize = 0;
+   }
+ 
+@@ -3120,9 +3121,13 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+     // generic?
+     nsFont::GetGenericID(font->mFont.name, &generic);
+ 
++    mPresContext->AddFontAttempt(font->mFont);
++
+     // If we aren't allowed to use document fonts, then we are only entitled
+     // to use the user's default variable-width font and fixed-width font
+-    if (!useDocumentFonts) {
++    if (!isXUL && (!useDocumentFonts ||
++                    mPresContext->FontAttemptCountReached(font->mFont) ||
++                    mPresContext->FontUseCountReached(font->mFont))) {
+       // Extract the generic from the specified font family...
+       nsAutoString genericName;
+       if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
+@@ -3158,6 +3163,8 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
+                                minimumFontSize, font);
+   }
+ 
++  if (font->mGenericID == kGenericFont_NONE)
++    mPresContext->AddFontUse(font->mFont);
+   COMPUTE_END_INHERITED(Font, font)
+ }
+ 
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch b/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch
new file mode 100644
index 0000000..e627238
--- /dev/null
+++ b/src/current-patches/firefox/0012-Rebrand-Firefox-to-TorBrowser.patch
@@ -0,0 +1,50 @@
+From 5820fc300fe1cae27752673e8721a19e70bf727c Mon Sep 17 00:00:00 2001
+From: Erinn Clark <erinn@xxxxxxxxxxxxxx>
+Date: Wed, 25 Apr 2012 09:14:00 -0300
+Subject: [PATCH 12/24] Rebrand Firefox to TorBrowser
+
+This patch does some basic renaming of Firefox to TorBrowser. The rest of the
+branding is done by images and icons.
+---
+ browser/branding/official/configure.sh             |    2 +-
+ browser/branding/official/locales/en-US/brand.dtd  |    6 +++---
+ .../official/locales/en-US/brand.properties        |    6 +++---
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/browser/branding/official/configure.sh b/browser/branding/official/configure.sh
+index 4d3d297..e9b3738 100644
+--- a/browser/branding/official/configure.sh
++++ b/browser/branding/official/configure.sh
+@@ -1,2 +1,2 @@
+-MOZ_APP_DISPLAYNAME=Firefox
++MOZ_APP_DISPLAYNAME=TorBrowser
+ MOZ_UA_BUILDID=20100101
+diff --git a/browser/branding/official/locales/en-US/brand.dtd b/browser/branding/official/locales/en-US/brand.dtd
+index 142d79b..c137e04 100644
+--- a/browser/branding/official/locales/en-US/brand.dtd
++++ b/browser/branding/official/locales/en-US/brand.dtd
+@@ -1,4 +1,4 @@
+-<!ENTITY  brandShortName        "Firefox">
+-<!ENTITY  brandFullName         "Mozilla Firefox">
+-<!ENTITY  vendorShortName       "Mozilla">
++<!ENTITY  brandShortName        "TorBrowser">
++<!ENTITY  brandFullName         "Tor Browser">
++<!ENTITY  vendorShortName       "Tor Project">
+ <!ENTITY  trademarkInfo.part1   "Firefox and the Firefox logos are trademarks of the Mozilla Foundation.">
+diff --git a/browser/branding/official/locales/en-US/brand.properties b/browser/branding/official/locales/en-US/brand.properties
+index 5f3ad54..62ac2fd 100644
+--- a/browser/branding/official/locales/en-US/brand.properties
++++ b/browser/branding/official/locales/en-US/brand.properties
+@@ -1,6 +1,6 @@
+-brandShortName=Firefox
+-brandFullName=Mozilla Firefox
+-vendorShortName=Mozilla
++brandShortName=TorBrowser
++brandFullName=Tor Browser
++vendorShortName=Tor Project
+ 
+ homePageSingleStartMain=Firefox Start, a fast home page with built-in search
+ homePageImport=Import your home page from %S
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch b/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch
new file mode 100644
index 0000000..1ad0972
--- /dev/null
+++ b/src/current-patches/firefox/0013-Make-Download-manager-memory-only.patch
@@ -0,0 +1,57 @@
+From 28178fb406d86b317b13b16ade3b06e5e1500c7e Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 25 Apr 2012 13:39:35 -0700
+Subject: [PATCH 13/24] Make Download manager memory only.
+
+Solves https://trac.torproject.org/projects/tor/ticket/4017.
+
+Yes, this is an ugly hack. We *could* send the observer notification from
+Torbutton to tell the download manager to switch to memory, but then we have
+to dance around and tell it again if the user switches in and out of private
+browsing mode..
+
+The right way to do this is with a pref. Maybe I'll get to that someday, if
+this breaks enough times in conflict.
+---
+ toolkit/components/downloads/nsDownloadManager.cpp |    4 ++--
+ toolkit/components/downloads/nsDownloadManager.h   |    2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
+index 00a6e7d..2e83f61 100644
+--- a/toolkit/components/downloads/nsDownloadManager.cpp
++++ b/toolkit/components/downloads/nsDownloadManager.cpp
+@@ -1992,7 +1992,7 @@ nsDownloadManager::Observe(nsISupports *aSubject,
+     if (NS_LITERAL_STRING("memory").Equals(aData))
+       return SwitchDatabaseTypeTo(DATABASE_MEMORY);
+     else if (NS_LITERAL_STRING("disk").Equals(aData))
+-      return SwitchDatabaseTypeTo(DATABASE_DISK);
++      return SwitchDatabaseTypeTo(DATABASE_MEMORY);
+   }
+   else if (strcmp(aTopic, "alertclickcallback") == 0) {
+     nsCOMPtr<nsIDownloadManagerUI> dmui =
+@@ -2069,7 +2069,7 @@ nsDownloadManager::OnLeavePrivateBrowsingMode()
+   (void)ResumeAllDownloads(false);
+ 
+   // Switch back to the on-disk DB again
+-  (void)SwitchDatabaseTypeTo(DATABASE_DISK);
++  //(void)SwitchDatabaseTypeTo(DATABASE_DISK);
+ 
+   mInPrivateBrowsing = false;
+ }
+diff --git a/toolkit/components/downloads/nsDownloadManager.h b/toolkit/components/downloads/nsDownloadManager.h
+index 54312e4..cb63b52 100644
+--- a/toolkit/components/downloads/nsDownloadManager.h
++++ b/toolkit/components/downloads/nsDownloadManager.h
+@@ -90,7 +90,7 @@ public:
+ 
+   virtual ~nsDownloadManager();
+   nsDownloadManager() :
+-      mDBType(DATABASE_DISK)
++      mDBType(DATABASE_MEMORY)
+     , mInPrivateBrowsing(false)
+ #ifdef DOWNLOAD_SCANNER
+     , mScanner(nsnull)
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch b/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch
new file mode 100644
index 0000000..adbd3d4
--- /dev/null
+++ b/src/current-patches/firefox/0014-Add-DDG-and-StartPage-to-Omnibox.patch
@@ -0,0 +1,84 @@
+From 2a80e84755c97cf4ff3ab63bda1bd5f0936d9594 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 25 Apr 2012 15:03:46 -0700
+Subject: [PATCH 14/24] Add DDG and StartPage to Omnibox.
+
+You mean there are search engines that don't require captchas if you don't
+have a cookie? Holy crap. Get those in there now.
+---
+ browser/locales/en-US/searchplugins/duckduckgo.xml |   29 ++++++++++++++++++++
+ browser/locales/en-US/searchplugins/list.txt       |    2 +
+ browser/locales/en-US/searchplugins/startpage.xml  |   11 +++++++
+ 3 files changed, 42 insertions(+), 0 deletions(-)
+ create mode 100644 browser/locales/en-US/searchplugins/duckduckgo.xml
+ create mode 100644 browser/locales/en-US/searchplugins/startpage.xml
+
+diff --git a/browser/locales/en-US/searchplugins/duckduckgo.xml b/browser/locales/en-US/searchplugins/duckduckgo.xml
+new file mode 100644
+index 0000000..4f00b4d
+--- /dev/null
++++ b/browser/locales/en-US/searchplugins/duckduckgo.xml
+@@ -0,0 +1,29 @@
++<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/";>
++<ShortName>DuckDuckGo</ShortName>
++<Description>Duck Duck Go</Description>
++<InputEncoding>UTF-8</InputEncoding>
++<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAANcNAADXDQAAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAAJyDsJmlk8pf6+v3s/v7+++zr/fcnIOyzJyDsgCcg7CYAAAAA
++AAAAAAAAAAAAAAAAAAAAAAAAAAAnIOwBJyDscCcg7PZttJ7/7Pfs//////++xO7/S5GA/ycg7P8n
++IOz2JyDscCcg7AEAAAAAAAAAAAAAAAAnIOwBJyDstScg7P8nIOz/Y8p5/2fHZf9Yv0z/YcF2/1rB
++Uv8nIOz/JyDs/ycg7P8nIOy1JyDsAQAAAAAAAAAAJyDscCcg7P8nIOz/JyDs/4jQoP/p9+n/////
++/05X3v9LkYD/JyDs/ycg7P8nIOz/JyDs/ycg7HAAAAAAJyDsJicg7PYnIOz/JyDs/zUu7f/+/v//
++//////////89N+7/JyDs/yUo7f8nIOz/JyDs/ycg7P8nIOz2JyDsJicg7IAnIOz/JyDs/ycg7P9h
++XPH////////////t/P//GIr2/wfD+/8Gyfz/DKv5/yM57/8nIOz/JyDs/ycg7H8nIOyzJyDs/ycg
++7P8nIOz/jov1////////////Otz9/w3G/P8cWfH/JSvt/ycg7P8nIOz/JyDs/ycg7P8nIOyzJyDs
++5icg7P8nIOz/JyDs/7u5+f///////////27l/v8E0v3/BNL9/wTQ/f8Oofn/IT7v/ycg7P8nIOz/
++JyDs5icg7OYnIOz/JyDs/ycg7P/p6P3/uWsC////////////5fr//6Po/f8Thfb/DKv5/w6f+f8n IOz/JyDs/ycg7OYnIOyzJyDs/ycg7P8nIOz/9/b+/////////////////7lrAv/V1Pv/JyDs/ycg
++7P8nIOz/JyDs/ycg7P8nIOyzJyDsgCcg7P8nIOz/JyDs/8/N+///////////////////////iIX1
++/ycg7P8nIOz/JyDs/ycg7P8nIOz/JyDsfycg7CYnIOz2JyDs/ycg7P9FP+7/q6n4/+7u/f/n5v3/
++fXn0/yoj7P8nIOz/JyDs/ycg7P8nIOz/JyDs9icg7CYAAAAAJyDscCcg7P8nIOz/wsD6/+no/f/Y
++1/z/eHTz/ycg7P8nIOz/JyDs/ycg7P8nIOz/JyDs/ycg7HAAAAAAAAAAACcg7AEnIOy1JyDs/ycg
++7P8nIOz/JyDs/ycg7P8nIOz/JyDs/ycg7P8nIOz/JyDs/ycg7LUnIOwBAAAAAAAAAAAAAAAAJyDs
++AScg7HAnIOz2JyDs/ycg7P8nIOz/JyDs/ycg7P8nIOz/JyDs9icg7HAnIOwBAAAAAAAAAAAAAAAA
++AAAAAAAAAAAAAAAAJyDsJicg7IAnIOyzJyDs5icg7OYnIOyzJyDsgCcg7CYAAAAAAAAAAAAAAAAA
++AAAA+B8AAPAPAADAAwAAwAMAAIABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAACAAQAAwAMAAMAD
++AADwDwAA+B8AAA==</Image>
++<Url type="text/html" method="POST" template="https://duckduckgo.com/html/";>
++  <Param name="q" value="{searchTerms}"/>
++</Url>
++<SearchForm>https://duckduckgo.com/html/</SearchForm>
++</SearchPlugin>
+diff --git a/browser/locales/en-US/searchplugins/list.txt b/browser/locales/en-US/searchplugins/list.txt
+index 2a1141a..0466f4e 100644
+--- a/browser/locales/en-US/searchplugins/list.txt
++++ b/browser/locales/en-US/searchplugins/list.txt
+@@ -1,7 +1,9 @@
+ amazondotcom
+ bing
++duckduckgo
+ eBay
+ google
++startpage
+ twitter
+ wikipedia
+ yahoo
+diff --git a/browser/locales/en-US/searchplugins/startpage.xml b/browser/locales/en-US/searchplugins/startpage.xml
+new file mode 100644
+index 0000000..1a310b1
+--- /dev/null
++++ b/browser/locales/en-US/searchplugins/startpage.xml
+@@ -0,0 +1,11 @@
++<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/";>
++<ShortName>Startpage</ShortName>
++<Description>Start Page</Description>
++<InputEncoding>UTF-8</InputEncoding>
++<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2jkj+9YtD/vWLQ/71i0P+9otD/vaLRP72i0T+9YtE/vWLRP72i0T+9otD/vaNRP72jUT+9otF/vaLRf73kkv+9Yc///WJP//1iT//9Yk///rAmf/94Mz/+sCa//aRTv/1iUH/9ok///aJP//2i0H/9otB//aJQv/2iUL/9otC//aNRP/2jUT/9o1E//aNRP/6wpv////////////96dr/95dQ//aNRP/2kET/9pBG//aQRv/2kEb/9pBG//aRR//3lEz/95BH//mueP/7xJ3/959g//efYf/4p23//vDm//3p2//3kEr/95FJ//aRSf/niFH/95FK//aRSv/2mE//95hS/vq4iP/////////////////81bj/95xZ//q4iP//////+bF+//eZT//njFT/PSqi/2xGjv/2mVD/951V/vedVv783cX///////vQrf/++PP///////748//+8uj///////m3gf/olFr/PSuj/w8Pt/9sSJD/951V//eeWf73oVv++8ul///////5sXf/+KRi//vRsf////////////3r3v/olF//Piyk/w8Pt/9sSJH/+J5Z//ieWv/3oV/++KZf/vihXP/97N7//vn0//zTs//6wJP/+bBy//q6iP/onW//Piyl/w8Pt/8fGbH/m2iB/+icY//4pGD/96hl/viqZf74pmD/+Kxr//3iy/////////n1//ivbP/onGj/Pi2m/w8Pt/8uJKz/fFeQ/x8Zsf8+Lqb/6J9r//ivbP74rm3++Klm//mpZv/5q2f/+bR9//m0e//poW7/Pi6n/w8Pt/9sTZj/+Ktp//ira/+rd4P/Dw+3/4xijv/5snH+
 +LN1/vmvbf/5r23/+a5t//mvb//4r2//TTuk/w8Pt/8fGrL/6ah1//ivcP/4r3P/q3yI/w8Pt/+MZpP/+bN5/vm4ev75t3X/+bV1//m1df/5t3X/+Ld3/8qUhP98XZn/Hxqz/+mse//5t3f/2p+B/x8as/8PD7f/u4qK//m7fv76u4D++bl7//m3fP/5uXz/+bl8//m5fP/5t3z/+bl//x8as/9NPKf/fWCb/x8as/8PD7f/bVOh//q5f//6v4X++sGI/vm9g//5voX/+b6F//m9hf/6vYX/+r6F//nCh/+bepr/Hxu0/w8Pt/8PD7f/fWOh//q+hf/6wof/+saN/vrGjf75xIv/+ceL//nEi//5xIv/+sSL//rHi//6x43/+ceN/+m7kP+7lpj/6ruQ//rHkP/6x43/+seQ//rLlf76ypT++seR//rJkf/6yZH/+seR//rJkf/6yZH/+8mR//vJlP/7yZT/+smU//rJlP/6yZT/+8yV//rJlf/6zpn+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</Image>
++
++<Url type="text/html" method="POST" template="https://startpage.com/do/search";>
++  <Param name="q" value="{searchTerms}"/>
++</Url>
++<SearchForm>https://startpage.com/do/search/</SearchForm>
++</SearchPlugin>
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch b/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch
new file mode 100644
index 0000000..93a989b
--- /dev/null
+++ b/src/current-patches/firefox/0015-Make-nsICacheService.EvictEntries-synchronous.patch
@@ -0,0 +1,44 @@
+From 20c94cb890a8872c07ba13686e293ca147b85cd6 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Tue, 1 May 2012 15:02:03 -0700
+Subject: [PATCH 15/24] Make nsICacheService.EvictEntries synchronous
+
+This fixes a race condition that allows cache-based EverCookies to persist for
+a brief time (on the order of minutes?) after cache clearing/"New Identity".
+
+https://trac.torproject.org/projects/tor/ticket/5715
+---
+ netwerk/cache/nsCacheService.cpp |   15 +++++++++++++--
+ 1 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp
+index 83ce887..e9f1a76 100644
+--- a/netwerk/cache/nsCacheService.cpp
++++ b/netwerk/cache/nsCacheService.cpp
+@@ -1316,10 +1316,21 @@ NS_IMETHODIMP nsCacheService::VisitEntries(nsICacheVisitor *visitor)
+     return NS_OK;
+ }
+ 
+-
+ NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
+ {
+-    return  EvictEntriesForClient(nsnull, storagePolicy);
++    NS_IMETHODIMP r;
++    r = EvictEntriesForClient(nsnull, storagePolicy);
++
++    // XXX: Bloody hack until we get this notifier in FF14.0:
++    // https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsICacheListener#onCacheEntryDoomed%28%29
++    if (storagePolicy == nsICache::STORE_ANYWHERE &&
++            NS_IsMainThread() && gService && gService->mInitialized) {
++        nsCacheServiceAutoLock lock;
++        gService->DoomActiveEntries();
++        gService->ClearDoomList();
++        (void) SyncWithCacheIOThread();
++    }
++    return r; 
+ }
+ 
+ NS_IMETHODIMP nsCacheService::GetCacheIOTarget(nsIEventTarget * *aCacheIOTarget)
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch b/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch
new file mode 100644
index 0000000..bb70b17
--- /dev/null
+++ b/src/current-patches/firefox/0016-Prevent-WebSocket-DNS-leak.patch
@@ -0,0 +1,132 @@
+From 976f0d4fabb6b0b50c83192d622827357c761bd3 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 2 May 2012 17:44:39 -0700
+Subject: [PATCH 16/24] Prevent WebSocket DNS leak.
+
+This is due to an improper implementation of the WebSocket spec by Mozilla.
+
+"There MUST be no more than one connection in a CONNECTING state.  If multiple
+connections to the same IP address are attempted simultaneously, the client
+MUST serialize them so that there is no more than one connection at a time
+running through the following steps.
+
+If the client cannot determine the IP address of the remote host (for
+example, because all communication is being done through a proxy server that
+performs DNS queries itself), then the client MUST assume for the purposes of
+this step that each host name refers to a distinct remote host,"
+
+https://tools.ietf.org/html/rfc6455#page-15
+
+They implmented the first paragraph, but not the second...
+
+While we're at it, we also prevent the DNS service from being used to look up
+anything other than IP addresses if socks_remote_dns is set to true, so this
+bug can't turn up in other components or due to 3rd party addons.
+---
+ netwerk/dns/nsDNSService2.cpp                   |   24 ++++++++++++++++++++++-
+ netwerk/dns/nsDNSService2.h                     |    1 +
+ netwerk/protocol/websocket/WebSocketChannel.cpp |    8 +++++-
+ 3 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp
+index 68ad8a5..1253b2f 100644
+--- a/netwerk/dns/nsDNSService2.cpp
++++ b/netwerk/dns/nsDNSService2.cpp
+@@ -383,6 +383,7 @@ nsDNSService::Init()
+     bool     enableIDN        = true;
+     bool     disableIPv6      = false;
+     bool     disablePrefetch  = false;
++    bool     disableDNS       = false;
+     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
+     
+     nsAdoptingCString ipv4OnlyDomains;
+@@ -404,6 +405,10 @@ nsDNSService::Init()
+ 
+         // If a manual proxy is in use, disable prefetch implicitly
+         prefs->GetIntPref("network.proxy.type", &proxyType);
++
++        // If the user wants remote DNS, we should fail any lookups that still
++        // make it here.
++        prefs->GetBoolPref("network.proxy.socks_remote_dns", &disableDNS);
+     }
+ 
+     if (mFirstTime) {
+@@ -420,7 +425,7 @@ nsDNSService::Init()
+ 
+             // Monitor these to see if there is a change in proxy configuration
+             // If a manual proxy is in use, disable prefetch implicitly
+-            prefs->AddObserver("network.proxy.type", this, false);
++            prefs->AddObserver("network.proxy.", this, false);
+         }
+     }
+ 
+@@ -448,6 +453,7 @@ nsDNSService::Init()
+         mIDN = idn;
+         mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership
+         mDisableIPv6 = disableIPv6;
++        mDisableDNS = disableDNS;
+ 
+         // Disable prefetching either by explicit preference or if a manual proxy is configured 
+         mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
+@@ -547,6 +553,14 @@ nsDNSService::AsyncResolve(const nsACString  &hostname,
+         if (mDisablePrefetch && (flags & RESOLVE_SPECULATE))
+             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
+ 
++        PRNetAddr tempAddr;
++        if (mDisableDNS) {
++            // Allow IP lookups through, but nothing else.
++            if (PR_StringToNetAddr(hostname.BeginReading(), &tempAddr) != PR_SUCCESS) {
++                return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED?
++            }
++        }
++
+         res = mResolver;
+         idn = mIDN;
+     }
+@@ -597,6 +611,14 @@ nsDNSService::Resolve(const nsACString &hostname,
+         MutexAutoLock lock(mLock);
+         res = mResolver;
+         idn = mIDN;
++
++        PRNetAddr tempAddr;
++        if (mDisableDNS) {
++            // Allow IP lookups through, but nothing else.
++            if (PR_StringToNetAddr(hostname.BeginReading(), &tempAddr) != PR_SUCCESS) {
++                return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED?
++            }
++        }
+     }
+     NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
+ 
+diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h
+index 1749b41..3ec8eba 100644
+--- a/netwerk/dns/nsDNSService2.h
++++ b/netwerk/dns/nsDNSService2.h
+@@ -70,4 +70,5 @@ private:
+     bool                      mDisableIPv6;
+     bool                      mDisablePrefetch;
+     bool                      mFirstTime;
++    bool                      mDisableDNS;
+ };
+diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp
+index 9e446e9..42aa6ca 100644
+--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
++++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
+@@ -1698,8 +1698,12 @@ WebSocketChannel::ApplyForAdmission()
+   LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
+   nsCOMPtr<nsIThread> mainThread;
+   NS_GetMainThread(getter_AddRefs(mainThread));
+-  dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mDNSRequest));
+-  NS_ENSURE_SUCCESS(rv, rv);
++  rv = dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mDNSRequest));
++  if (NS_FAILED(rv)) {
++      // Fall back to hostname on dispatch failure
++      mDNSRequest = nsnull;
++      OnLookupComplete(nsnull, nsnull, rv);
++  }
+ 
+   return NS_OK;
+ }
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch b/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch
new file mode 100644
index 0000000..f1814e7
--- /dev/null
+++ b/src/current-patches/firefox/0017-Randomize-HTTP-request-order-and-pipeline-depth.patch
@@ -0,0 +1,251 @@
+From 36f826e64411a74912ba1adebd1a30b84716bf84 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Wed, 6 Jun 2012 11:08:56 -0700
+Subject: [PATCH 17/24] Randomize HTTP request order and pipeline depth.
+
+This is an experimental defense against
+http://lorre.uni.lu/~andriy/papers/acmccs-wpes11-fingerprinting.pdf
+
+See:
+https://blog.torproject.org/blog/experimental-defense-website-traffic-fingerprinting
+
+This defense has been improved since that blog post to additionally randomize
+the order and concurrency of non-pipelined HTTP requests.
+---
+ netwerk/protocol/http/nsHttpConnectionMgr.cpp |  136 ++++++++++++++++++++++++-
+ netwerk/protocol/http/nsHttpConnectionMgr.h   |    5 +
+ 2 files changed, 136 insertions(+), 5 deletions(-)
+
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+index 23ef893..788368f 100644
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+@@ -94,6 +94,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
+ {
+     LOG(("Creating nsHttpConnectionMgr @%x\n", this));
+     mCT.Init();
++
++    nsresult rv;
++    mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1", &rv);
++    if (NS_FAILED(rv)) {
++        mRandomGenerator = nsnull;
++    }
+ }
+ 
+ nsHttpConnectionMgr::~nsHttpConnectionMgr()
+@@ -342,8 +348,12 @@ nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline)
+         nsConnectionEntry *ent = mCT.Get(ci->HashKey());
+         if (ent) {
+             // search for another request to pipeline...
+-            PRInt32 i, count = ent->mPendingQ.Length();
+-            for (i=0; i<count; ++i) {
++            PRInt32 i, h, count = ent->mPendingQ.Length();
++            PRInt32* ind = new PRInt32[count];
++            ShuffleRequestOrder((PRUint32*)ind, (PRUint32)count);
++       
++            for (h=0; h<count; ++h) {
++                i = ind[h]; // random request sequence
+                 nsHttpTransaction *trans = ent->mPendingQ[i];
+                 if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) {
+                     pipeline->AddTransaction(trans);
+@@ -354,6 +364,8 @@ nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline)
+                     break;
+                 }
+             }
++
++            delete [] ind;
+         }
+     }
+ }
+@@ -585,12 +597,17 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
+     LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry [ci=%s]\n",
+         ent->mConnInfo->HashKey().get()));
+ 
+-    PRInt32 i, count = ent->mPendingQ.Length();
++    PRUint32 h, i = 0, count = ent->mPendingQ.Length();
+     if (count > 0) {
+         LOG(("  pending-count=%u\n", count));
+         nsHttpTransaction *trans = nsnull;
+         nsHttpConnection *conn = nsnull;
+-        for (i=0; i<count; ++i) {
++
++        PRUint32* ind = new PRUint32[count];
++        ShuffleRequestOrder(ind, count);
++       
++        for (h=0; h<count; ++h) {
++            i = ind[h]; // random request sequence
+             trans = ent->mPendingQ[i];
+ 
+             // When this transaction has already established a half-open
+@@ -610,6 +627,7 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent)
+             if (conn)
+                 break;
+         }
++        delete [] ind;
+         if (conn) {
+             LOG(("  dispatching pending transaction...\n"));
+ 
+@@ -694,6 +712,19 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, PRUint8 cap
+         maxPersistConns = mMaxPersistConnsPerHost;
+     }
+ 
++    // Fuzz maxConns for website fingerprinting attack
++    // We create a range of maxConns/5 up to 6*maxConns/5 
++    // because this function is called repeatedly, and we'll
++    // end up converging to the high side of concurrent connections
++    // after a short while. 
++    PRUint8 *bytes = nsnull;
++    nsresult rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
++    NS_ENSURE_SUCCESS(rv, rv);
++
++    bytes[0] = bytes[0] % (maxConns + 1);
++    maxConns = (maxConns/5) + bytes[0];
++    NS_Free(bytes);
++
+     // use >= just to be safe
+     return (totalCount >= maxConns) || ( (caps & NS_HTTP_ALLOW_KEEPALIVE) &&
+                                          (persistCount >= maxPersistConns) );
+@@ -865,7 +896,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
+     nsHttpPipeline *pipeline = nsnull;
+     if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) {
+         LOG(("  looking to build pipeline...\n"));
+-        if (BuildPipeline(ent, trans, &pipeline))
++        if (BuildRandomizedPipeline(ent, trans, &pipeline))
+             trans = pipeline;
+     }
+ 
+@@ -938,6 +969,101 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent,
+     return true;
+ }
+ 
++
++// Generate a shuffled request ordering sequence 
++void
++nsHttpConnectionMgr::ShuffleRequestOrder(PRUint32 *ind, PRUint32 count)
++{
++   PRUint32 i;
++   PRUint32 *rints;
++
++   for (i=0; i<count; ++i) {
++       ind[i] = i;
++   }
++   nsresult rv = mRandomGenerator->GenerateRandomBytes(sizeof(PRUint32)*count,
++                                                       (PRUint8**)&rints);
++   if (NS_FAILED(rv))
++       return; // Leave unshuffled if error
++
++   for (i=0; i < count; ++i) {
++       PRInt32 temp = ind[i];
++       ind[i] = ind[rints[i]%count]; 
++       ind[rints[i]%count] = temp;
++   }
++   NS_Free(rints);
++}
++
++bool
++nsHttpConnectionMgr::BuildRandomizedPipeline(nsConnectionEntry *ent,
++                                   nsAHttpTransaction *firstTrans,
++                                   nsHttpPipeline **result)
++{
++    if (mRandomGenerator == nsnull)
++        return BuildPipeline(ent, firstTrans, result);
++    if (mMaxPipelinedRequests < 2)
++        return PR_FALSE;
++
++    nsresult rv;
++    PRUint8 *bytes = nsnull;
++
++    nsHttpPipeline *pipeline = nsnull;
++    nsHttpTransaction *trans;
++
++    PRUint32 i = 0, numAdded = 0, numAllowed = 0;
++    PRUint32 max = 0;
++
++    while (i < ent->mPendingQ.Length()) {
++        if (ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING)
++            numAllowed++;
++        i++;
++    }
++
++    rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
++    NS_ENSURE_SUCCESS(rv, rv);
++    // 4...12
++    max = 4 + (bytes[0] % (mMaxPipelinedRequests + 1));
++    NS_Free(bytes);
++
++    while (numAllowed > 0) {
++        rv = mRandomGenerator->GenerateRandomBytes(1, &bytes);
++        NS_ENSURE_SUCCESS(rv, rv);
++        i = bytes[0] % ent->mPendingQ.Length();
++        NS_Free(bytes);
++
++        trans = ent->mPendingQ[i];
++
++        if (!(ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING))
++            continue;
++
++        if (numAdded == 0) {
++            pipeline = new nsHttpPipeline;
++            if (!pipeline)
++                return PR_FALSE;
++            pipeline->AddTransaction(firstTrans);
++            numAdded = 1;
++        }
++        pipeline->AddTransaction(trans);
++
++        // remove transaction from pending queue
++        ent->mPendingQ.RemoveElementAt(i);
++        NS_RELEASE(trans);
++
++        numAllowed--;
++
++        if (++numAdded == max)
++            break;
++    }
++
++    //fprintf(stderr, "Yay!!! pipelined %u/%u transactions\n", numAdded, max);
++    LOG(("  pipelined %u/%u transactions\n", numAdded, max));
++
++    if (numAdded == 0)
++        return PR_FALSE;
++
++    NS_ADDREF(*result = pipeline);
++    return PR_TRUE;
++}
++
+ nsresult
+ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
+ {
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h
+index cdf21a9..81b282a 100644
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
+@@ -51,6 +51,7 @@
+ 
+ #include "nsIObserver.h"
+ #include "nsITimer.h"
++#include "nsIRandomGenerator.h"
+ 
+ class nsHttpPipeline;
+ 
+@@ -276,6 +277,8 @@ private:
+     nsresult DispatchTransaction(nsConnectionEntry *, nsAHttpTransaction *,
+                                  PRUint8 caps, nsHttpConnection *);
+     bool     BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
++    bool     BuildRandomizedPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
++    void     ShuffleRequestOrder(PRUint32 *, PRUint32);
+     nsresult ProcessNewTransaction(nsHttpTransaction *);
+     nsresult EnsureSocketThreadTargetIfOnline();
+     void     ClosePersistentConnections(nsConnectionEntry *ent);
+@@ -353,6 +356,8 @@ private:
+     PRUint64 mTimeOfNextWakeUp;
+     // Timer for next pruning of dead connections.
+     nsCOMPtr<nsITimer> mTimer;
++    // Random number generator for reordering HTTP pipeline
++    nsCOMPtr<nsIRandomGenerator>             mRandomGenerator;
+ 
+     //
+     // the connection table
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch b/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch
new file mode 100644
index 0000000..46cf611
--- /dev/null
+++ b/src/current-patches/firefox/0018-Add-HTTP-auth-headers-before-the-modify-request-obse.patch
@@ -0,0 +1,52 @@
+From c1e26c8a294abe426fd6fb84508db6074ef23379 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxx>
+Date: Fri, 2 Sep 2011 15:33:20 -0700
+Subject: [PATCH 18/24] Add HTTP auth headers before the modify-request
+ observer.
+
+Otherwise, how are we supposed to modify them?
+
+Thanks to Georg Koppen for spotting both the problem and this fix.
+---
+ netwerk/protocol/http/nsHttpChannel.cpp |   11 +++++++----
+ 1 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+index 97bd84c..6205d62 100644
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -316,9 +316,6 @@ nsHttpChannel::Connect(bool firstTime)
+         return NS_ERROR_DOCUMENT_NOT_CACHED;
+     }
+ 
+-    // check to see if authorization headers should be included
+-    mAuthProvider->AddAuthorizationHeaders();
+-
+     if (mLoadFlags & LOAD_NO_NETWORK_IO) {
+         return NS_ERROR_DOCUMENT_NOT_CACHED;
+     }
+@@ -3707,6 +3704,9 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
+ 
+     AddCookiesToRequest();
+ 
++    // check to see if authorization headers should be included
++    mAuthProvider->AddAuthorizationHeaders();
++
+     // notify "http-on-modify-request" observers
+     gHttpHandler->OnModifyRequest(this);
+ 
+@@ -4817,7 +4817,10 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
+     // this authentication attempt (bug 84794).
+     // TODO: save cookies from auth response and send them here (bug 572151).
+     AddCookiesToRequest();
+-    
++   
++    // check to see if authorization headers should be included
++    mAuthProvider->AddAuthorizationHeaders();
++ 
+     // notify "http-on-modify-request" observers
+     gHttpHandler->OnModifyRequest(this);
+ 
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch b/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
new file mode 100644
index 0000000..7f3869c
--- /dev/null
+++ b/src/current-patches/firefox/0019-Adapt-Steven-Michaud-s-Mac-crashfix-patch.patch
@@ -0,0 +1,532 @@
+From 49cccdba3e6fc10e0e376d423b3ba1b6135f62e1 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
+Date: Thu, 7 Jun 2012 16:25:48 -0700
+Subject: [PATCH 19/24] Adapt Steven Michaud's Mac crashfix patch
+
+Source is: https://bugzilla.mozilla.org/show_bug.cgi?id=715885#c35
+
+Some minor tweaks were needed to get it to apply and to compile on
+MacOS.
+---
+ widget/public/Makefile.in                  |    2 +
+ widget/public/nsIDragService.idl           |    1 -
+ widget/public/nsPIDragService.idl          |   48 ++++++++++++++++++++++++++++
+ widget/public/nsPIDragServiceWindows.idl   |   46 ++++++++++++++++++++++++++
+ widget/src/cocoa/nsChildView.mm            |   35 +++++++++++++-------
+ widget/src/gtk2/nsDragService.cpp          |    2 +-
+ widget/src/gtk2/nsWindow.cpp               |    2 +-
+ widget/src/qt/nsDragService.h              |    2 +
+ widget/src/windows/Makefile.in             |    1 -
+ widget/src/windows/nsDragService.cpp       |   13 +++++---
+ widget/src/windows/nsDragService.h         |   12 +++---
+ widget/src/windows/nsNativeDragSource.cpp  |    7 ++--
+ widget/src/windows/nsNativeDragTarget.cpp  |   28 ++++++++++------
+ widget/src/xpwidgets/nsBaseDragService.cpp |   16 +++++++++-
+ widget/src/xpwidgets/nsBaseDragService.h   |    9 ++---
+ 15 files changed, 176 insertions(+), 48 deletions(-)
+ create mode 100644 widget/public/nsPIDragService.idl
+ create mode 100644 widget/public/nsPIDragServiceWindows.idl
+
+diff --git a/widget/public/Makefile.in b/widget/public/Makefile.in
+index a70e65a..8a9b73d 100644
+--- a/widget/public/Makefile.in
++++ b/widget/public/Makefile.in
+@@ -110,6 +110,8 @@ XPIDLSRCS	= \
+ 		nsIClipboardDragDropHooks.idl \
+ 		nsIClipboardDragDropHookList.idl \
+ 		nsIDragSession.idl \
++		nsPIDragService.idl \
++		nsPIDragServiceWindows.idl \
+ 		nsIDragService.idl \
+ 		nsIFormatConverter.idl \
+ 		nsIClipboard.idl \
+diff --git a/widget/public/nsIDragService.idl b/widget/public/nsIDragService.idl
+index 6863a88..c4a1e26 100644
+--- a/widget/public/nsIDragService.idl
++++ b/widget/public/nsIDragService.idl
+@@ -146,7 +146,6 @@ interface nsIDragService : nsISupports
+   void suppress();
+   void unsuppress();
+ 
+-  [noscript] void dragMoved(in long aX, in long aY);
+ };
+ 
+ 
+diff --git a/widget/public/nsPIDragService.idl b/widget/public/nsPIDragService.idl
+new file mode 100644
+index 0000000..93a144d
+--- /dev/null
++++ b/widget/public/nsPIDragService.idl
+@@ -0,0 +1,48 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is mozilla.org code.
++ *
++ * The Initial Developer of the Original Code is
++ * The Mozilla Foundation.
++ * Portions created by the Initial Developer are Copyright (C) 2012
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *   Steven Michaud <smichaud@xxxxxxxxx>
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "nsISupports.idl"
++
++[scriptable, uuid(FAD8C90B-8E1D-446A-9B6C-241486A85CBD)]
++interface nsPIDragService : nsISupports
++{
++  void dragMoved(in long aX, in long aY);
++
++  PRUint16 getInputSource();
++
++  void setDragEndPoint(in long aX, in long aY);
++};
+diff --git a/widget/public/nsPIDragServiceWindows.idl b/widget/public/nsPIDragServiceWindows.idl
+new file mode 100644
+index 0000000..c8a46dd
+--- /dev/null
++++ b/widget/public/nsPIDragServiceWindows.idl
+@@ -0,0 +1,46 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is mozilla.org code.
++ *
++ * The Initial Developer of the Original Code is
++ * The Mozilla Foundation.
++ * Portions created by the Initial Developer are Copyright (C) 2012
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *   Steven Michaud <smichaud@xxxxxxxxx>
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++#include "nsISupports.idl"
++
++[scriptable, uuid(6FC2117D-5EB4-441A-9C12-62A783BEBC0C)]
++interface nsPIDragServiceWindows : nsISupports
++{
++  void setIDataObject(in nsISupports aDataObj);
++
++  void setDroppedLocal();
++};
+diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm
+index 64336e3..b2ab6bc 100644
+--- a/widget/src/cocoa/nsChildView.mm
++++ b/widget/src/cocoa/nsChildView.mm
+@@ -4513,11 +4513,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
+   if (!dragService) {
+     dragService = do_GetService(kDragServiceContractID);
+   }
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
+ 
+   if (dragService) {
+     NSPoint pnt = [NSEvent mouseLocation];
+     FlipCocoaScreenCoordinate(pnt);
+-    dragService->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
++    dragServicePriv->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
+   }
+ }
+ 
+@@ -4538,11 +4539,13 @@ NSEvent* gLastDragMouseDownEvent = nil;
+   }
+ 
+   if (mDragService) {
+-    // set the dragend point from the current mouse location
+-    nsDragService* dragService = static_cast<nsDragService *>(mDragService);
+-    NSPoint pnt = [NSEvent mouseLocation];
+-    FlipCocoaScreenCoordinate(pnt);
+-    dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
++    nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++    if (dragServicePriv) {
++      // set the dragend point from the current mouse location
++      NSPoint pnt = [NSEvent mouseLocation];
++      FlipCocoaScreenCoordinate(pnt);
++      dragServicePriv->SetDragEndPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
++    }
+ 
+     // XXX: dropEffect should be updated per |operation|. 
+     // As things stand though, |operation| isn't well handled within "our"
+@@ -4553,13 +4556,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
+     // value for NSDragOperationGeneric that is passed by other applications.
+     // All that said, NSDragOperationNone is still reliable.
+     if (operation == NSDragOperationNone) {
+-      nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
+-      dragService->GetDataTransfer(getter_AddRefs(dataTransfer));
+-      nsCOMPtr<nsIDOMNSDataTransfer> dataTransferNS =
+-        do_QueryInterface(dataTransfer);
+-
+-      if (dataTransferNS)
+-        dataTransferNS->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
++      nsCOMPtr<nsIDragSession> dragSession;
++      mDragService->GetCurrentSession(getter_AddRefs(dragSession));
++      if (dragSession) {
++        nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
++        dragSession->GetDataTransfer(getter_AddRefs(dataTransfer));
++        if (dataTransfer) {
++          nsCOMPtr<nsIDOMNSDataTransfer> dataTransferNS =
++                do_QueryInterface(dataTransfer);
++          if (dataTransferNS) {
++            dataTransferNS->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
++          }
++        }
++      }
+     }
+ 
+     mDragService->EndDragSession(true);
+diff --git a/widget/src/gtk2/nsDragService.cpp b/widget/src/gtk2/nsDragService.cpp
+index ca5a42c..876fd55 100644
+--- a/widget/src/gtk2/nsDragService.cpp
++++ b/widget/src/gtk2/nsDragService.cpp
+@@ -1334,7 +1334,7 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext,
+     GdkDisplay* display = gdk_display_get_default();
+     if (display) {
+       gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+-      SetDragEndPoint(nsIntPoint(x, y));
++      SetDragEndPoint(x, y);
+     }
+ 
+     // Either the drag was aborted or the drop occurred outside the app.
+diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp
+index 2fd6f64..a2e27e1 100644
+--- a/widget/src/gtk2/nsWindow.cpp
++++ b/widget/src/gtk2/nsWindow.cpp
+@@ -3738,7 +3738,7 @@ nsWindow::OnDragDropEvent(GtkWidget *aWidget,
+     if (display) {
+       // get the current cursor position
+       gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+-      ((nsDragService *)dragService.get())->SetDragEndPoint(nsIntPoint(x, y));
++      ((nsDragService *)dragService.get())->SetDragEndPoint(x, y);
+     }
+     dragService->EndDragSession(true);
+ 
+diff --git a/widget/src/qt/nsDragService.h b/widget/src/qt/nsDragService.h
+index 5a3e5bb..50dcfac 100644
+--- a/widget/src/qt/nsDragService.h
++++ b/widget/src/qt/nsDragService.h
+@@ -50,6 +50,8 @@ public:
+     NS_DECL_ISUPPORTS
+     NS_DECL_NSIDRAGSERVICE
+ 
++    NS_IMETHOD DragMoved(PRInt32 aX, PRInt32 aY);
++
+     nsDragService();
+ 
+ private:
+diff --git a/widget/src/windows/Makefile.in b/widget/src/windows/Makefile.in
+index 53277ea..d7ff7ce 100644
+--- a/widget/src/windows/Makefile.in
++++ b/widget/src/windows/Makefile.in
+@@ -115,7 +115,6 @@ ifdef MOZ_ENABLE_D3D10_LAYER
+ DEFINES		+= -DMOZ_ENABLE_D3D10_LAYER
+ endif
+ 
+-
+ EXPORTS		= nsdefs.h WindowHook.h
+ EXPORTS_NAMESPACES = mozilla/widget
+ EXPORTS_mozilla/widget = AudioSession.h
+diff --git a/widget/src/windows/nsDragService.cpp b/widget/src/windows/nsDragService.cpp
+index 2dcede3..3d8af21 100644
+--- a/widget/src/windows/nsDragService.cpp
++++ b/widget/src/windows/nsDragService.cpp
+@@ -97,6 +97,8 @@ nsDragService::~nsDragService()
+   NS_IF_RELEASE(mDataObject);
+ }
+ 
++NS_IMPL_ISUPPORTS_INHERITED1(nsDragService, nsBaseDragService, nsPIDragServiceWindows)
++
+ bool
+ nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
+                                nsIScriptableRegion *aRegion,
+@@ -350,7 +352,7 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
+   POINT cpos;
+   cpos.x = GET_X_LPARAM(pos);
+   cpos.y = GET_Y_LPARAM(pos);
+-  SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
++  SetDragEndPoint(cpos.x, cpos.y);
+   EndDragSession(true);
+ 
+   mDoingDrag = false;
+@@ -468,25 +470,26 @@ nsDragService::GetData(nsITransferable * aTransferable, PRUint32 anItem)
+ 
+ //---------------------------------------------------------
+ NS_IMETHODIMP
+-nsDragService::SetIDataObject(IDataObject * aDataObj)
++nsDragService::SetIDataObject(nsISupports * aDataObj)
+ {
++  IDataObject *dataObj = (IDataObject*) aDataObj;
+   // When the native drag starts the DragService gets
+   // the IDataObject that is being dragged
+   NS_IF_RELEASE(mDataObject);
+-  mDataObject = aDataObj;
++  mDataObject = dataObj;
+   NS_IF_ADDREF(mDataObject);
+ 
+   return NS_OK;
+ }
+ 
+ //---------------------------------------------------------
+-void
++NS_IMETHODIMP
+ nsDragService::SetDroppedLocal()
+ {
+   // Sent from the native drag handler, letting us know
+   // a drop occurred within the application vs. outside of it.
+   mSentLocalDropEvent = true;
+-  return;
++  return NS_OK;
+ }
+ 
+ //-------------------------------------------------------------------------
+diff --git a/widget/src/windows/nsDragService.h b/widget/src/windows/nsDragService.h
+index 067bcf2..2699e47 100644
+--- a/widget/src/windows/nsDragService.h
++++ b/widget/src/windows/nsDragService.h
+@@ -39,6 +39,7 @@
+ #define nsDragService_h__
+ 
+ #include "nsBaseDragService.h"
++#include "nsPIDragServiceWindows.h"
+ #include <windows.h>
+ #include <shlobj.h>
+ 
+@@ -52,12 +53,15 @@ class  nsString;
+  * Native Win32 DragService wrapper
+  */
+ 
+-class nsDragService : public nsBaseDragService
++class nsDragService : public nsBaseDragService, public nsPIDragServiceWindows
+ {
+ public:
+   nsDragService();
+   virtual ~nsDragService();
+-  
++
++  NS_DECL_ISUPPORTS_INHERITED
++  NS_DECL_NSPIDRAGSERVICEWINDOWS
++
+   // nsIDragService
+   NS_IMETHOD InvokeDragSession(nsIDOMNode *aDOMNode,
+                                nsISupportsArray *anArrayTransferables,
+@@ -71,13 +75,9 @@ public:
+   NS_IMETHOD EndDragSession(bool aDoneDrag);
+ 
+   // native impl.
+-  NS_IMETHOD SetIDataObject(IDataObject * aDataObj);
+   NS_IMETHOD StartInvokingDragSession(IDataObject * aDataObj,
+                                       PRUint32 aActionType);
+ 
+-  // A drop occurred within the application vs. outside of it.
+-  void SetDroppedLocal();
+-
+ protected:
+   nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj);
+ 
+diff --git a/widget/src/windows/nsNativeDragSource.cpp b/widget/src/windows/nsNativeDragSource.cpp
+index e51101e..0fe6ffe 100644
+--- a/widget/src/windows/nsNativeDragSource.cpp
++++ b/widget/src/windows/nsNativeDragSource.cpp
+@@ -42,7 +42,7 @@
+ #include "nsIServiceManager.h"
+ #include "nsToolkit.h"
+ #include "nsWidgetsCID.h"
+-#include "nsIDragService.h"
++#include "nsDragService.h"
+ 
+ static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
+ 
+@@ -101,9 +101,10 @@ STDMETHODIMP
+ nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState)
+ {
+   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
+-  if (dragService) {
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(dragService);
++  if (dragServicePriv) {
+     DWORD pos = ::GetMessagePos();
+-    dragService->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
++    dragServicePriv->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
+   }
+ 
+   if (fEsc) {
+diff --git a/widget/src/windows/nsNativeDragTarget.cpp b/widget/src/windows/nsNativeDragTarget.cpp
+index cf6196b..82ad3c6 100644
+--- a/widget/src/windows/nsNativeDragTarget.cpp
++++ b/widget/src/windows/nsNativeDragTarget.cpp
+@@ -209,7 +209,11 @@ nsNativeDragTarget::DispatchDragDropEvent(PRUint32 aEventType, POINTL aPT)
+   event.isControl = IsKeyDown(NS_VK_CONTROL);
+   event.isMeta    = false;
+   event.isAlt     = IsKeyDown(NS_VK_ALT);
+-  event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
++  event.inputSource = 0;
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++  if (dragServicePriv) {
++    dragServicePriv->GetInputSource(&event.inputSource);
++  }
+ 
+   mWindow->DispatchEvent(&event, status);
+ }
+@@ -296,9 +300,8 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
+   // This cast is ok because in the constructor we created a
+   // the actual implementation we wanted, so we know this is
+   // a nsDragService. It should be a private interface, though.
+-  nsDragService * winDragService =
+-    static_cast<nsDragService *>(mDragService);
+-  winDragService->SetIDataObject(pIDataSource);
++  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
++  winDragService->SetIDataObject((nsISupports*)pIDataSource);
+ 
+   // Now process the native drag state and then dispatch the event
+   ProcessDrag(NS_DRAGDROP_ENTER, grfKeyState, ptl, pdwEffect);
+@@ -436,8 +439,8 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
+   // This cast is ok because in the constructor we created a
+   // the actual implementation we wanted, so we know this is
+   // a nsDragService (but it should still be a private interface)
+-  nsDragService* winDragService = static_cast<nsDragService*>(mDragService);
+-  winDragService->SetIDataObject(pData);
++  nsCOMPtr<nsPIDragServiceWindows> winDragService = do_QueryInterface(mDragService);
++  winDragService->SetIDataObject((nsISupports*)pData);
+ 
+   // NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
+   // We use strong refs to prevent it from destroying these:
+@@ -461,11 +464,14 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
+   // tell the drag service we're done with the session
+   // Use GetMessagePos to get the position of the mouse at the last message
+   // seen by the event loop. (Bug 489729)
+-  DWORD pos = ::GetMessagePos();
+-  POINT cpos;
+-  cpos.x = GET_X_LPARAM(pos);
+-  cpos.y = GET_Y_LPARAM(pos);
+-  winDragService->SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
++  nsCOMPtr<nsPIDragService> dragServicePriv = do_QueryInterface(mDragService);
++  if (dragServicePriv) {
++    DWORD pos = ::GetMessagePos();
++    POINT cpos;
++    cpos.x = GET_X_LPARAM(pos);
++    cpos.y = GET_Y_LPARAM(pos);
++    dragServicePriv->SetDragEndPoint(cpos.x, cpos.y);
++  }
+   serv->EndDragSession(true);
+ 
+   // release the ref that was taken in DragEnter
+diff --git a/widget/src/xpwidgets/nsBaseDragService.cpp b/widget/src/xpwidgets/nsBaseDragService.cpp
+index 52efb7e..1c35673 100644
+--- a/widget/src/xpwidgets/nsBaseDragService.cpp
++++ b/widget/src/xpwidgets/nsBaseDragService.cpp
+@@ -89,7 +89,7 @@ nsBaseDragService::~nsBaseDragService()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS2(nsBaseDragService, nsIDragService, nsIDragSession)
++NS_IMPL_ISUPPORTS3(nsBaseDragService, nsIDragService, nsPIDragService, nsIDragSession)
+ 
+ //---------------------------------------------------------
+ NS_IMETHODIMP
+@@ -443,6 +443,20 @@ nsBaseDragService::DragMoved(PRInt32 aX, PRInt32 aY)
+   return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++nsBaseDragService::SetDragEndPoint(PRInt32 aX, PRInt32 aY)
++{
++  mEndDragPoint = nsIntPoint(aX, aY);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++nsBaseDragService::GetInputSource(PRUint16* aInputSource)
++{
++  *aInputSource = mInputSource;
++  return NS_OK;
++}
++
+ static nsIPresShell*
+ GetPresShellForContent(nsIDOMNode* aDOMNode)
+ {
+diff --git a/widget/src/xpwidgets/nsBaseDragService.h b/widget/src/xpwidgets/nsBaseDragService.h
+index 290c0cb..2ceac2b 100644
+--- a/widget/src/xpwidgets/nsBaseDragService.h
++++ b/widget/src/xpwidgets/nsBaseDragService.h
+@@ -39,6 +39,7 @@
+ #define nsBaseDragService_h__
+ 
+ #include "nsIDragService.h"
++#include "nsPIDragService.h"
+ #include "nsIDragSession.h"
+ #include "nsITransferable.h"
+ #include "nsISupportsArray.h"
+@@ -64,6 +65,7 @@ class nsICanvasElementExternal;
+  */
+ 
+ class nsBaseDragService : public nsIDragService,
++                          public nsPIDragService,
+                           public nsIDragSession
+ {
+ 
+@@ -74,14 +76,11 @@ public:
+   //nsISupports
+   NS_DECL_ISUPPORTS
+ 
+-  //nsIDragSession and nsIDragService
++  //nsIDragSession, nsIDragService and nsPIDragService
+   NS_DECL_NSIDRAGSERVICE
++  NS_DECL_NSPIDRAGSERVICE
+   NS_DECL_NSIDRAGSESSION
+ 
+-  void SetDragEndPoint(nsIntPoint aEndDragPoint) { mEndDragPoint = aEndDragPoint; }
+-
+-  PRUint16 GetInputSource() { return mInputSource; }
+-
+ protected:
+ 
+   /**
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch b/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
index 56d9848..114301d 100644
--- a/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
+++ b/src/current-patches/firefox/0020-Add-mozIThirdPartyUtil.getFirstPartyURI-API.patch
@@ -1,17 +1,17 @@
-From 73e548ceee36b99f06e33010163ed8b8cc86b3dd Mon Sep 17 00:00:00 2001
+From 36d57455893bcf6dc08e91a2784970f285c5e84b Mon Sep 17 00:00:00 2001
 From: Mike Perry <mikeperry-git@xxxxxxxxxxxxxx>
 Date: Tue, 28 Aug 2012 18:35:33 -0700
-Subject: [PATCH 20/20] Add mozIThirdPartyUtil.getFirstPartyURI API
+Subject: [PATCH 20/24] Add mozIThirdPartyUtil.getFirstPartyURI API
 
 API allows you to get the url bar URI for a channel or nsIDocument.
 ---
- content/base/src/ThirdPartyUtil.cpp        |   52 ++++++++++++++++++++++++++++
+ content/base/src/ThirdPartyUtil.cpp        |   59 ++++++++++++++++++++++++++++
  content/base/src/ThirdPartyUtil.h          |    2 +
- netwerk/base/public/mozIThirdPartyUtil.idl |   21 +++++++++++
- 3 files changed, 75 insertions(+), 0 deletions(-)
+ netwerk/base/public/mozIThirdPartyUtil.idl |   21 ++++++++++
+ 3 files changed, 82 insertions(+), 0 deletions(-)
 
 diff --git a/content/base/src/ThirdPartyUtil.cpp b/content/base/src/ThirdPartyUtil.cpp
-index 6a415e9..62333f3 100644
+index 6a415e9..52b3dab 100644
 --- a/content/base/src/ThirdPartyUtil.cpp
 +++ b/content/base/src/ThirdPartyUtil.cpp
 @@ -40,6 +40,9 @@
@@ -32,7 +32,7 @@ index 6a415e9..62333f3 100644
    return rv;
  }
  
-@@ -315,3 +319,51 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
+@@ -315,3 +319,58 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
  
    return NS_OK;
  }
@@ -62,12 +62,19 @@ index 6a415e9..62333f3 100644
 +  if (NS_FAILED(rv) && aDoc) {
 +    nsCOMPtr<nsIDOMWindow> top;
 +    nsCOMPtr<nsIDOMDocument> topDDoc;
-+    
-+    aDoc->GetWindow()->GetTop(getter_AddRefs(top));
-+    top->GetDocument(getter_AddRefs(topDDoc));
++   
++    if (aDoc->GetWindow()) {
++      aDoc->GetWindow()->GetTop(getter_AddRefs(top));
++      top->GetDocument(getter_AddRefs(topDDoc));
 +
-+    nsCOMPtr<nsIDocument> topDoc(do_QueryInterface(topDDoc));
-+    *aOutput = topDoc->GetOriginalURI();
++      nsCOMPtr<nsIDocument> topDoc(do_QueryInterface(topDDoc));
++      *aOutput = topDoc->GetOriginalURI();
++    } else {
++      // XXX: Chrome callers (such as NoScript) can end up here
++      // through getImageData/canvas usage with no document state
++      // (no Window and a document URI of about:blank). Propogate
++      // rv fail (by doing nothing), and hope caller recovers.
++    }
 +
 +    if (*aOutput)
 +      rv = NS_OK;
diff --git a/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch b/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch
new file mode 100644
index 0000000..cf5dd61
--- /dev/null
+++ b/src/current-patches/firefox/0021-Add-canvas-image-extraction-prompt.patch
@@ -0,0 +1,551 @@
+From 29ce940434ebbb8e54c0d9b8f84ccf6ec6bd71bc Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade@xxxxxxxxxxxxxxxxx>
+Date: Tue, 9 Oct 2012 11:21:06 -0400
+Subject: [PATCH 21/24] Add canvas image extraction prompt.
+
+---
+ browser/base/content/browser.css                   |    1 +
+ browser/base/content/browser.js                    |  102 ++++++++++++++++++++
+ browser/base/content/browser.xul                   |    1 +
+ .../en-US/chrome/browser/browser.properties        |    7 ++
+ browser/themes/gnomestripe/browser/browser.css     |    2 +
+ browser/themes/pinstripe/browser/browser.css       |    2 +
+ browser/themes/winstripe/browser/browser.css       |    2 +
+ content/canvas/src/CanvasUtils.cpp                 |   63 ++++++++++++
+ content/canvas/src/CanvasUtils.h                   |    2 +
+ content/canvas/src/nsCanvasRenderingContext2D.cpp  |   15 +++
+ .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   15 +++
+ content/html/content/public/nsHTMLCanvasElement.h  |    3 +
+ content/html/content/src/Makefile.in               |    1 +
+ content/html/content/src/nsHTMLCanvasElement.cpp   |   39 ++++++--
+ 14 files changed, 246 insertions(+), 9 deletions(-)
+
+diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
+index f033c2b..c709631 100644
+--- a/browser/base/content/browser.css
++++ b/browser/base/content/browser.css
+@@ -440,6 +440,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
+    created with a null anchorID, so in that case use a default anchor icon. */
+ #notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon,
+ #notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
++#notification-popup-box[anchorid="canvas-notification-icon"] > #canvas-notification-icon,
+ #notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
+ #notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
+ #notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon {
+diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
+index 20e3666..0c6bd46 100644
+--- a/browser/base/content/browser.js
++++ b/browser/base/content/browser.js
+@@ -1522,6 +1522,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
+   BrowserOffline.init();
+   OfflineApps.init();
+   IndexedDBPromptHelper.init();
++  CanvasPermissionPromptHelper.init();
+   gFormSubmitObserver.init();
+   AddonManager.addAddonListener(AddonsMgrListener);
+ 
+@@ -1834,6 +1835,7 @@ function BrowserShutdown() {
+     BrowserOffline.uninit();
+     OfflineApps.uninit();
+     IndexedDBPromptHelper.uninit();
++    CanvasPermissionPromptHelper.uninit();
+     AddonManager.removeAddonListener(AddonsMgrListener);
+   }
+ 
+@@ -6656,6 +6658,106 @@ var IndexedDBPromptHelper = {
+   }
+ };
+ 
++var CanvasPermissionPromptHelper = {
++  _permissionsPrompt: "canvas-permissions-prompt",
++  _notificationIcon: "canvas-notification-icon",
++
++  init:
++  function CanvasPermissionPromptHelper_init() {
++    Services.obs.addObserver(this, this._permissionsPrompt, false);
++  },
++
++  uninit:
++  function CanvasPermissionPromptHelper_uninit() {
++    Services.obs.removeObserver(this, this._permissionsPrompt, false);
++  },
++
++  // aSubject is an nsIDOMWindow.
++  // aData is an URL string.
++  observe:
++  function CanvasPermissionPromptHelper_observe(aSubject, aTopic, aData) {
++    if ((aTopic != this._permissionsPrompt) || !aData)
++      throw new Error("Unexpected topic or missing URL");
++
++    var uri = makeURI(aData);
++    var contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
++    var contentDocument = contentWindow.document;
++    var browserWindow =
++      OfflineApps._getBrowserWindowForContentWindow(contentWindow);
++
++    if (browserWindow != window) {
++      // Must belong to some other window.
++      return;
++    }
++
++    // If canvas prompt is already displayed, just return.  This is OK (and
++    // more efficient) since this permission is associated with the top
++    // browser's URL.
++    if (PopupNotifications.getNotification(aTopic, browser))
++      return;
++
++    var bundleSvc = Cc["@mozilla.org/intl/stringbundle;1"].
++                        getService(Ci.nsIStringBundleService);
++    var torBtnBundle;
++    try {
++      torBtnBundle = bundleSvc.createBundle(
++                             "chrome://torbutton/locale/torbutton.properties");
++    } catch (e) {}
++
++    var message = getLocalizedString("canvas.siteprompt", [ uri.asciiHost ]);
++
++    var mainAction = {
++      label: getLocalizedString("canvas.allow"),
++      accessKey: getLocalizedString("canvas.allowAccessKey"),
++      callback: function() {
++          setCanvasPermission(uri, Ci.nsIPermissionManager.ALLOW_ACTION);
++      }
++    };
++
++    var secondaryActions = [
++      {
++        label: getLocalizedString("canvas.never"),
++        accessKey: getLocalizedString("canvas.neverAccessKey"),
++        callback: function() {
++          setCanvasPermission(uri, Ci.nsIPermissionManager.DENY_ACTION);
++        }
++      }
++    ];
++
++    // Since we have a process in place to perform localization for the
++    // Torbutton extension, get our strings from the extension if possible.
++    function getLocalizedString(aID, aParams) {
++      var s;
++      if (torBtnBundle) try {
++        if (aParams)
++          s = torBtnBundle.formatStringFromName(aID, aParams, aParams.length);
++        else
++          s = torBtnBundle.GetStringFromName(aID);
++      } catch (e) {}
++
++      if (!s) {
++        if (aParams)
++          s = gNavigatorBundle.getFormattedString(aID, aParams);
++        else
++          s = gNavigatorBundle.getString(aID);
++      }
++
++      return s;
++    }
++
++    function setCanvasPermission(aURI, aPerm) {
++      Services.perms.add(aURI, "canvas/extractData", aPerm,
++                         Ci.nsIPermissionManager.EXPIRE_NEVER);
++    }
++
++    var browser = OfflineApps._getBrowserForContentWindow(browserWindow,
++                                                          contentWindow);
++    notification = PopupNotifications.show(browser, aTopic, message,
++                                           this._notificationIcon, mainAction,
++                                           secondaryActions, null);
++  }
++};
++
+ function WindowIsClosing()
+ {
+   if (TabView.isVisible()) {
+diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
+index ba2a7cb..1acea43 100644
+--- a/browser/base/content/browser.xul
++++ b/browser/base/content/browser.xul
+@@ -520,6 +520,7 @@
+             <image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
++            <image id="canvas-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
+             <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
+           </box>
+diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
+index 380e3c3..98154d1 100644
+--- a/browser/locales/en-US/chrome/browser/browser.properties
++++ b/browser/locales/en-US/chrome/browser/browser.properties
+@@ -197,6 +197,13 @@ offlineApps.usage=This website (%S) is now storing more than %SMB of data on you
+ offlineApps.manageUsage=Show settings
+ offlineApps.manageUsageAccessKey=S
+ 
++# Canvas permission prompt
++canvas.siteprompt=This website (%S) attempted to access image data on a canvas.  Blank (white) image data was returned this time.
++canvas.allow=Allow in the Future
++canvas.allowAccessKey=A
++canvas.never=Never for This Site
++canvas.neverAccessKey=e
++
+ # LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
+ # %2$S a number of megabytes.
+ indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
+diff --git a/browser/themes/gnomestripe/browser/browser.css b/browser/themes/gnomestripe/browser/browser.css
+index edc0b72..8ba057e 100644
+--- a/browser/themes/gnomestripe/browser/browser.css
++++ b/browser/themes/gnomestripe/browser/browser.css
+@@ -1227,6 +1227,7 @@ toolbar[iconsize="small"] #feed-button {
+   list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+@@ -1281,6 +1282,7 @@ toolbar[iconsize="small"] #feed-button {
+   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css
+index 2a96556..f94a6f2 100644
+--- a/browser/themes/pinstripe/browser/browser.css
++++ b/browser/themes/pinstripe/browser/browser.css
+@@ -2404,10 +2404,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
+   -moz-image-region: rect(0px, 48px, 16px, 32px);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+diff --git a/browser/themes/winstripe/browser/browser.css b/browser/themes/winstripe/browser/browser.css
+index 0103c79..d352790 100644
+--- a/browser/themes/winstripe/browser/browser.css
++++ b/browser/themes/winstripe/browser/browser.css
+@@ -2294,6 +2294,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
+   -moz-image-region: rect(32px, 32px, 48px, 16px);
+ }
+ 
++.popup-notification-icon[popupid="canvas-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
+ .popup-notification-icon[popupid="indexedDB-quota-prompt"] {
+   list-style-image: url(chrome://global/skin/icons/question-64.png);
+@@ -2346,6 +2347,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
+   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
+ }
+ 
++#canvas-notification-icon,
+ #indexedDB-notification-icon {
+   list-style-image: url(chrome://global/skin/icons/question-16.png);
+ }
+diff --git a/content/canvas/src/CanvasUtils.cpp b/content/canvas/src/CanvasUtils.cpp
+index 2f822eb..d7d0591 100644
+--- a/content/canvas/src/CanvasUtils.cpp
++++ b/content/canvas/src/CanvasUtils.cpp
+@@ -59,6 +59,15 @@
+ #include "CanvasUtils.h"
+ #include "mozilla/gfx/Matrix.h"
+ 
++#include "nsIScriptObjectPrincipal.h"
++#include "nsIPermissionManager.h"
++#include "mozIThirdPartyUtil.h"
++#include "nsContentUtils.h"
++#include "nsUnicharUtils.h"
++
++#define TOPIC_CANVAS_PERMISSIONS_PROMPT "canvas-permissions-prompt"
++#define PERMISSION_CANVAS_EXTRACT_DATA "canvas/extractData"
++
+ namespace mozilla {
+ namespace CanvasUtils {
+ 
+@@ -101,6 +110,60 @@ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
+     aCanvasElement->SetWriteOnly();
+ }
+ 
++// Check site-specific permission and display prompt if appropriate.
++bool
++IsImageExtractionAllowed(nsIDocument *aDocument)
++{
++  if (!aDocument)
++    return false;
++
++  nsPIDOMWindow *win = aDocument->GetWindow();
++  nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
++  if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()))
++    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);
++      }
++    }
++
++    if (NS_SUCCEEDED(rv)) {
++      isAllowed = (permission == nsIPermissionManager::ALLOW_ACTION);
++
++      if (!isAllowed && (permission != nsIPermissionManager::DENY_ACTION)) {
++        // Send notification so that a prompt is displayed.
++        nsCString spec;
++        rv = uri->GetSpec(spec);
++        NS_ENSURE_SUCCESS(rv, rv);
++        nsCOMPtr<nsIObserverService> obs =
++                                    mozilla::services::GetObserverService();
++        obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT,
++                             NS_ConvertUTF8toUTF16(spec).get());
++      }
++    }
++  }
++
++  return isAllowed;
++}
++
+ void
+ LogMessage (const nsCString& errorString)
+ {
+diff --git a/content/canvas/src/CanvasUtils.h b/content/canvas/src/CanvasUtils.h
+index 36186dd..067ee46 100644
+--- a/content/canvas/src/CanvasUtils.h
++++ b/content/canvas/src/CanvasUtils.h
+@@ -77,6 +77,8 @@ void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
+                               bool forceWriteOnly,
+                               bool CORSUsed);
+ 
++bool IsImageExtractionAllowed(nsIDocument *aDocument);
++
+ void LogMessage (const nsCString& errorString);
+ void LogMessagef (const char *fmt, ...);
+ 
+diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+index 36389b0..0cf97ce 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+@@ -3886,6 +3886,21 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
+     if (!rightMost.valid() || !bottomMost.valid())
+         return NS_ERROR_DOM_SYNTAX_ERR;
+ 
++    // Check for site-specific permission and return all-white, opaque pixel
++    // data if no permission.  This check is not needed if the canvas was
++    // created with a docshell (that is only done for special internal uses).
++    bool usePlaceholder = false;
++    if (mCanvasElement) {
++      nsCOMPtr<nsIDocument> ownerDoc = HTMLCanvasElement()->OwnerDoc();
++      usePlaceholder = !ownerDoc ||
++                          !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
++    }
++
++    if (usePlaceholder) {
++      memset(aData, 0xFF, aDataLen);
++      return NS_OK;
++    }
++
+     /* Copy the surface contents to the buffer */
+     nsRefPtr<gfxImageSurface> tmpsurf =
+         new gfxImageSurface(aData,
+diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+index 13baaa5..e8dfb1e 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+@@ -4038,6 +4038,21 @@ nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRU
+     return NS_OK;
+   }
+ 
++  // Check for site-specific permission and return all-white, opaque pixel
++  // data if no permission.  This check is not needed if the canvas was
++  // created with a docshell (that is only done for special internal uses).
++  bool usePlaceholder = false;
++  if (mCanvasElement) {
++    nsCOMPtr<nsIDocument> ownerDoc = HTMLCanvasElement()->OwnerDoc();
++    usePlaceholder = !ownerDoc ||
++                        !CanvasUtils::IsImageExtractionAllowed(ownerDoc);
++  }
++
++  if (usePlaceholder) {
++    memset(aData, 0xFF, aDataLen);
++    return NS_OK;
++  }
++
+   IntRect srcRect(0, 0, mWidth, mHeight);
+   IntRect destRect(x, y, w, h);
+ 
+diff --git a/content/html/content/public/nsHTMLCanvasElement.h b/content/html/content/public/nsHTMLCanvasElement.h
+index 86202a8..66176f2 100644
+--- a/content/html/content/public/nsHTMLCanvasElement.h
++++ b/content/html/content/public/nsHTMLCanvasElement.h
+@@ -188,13 +188,16 @@ protected:
+   nsresult UpdateContext(nsIPropertyBag *aNewContextOptions = nsnull);
+   nsresult ExtractData(const nsAString& aType,
+                        const nsAString& aOptions,
++                       bool aUsePlaceholder,
+                        nsIInputStream** aStream,
+                        bool& aFellBackToPNG);
+   nsresult ToDataURLImpl(const nsAString& aMimeType,
+                          nsIVariant* aEncoderOptions,
++                         bool aUsePlaceholder,
+                          nsAString& aDataURL);
+   nsresult MozGetAsFileImpl(const nsAString& aName,
+                             const nsAString& aType,
++                            bool aUsePlaceholder,
+                             nsIDOMFile** aResult);
+   nsresult GetContextHelper(const nsAString& aContextId,
+                             bool aForceThebes,
+diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in
+index 019d297..3db4f7c 100644
+--- a/content/html/content/src/Makefile.in
++++ b/content/html/content/src/Makefile.in
+@@ -138,6 +138,7 @@ INCLUDES	+= \
+ 		-I$(srcdir)/../../../events/src \
+ 		-I$(srcdir)/../../../xbl/src \
+ 		-I$(srcdir)/../../../xul/content/src \
++		-I$(srcdir)/../../../canvas/src/ \
+ 		-I$(srcdir)/../../../../layout/forms \
+ 		-I$(srcdir)/../../../../layout/style \
+ 		-I$(srcdir)/../../../../layout/tables \
+diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp
+index a302f67..572a81b 100644
+--- a/content/html/content/src/nsHTMLCanvasElement.cpp
++++ b/content/html/content/src/nsHTMLCanvasElement.cpp
+@@ -60,6 +60,8 @@
+ 
+ #include "nsIWritablePropertyBag2.h"
+ 
++#include "CanvasUtils.h"
++
+ #define DEFAULT_CANVAS_WIDTH 300
+ #define DEFAULT_CANVAS_HEIGHT 150
+ 
+@@ -213,25 +215,36 @@ nsHTMLCanvasElement::ToDataURL(const nsAString& aType, nsIVariant* aParams,
+     return NS_ERROR_DOM_SECURITY_ERR;
+   }
+ 
+-  return ToDataURLImpl(aType, aParams, aDataURL);
++  // Check site-specific permission and display prompt if appropriate.
++  // If no permission, return all-white, opaque image data.
++  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
++  return ToDataURLImpl(aType, aParams, usePlaceholder, aDataURL);
+ }
+ 
++// TODO: on FF trunk, we also need to patch mozFetchAsStream().
+ nsresult
+ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+                                  const nsAString& aOptions,
++                                 bool aUsePlaceholder,
+                                  nsIInputStream** aStream,
+                                  bool& aFellBackToPNG)
+ {
+   // note that if we don't have a current context, the spec says we're
+   // supposed to just return transparent black pixels of the canvas
+   // dimensions.
++  // If placeholder data was requested, return all-white, opaque image data.
+   nsRefPtr<gfxImageSurface> emptyCanvas;
+   nsIntSize size = GetWidthHeight();
+-  if (!mCurrentContext) {
++  if (aUsePlaceholder || !mCurrentContext) {
+     emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
+     if (emptyCanvas->CairoStatus()) {
+       return NS_ERROR_INVALID_ARG;
+     }
++
++    if (aUsePlaceholder) {
++      int32_t dataSize = emptyCanvas->GetDataSize();
++      memset(emptyCanvas->Data(), 0xFF, dataSize);
++    }
+   }
+ 
+   nsresult rv;
+@@ -241,12 +254,13 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+   NS_ConvertUTF16toUTF8 encoderType(aType);
+ 
+  try_again:
+-  if (mCurrentContext) {
++  if (!aUsePlaceholder && mCurrentContext) {
+     rv = mCurrentContext->GetInputStream(encoderType.get(),
+                                          nsPromiseFlatString(aOptions).get(),
+                                          getter_AddRefs(imgStream));
+   } else {
+-    // no context, so we have to encode the empty image we created above
++    // Using placeholder or we have no context:  encode the empty/white image
++    // we created above.
+     nsCString enccid("@mozilla.org/image/encoder;2?type=");
+     enccid += encoderType;
+ 
+@@ -284,6 +298,7 @@ nsHTMLCanvasElement::ExtractData(const nsAString& aType,
+ nsresult
+ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
+                                    nsIVariant* aEncoderOptions,
++                                   bool aUsePlaceholder,
+                                    nsAString& aDataURL)
+ {
+   bool fallbackToPNG = false;
+@@ -339,13 +354,15 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
+   }
+ 
+   nsCOMPtr<nsIInputStream> stream;
+-  rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
++  rv = ExtractData(type, params, aUsePlaceholder,
++                   getter_AddRefs(stream), fallbackToPNG);
+ 
+   // If there are unrecognized custom parse options, we should fall back to 
+   // the default values for the encoder without any options at all.
+   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
+     fallbackToPNG = false;
+-    rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
++    rv = ExtractData(type, EmptyString(), aUsePlaceholder,
++                     getter_AddRefs(stream), fallbackToPNG);
+   }
+ 
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -376,19 +393,23 @@ nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
+     return NS_ERROR_DOM_SECURITY_ERR;
+   }
+ 
+-  return MozGetAsFileImpl(aName, aType, aResult);
++  // Check site-speciifc permission and display prompt if appropriate.
++  // If no permission, return all-white, opaque image data.
++  bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc());
++  return MozGetAsFileImpl(aName, aType, usePlaceholder, aResult);
+ }
+ 
+ nsresult
+ nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
+                                       const nsAString& aType,
++                                      bool aUsePlaceholder,
+                                       nsIDOMFile** aResult)
+ {
+   bool fallbackToPNG = false;
+ 
+   nsCOMPtr<nsIInputStream> stream;
+-  nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
+-                            fallbackToPNG);
++  nsresult rv = ExtractData(aType, EmptyString(), aUsePlaceholder,
++                            getter_AddRefs(stream), fallbackToPNG);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   nsAutoString type(aType);
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch b/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch
new file mode 100644
index 0000000..6da9c72
--- /dev/null
+++ b/src/current-patches/firefox/0022-Return-client-window-coordinates-for-mouse-event-scr.patch
@@ -0,0 +1,43 @@
+From 74215e38ba60b74df59216122c4f2cc068e33216 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade@xxxxxxxxxxxxxxxxx>
+Date: Tue, 9 Oct 2012 11:13:45 -0400
+Subject: [PATCH 22/24] Return client window coordinates for mouse event
+ screenX/Y (for dragend, 0,0 is returned).
+
+---
+ content/events/src/nsDOMUIEvent.cpp |   15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/content/events/src/nsDOMUIEvent.cpp b/content/events/src/nsDOMUIEvent.cpp
+index fe57f52..d641f0d 100644
+--- a/content/events/src/nsDOMUIEvent.cpp
++++ b/content/events/src/nsDOMUIEvent.cpp
+@@ -135,10 +135,25 @@ nsDOMUIEvent::GetScreenPoint()
+     return nsIntPoint(0, 0);
+   }
+ 
++  bool isChrome = nsContentUtils::IsCallerChrome();
++
+   if (!((nsGUIEvent*)mEvent)->widget ) {
++    // For non-chrome callers, return 0,0 if there is no widget associated
++    // with this event, e.g., for dragend events.  Since dragend is for the
++    // drag originator and not for the receiver, it is probably not widely
++    // used (receivers get a drop event).  Therefore, returning 0,0 should
++    // not break many web pages.  Also, a few years ago Firefox returned 0,0.
++    // See:  https://bugzilla.mozilla.org/show_bug.cgi?id=466379
++    if (!isChrome)
++      return nsIntPoint(0, 0);
++
+     return mEvent->refPoint;
+   }
+ 
++  // For non-chrome callers, return client area coordinates instead.
++  if (!isChrome)
++    return GetClientPoint();
++
+   nsIntPoint offset = mEvent->refPoint + 
+     ((nsGUIEvent*)mEvent)->widget->WidgetToScreenOffset();
+   nscoord factor = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch b/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch
new file mode 100644
index 0000000..1b925e0
--- /dev/null
+++ b/src/current-patches/firefox/0023-Do-not-expose-physical-screen-info.-via-window-and-w.patch
@@ -0,0 +1,312 @@
+From d944531b020848e09ac280af11d039d992ab6461 Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade@xxxxxxxxxxxxxxxxx>
+Date: Wed, 3 Oct 2012 17:06:48 -0400
+Subject: [PATCH 23/24] Do not expose physical screen info. via window and
+ window.screen.
+
+---
+ dom/base/nsGlobalWindow.cpp |   46 +++++++++++++++++++++
+ dom/base/nsGlobalWindow.h   |    2 +
+ dom/base/nsScreen.cpp       |   92 +++++++++++++++++++++++++++++++++++++++++++
+ dom/base/nsScreen.h         |    3 +
+ 4 files changed, 143 insertions(+), 0 deletions(-)
+
+diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
+index 2c99571..982d931 100644
+--- a/dom/base/nsGlobalWindow.cpp
++++ b/dom/base/nsGlobalWindow.cpp
+@@ -3817,6 +3817,10 @@ nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
+ {
+   FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, return inner width to prevent fingerprinting.
++  if (!IsChrome())
++    return GetInnerWidth(aOuterWidth);
++
+   nsIntSize sizeCSSPixels;
+   nsresult rv = GetOuterSize(&sizeCSSPixels);
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -3830,6 +3834,10 @@ nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
+ {
+   FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, return inner height to prevent fingerprinting.
++  if (!IsChrome())
++    return GetInnerHeight(aOuterHeight);
++
+   nsIntSize sizeCSSPixels;
+   nsresult rv = GetOuterSize(&sizeCSSPixels);
+   NS_ENSURE_SUCCESS(rv, rv);
+@@ -3892,6 +3900,12 @@ nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
+ {
+   FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenX = 0;
++    return NS_OK;
++  }
++
+   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
+   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
+   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
+@@ -3933,6 +3947,12 @@ nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
+ {
+   FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenX = 0;
++    return NS_OK;
++  }
++
+   nsRect r = GetInnerScreenRect();
+   *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
+   return NS_OK;
+@@ -3943,6 +3963,12 @@ nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
+ {
+   FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenY = 0;
++    return NS_OK;
++  }
++
+   nsRect r = GetInnerScreenRect();
+   *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
+   return NS_OK;
+@@ -4064,6 +4090,12 @@ nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
+ {
+   FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
+ 
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aScreenY = 0;
++    return NS_OK;
++  }
++
+   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
+   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
+   NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
+@@ -4110,6 +4142,20 @@ nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
+   return NS_OK;
+ }
+ 
++bool
++nsGlobalWindow::IsChrome()
++{
++  bool isChrome = false;
++
++  if (mDocShell) {
++    nsRefPtr<nsPresContext> presContext;
++    mDocShell->GetPresContext(getter_AddRefs(presContext));
++    isChrome = (presContext && presContext->IsChrome());
++  }
++
++  return isChrome;
++}
++
+ // NOTE: Arguments to this function should have values scaled to
+ // CSS pixels, not device pixels.
+ nsresult
+diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
+index 2ffe4a7..863329c 100644
+--- a/dom/base/nsGlobalWindow.h
++++ b/dom/base/nsGlobalWindow.h
+@@ -744,6 +744,8 @@ protected:
+   nsresult SetOuterSize(PRInt32 aLengthCSSPixels, bool aIsWidth);
+   nsRect GetInnerScreenRect();
+ 
++  bool IsChrome();
++
+   bool IsFrame()
+   {
+     return GetParentInternal() != nsnull;
+diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp
+index 33a03dc..29a3598 100644
+--- a/dom/base/nsScreen.cpp
++++ b/dom/base/nsScreen.cpp
+@@ -82,6 +82,12 @@ nsScreen::SetDocShell(nsIDocShell* aDocShell)
+ NS_IMETHODIMP
+ nsScreen::GetTop(PRInt32* aTop)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aTop = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -94,6 +100,12 @@ nsScreen::GetTop(PRInt32* aTop)
+ NS_IMETHODIMP
+ nsScreen::GetLeft(PRInt32* aLeft)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aLeft = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -106,6 +118,14 @@ nsScreen::GetLeft(PRInt32* aLeft)
+ NS_IMETHODIMP
+ nsScreen::GetWidth(PRInt32* aWidth)
+ {
++  // For non-chrome callers, return content width to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerWidth(aWidth);
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -117,6 +137,14 @@ nsScreen::GetWidth(PRInt32* aWidth)
+ NS_IMETHODIMP
+ nsScreen::GetHeight(PRInt32* aHeight)
+ {
++  // For non-chrome callers, return content height to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerHeight(aHeight);
++  }
++
+   nsRect rect;
+   nsresult rv = GetRect(rect);
+ 
+@@ -128,6 +156,12 @@ nsScreen::GetHeight(PRInt32* aHeight)
+ NS_IMETHODIMP
+ nsScreen::GetPixelDepth(PRInt32* aPixelDepth)
+ {
++  // For non-chrome callers, always return 24 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aPixelDepth = 24;
++    return NS_OK;
++  }
++
+   nsDeviceContext* context = GetDeviceContext();
+ 
+   if (!context) {
+@@ -153,6 +187,14 @@ nsScreen::GetColorDepth(PRInt32* aColorDepth)
+ NS_IMETHODIMP
+ nsScreen::GetAvailWidth(PRInt32* aAvailWidth)
+ {
++  // For non-chrome callers, return content width to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerWidth(aAvailWidth);
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -164,6 +206,14 @@ nsScreen::GetAvailWidth(PRInt32* aAvailWidth)
+ NS_IMETHODIMP
+ nsScreen::GetAvailHeight(PRInt32* aAvailHeight)
+ {
++  // For non-chrome callers, return content height to prevent fingerprinting.
++  if (!IsChrome()) {
++    nsCOMPtr<nsIDOMWindow> win;
++    nsresult rv = GetDOMWindow(getter_AddRefs(win));
++    NS_ENSURE_SUCCESS(rv, rv);
++    return win->GetInnerHeight(aAvailHeight);
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -175,6 +225,12 @@ nsScreen::GetAvailHeight(PRInt32* aAvailHeight)
+ NS_IMETHODIMP
+ nsScreen::GetAvailLeft(PRInt32* aAvailLeft)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aAvailLeft = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -186,6 +242,12 @@ nsScreen::GetAvailLeft(PRInt32* aAvailLeft)
+ NS_IMETHODIMP
+ nsScreen::GetAvailTop(PRInt32* aAvailTop)
+ {
++  // For non-chrome callers, always return 0 to prevent fingerprinting.
++  if (!IsChrome()) {
++    *aAvailTop = 0;
++    return NS_OK;
++  }
++
+   nsRect rect;
+   nsresult rv = GetAvailRect(rect);
+ 
+@@ -237,3 +299,33 @@ nsScreen::GetAvailRect(nsRect& aRect)
+ 
+   return NS_OK;
+ }
++
++bool
++nsScreen::IsChrome()
++{
++  bool isChrome = false;
++  if (mDocShell) {
++    nsRefPtr<nsPresContext> presContext;
++    mDocShell->GetPresContext(getter_AddRefs(presContext));
++    if (presContext)
++      isChrome = presContext->IsChrome();
++  }
++
++  return isChrome;
++}
++
++nsresult
++nsScreen::GetDOMWindow(nsIDOMWindow **aResult)
++{
++  NS_ENSURE_ARG_POINTER(aResult);
++  *aResult = NULL;
++
++  if (!mDocShell)
++    return NS_ERROR_FAILURE;
++
++  nsCOMPtr<nsIDOMWindow> win = do_GetInterface(mDocShell);
++  NS_ENSURE_STATE(win);
++  win.swap(*aResult);
++
++  return NS_OK;
++}
+diff --git a/dom/base/nsScreen.h b/dom/base/nsScreen.h
+index 52eab29..d4edaa3 100644
+--- a/dom/base/nsScreen.h
++++ b/dom/base/nsScreen.h
+@@ -44,6 +44,7 @@
+ 
+ class nsIDocShell;
+ class nsDeviceContext;
++class nsIDOMWindow;
+ struct nsRect;
+ 
+ // Script "screen" object
+@@ -62,6 +63,8 @@ protected:
+   nsDeviceContext* GetDeviceContext();
+   nsresult GetRect(nsRect& aRect);
+   nsresult GetAvailRect(nsRect& aRect);
++  bool IsChrome();
++  nsresult GetDOMWindow(nsIDOMWindow **aResult);
+ 
+   nsIDocShell* mDocShell; // Weak Reference
+ };
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch b/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch
new file mode 100644
index 0000000..629a759
--- /dev/null
+++ b/src/current-patches/firefox/0024-Do-not-expose-system-colors-to-CSS-or-canvas.patch
@@ -0,0 +1,537 @@
+From 38a469e05779315cb2990be60c13fb167812e54d Mon Sep 17 00:00:00 2001
+From: Kathleen Brade <brade@xxxxxxxxxxxxxxxxx>
+Date: Thu, 4 Oct 2012 14:53:13 -0400
+Subject: [PATCH 24/24] Do not expose system colors to CSS or canvas.
+
+---
+ content/canvas/src/nsCanvasRenderingContext2D.cpp  |   36 +++-
+ .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |   51 ++++--
+ layout/style/nsCSSParser.cpp                       |   19 ++-
+ layout/style/nsRuleNode.cpp                        |    4 +-
+ widget/public/LookAndFeel.h                        |    9 +
+ widget/src/xpwidgets/nsXPLookAndFeel.cpp           |  173 +++++++++++++++++++-
+ widget/src/xpwidgets/nsXPLookAndFeel.h             |    5 +-
+ 7 files changed, 269 insertions(+), 28 deletions(-)
+
+diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+index 0cf97ce..6c47821 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
+@@ -186,8 +186,9 @@ class nsCanvasGradient : public nsIDOMCanvasGradient
+ public:
+     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
+ 
+-    nsCanvasGradient(gfxPattern* pat)
+-        : mPattern(pat)
++    nsCanvasGradient(mozilla::css::Loader* aLoader, gfxPattern* pat)
++        : mCSSLoader(aLoader)
++        , mPattern(pat)
+     {
+     }
+ 
+@@ -203,7 +204,7 @@ public:
+             return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ 
+         nscolor color;
+-        nsCSSParser parser;
++        nsCSSParser parser(mCSSLoader);
+         nsresult rv = parser.ParseColorString(nsString(colorstr),
+                                               nsnull, 0, &color);
+         if (NS_FAILED(rv))
+@@ -217,6 +218,7 @@ public:
+     NS_DECL_ISUPPORTS
+ 
+ protected:
++    mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
+     nsRefPtr<gfxPattern> mPattern;
+ };
+ 
+@@ -875,7 +877,9 @@ nsCanvasRenderingContext2D::SetStyleFromStringOrInterface(const nsAString& aStr,
+                                 HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+         // Pass the CSS Loader object to the parser, to allow parser error
+-        // reports to include the outer window ID.
++        // reports to include the outer window ID.  The parser also uses it to
++        // detect whether the caller is chrome in order to avoid exposing
++        // system colors.
+         nsCSSParser parser(document ? document->CSSLoader() : nsnull);
+         rv = parser.ParseColorString(aStr, nsnull, 0, &color);
+         if (NS_FAILED(rv)) {
+@@ -1778,7 +1782,14 @@ nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, f
+     if (!gradpat)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
++    // Pass the CSS Loader object to the parser, to allow parser error reports
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
++    nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
++                                      : nsnull;
++    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
++    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
++                                                               gradpat);
+     if (!grad)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+@@ -1800,7 +1811,14 @@ nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, f
+     if (!gradpat)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
++    // Pass the CSS Loader object to the parser, to allow parser error reports
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
++    nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
++                                      : nsnull;
++    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
++    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
++                                                               gradpat);
+     if (!grad)
+         return NS_ERROR_OUT_OF_MEMORY;
+ 
+@@ -1922,7 +1940,8 @@ nsCanvasRenderingContext2D::SetShadowColor(const nsAString& colorstr)
+                             HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+     // Pass the CSS Loader object to the parser, to allow parser error reports
+-    // to include the outer window ID.
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
+     nsCSSParser parser(document ? document->CSSLoader() : nsnull);
+     nscolor color;
+     nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color);
+@@ -3694,7 +3713,8 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
+                               HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+     // Pass the CSS Loader object to the parser, to allow parser error reports
+-    // to include the outer window ID.
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
+     nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull);
+     nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
+                                           nsnull, 0, &bgColor);
+diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+index e8dfb1e..cb5a5f5 100644
+--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
++++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+@@ -201,7 +201,10 @@ public:
+     }
+ 
+     nscolor color;
+-    nsCSSParser parser;
++    // Pass the CSS Loader object to the parser, to allow parser error reports
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
++    nsCSSParser parser(mCSSLoader);;
+     nsresult rv = parser.ParseColorString(nsString(colorstr),
+                                           nsnull, 0, &color);
+     if (NS_FAILED(rv)) {
+@@ -221,20 +224,24 @@ public:
+   }
+ 
+ protected:
+-  nsCanvasGradientAzure(Type aType) : mType(aType)
++  nsCanvasGradientAzure(mozilla::css::Loader* aLoader, Type aType)
++      : mCSSLoader(aLoader)
++      , mType(aType)
+   {}
+ 
+   nsTArray<GradientStop> mRawStops;
+   RefPtr<GradientStops> mStops;
++  mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
+   Type mType;
+ };
+ 
+ class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure
+ {
+ public:
+-  nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius,
++  nsCanvasRadialGradientAzure(mozilla::css::Loader* aLoader,
++                              const Point &aBeginOrigin, Float aBeginRadius,
+                               const Point &aEndOrigin, Float aEndRadius)
+-    : nsCanvasGradientAzure(RADIAL)
++    : nsCanvasGradientAzure(aLoader, RADIAL)
+     , mCenter1(aBeginOrigin)
+     , mCenter2(aEndOrigin)
+     , mRadius1(aBeginRadius)
+@@ -251,8 +258,9 @@ public:
+ class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure
+ {
+ public:
+-  nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd)
+-    : nsCanvasGradientAzure(LINEAR)
++  nsCanvasLinearGradientAzure(mozilla::css::Loader* aLoader,
++                              const Point &aBegin, const Point &aEnd)
++    : nsCanvasGradientAzure(aLoader, LINEAR)
+     , mBegin(aBegin)
+     , mEnd(aEnd)
+   {
+@@ -1066,8 +1074,9 @@ nsCanvasRenderingContext2DAzure::SetStyleFromStringOrInterface(const nsAString&
+     nsIDocument* document = mCanvasElement ?
+                             HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+-    // Pass the CSS Loader object to the parser, to allow parser error
+-    // reports to include the outer window ID.
++    // Pass the CSS Loader object to the parser, to allow parser error reports
++    // to include the outer window ID.  The parser also uses it to detect
++    // whether the caller is chrome in order to avoid exposing system colors.
+     nsCSSParser parser(document ? document->CSSLoader() : nsnull);
+     rv = parser.ParseColorString(aStr, nsnull, 0, &color);
+     if (NS_FAILED(rv)) {
+@@ -1855,8 +1864,14 @@ nsCanvasRenderingContext2DAzure::CreateLinearGradient(float x0, float y0, float
+     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+   }
+ 
+-  nsRefPtr<nsIDOMCanvasGradient> grad =
+-    new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1));
++  // Pass the CSS Loader object to the parser, to allow parser error reports
++  // to include the outer window ID.  The parser also uses it to detect
++  // whether the caller is chrome in order to avoid exposing system colors.
++  nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
++                                    : nsnull;
++  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
++  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasLinearGradientAzure(
++                                     cssLoader, Point(x0, y0), Point(x1, y1));
+ 
+   *_retval = grad.forget().get();
+   return NS_OK;
+@@ -1875,8 +1890,14 @@ nsCanvasRenderingContext2DAzure::CreateRadialGradient(float x0, float y0, float
+     return NS_ERROR_DOM_INDEX_SIZE_ERR;
+   }
+ 
+-  nsRefPtr<nsIDOMCanvasGradient> grad =
+-    new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1);
++  // Pass the CSS Loader object to the parser, to allow parser error reports
++  // to include the outer window ID.  The parser also uses it to detect
++  // whether the caller is chrome in order to avoid exposing system colors.
++  nsIDocument* doc = mCanvasElement ? HTMLCanvasElement()->OwnerDoc()
++                                    : nsnull;
++  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nsnull;
++  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasRadialGradientAzure(
++                            cssLoader, Point(x0, y0), r0, Point(x1, y1), r1);
+ 
+   *_retval = grad.forget().get();
+   return NS_OK;
+@@ -2024,7 +2045,8 @@ nsCanvasRenderingContext2DAzure::SetShadowColor(const nsAString& colorstr)
+                           HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+   // Pass the CSS Loader object to the parser, to allow parser error reports
+-  // to include the outer window ID.
++  // to include the outer window ID.  The parser also uses it to detect
++  // whether the caller is chrome in order to avoid exposing system colors.
+   nsCSSParser parser(document ? document->CSSLoader() : nsnull);
+   nscolor color;
+   nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color);
+@@ -3847,7 +3869,8 @@ nsCanvasRenderingContext2DAzure::DrawWindow(nsIDOMWindow* aWindow, float aX, flo
+                             HTMLCanvasElement()->OwnerDoc() : nsnull;
+ 
+   // Pass the CSS Loader object to the parser, to allow parser error reports
+-  // to include the outer window ID.
++  // to include the outer window ID.  The parser also uses it to detect
++  // whether the caller is chrome in order to avoid exposing system colors.
+   nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull);
+   nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
+                                         nsnull, 0, &bgColor);
+diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
+index ae1a474..30e179c 100644
+--- a/layout/style/nsCSSParser.cpp
++++ b/layout/style/nsCSSParser.cpp
+@@ -1216,8 +1216,25 @@ CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
+       // Should remove this limitation at some point.
+       return NS_ERROR_FAILURE;
+     }
++
++    // We do not want to expose system/native colors to content.  All callers
++    // who are working with content should ensure that they set the CSS
++    // loader (mChildLoader) so we can check here if the content is chrome.
++    bool isChrome = true;
++    if (mChildLoader) {
++      nsIDocument *doc = mChildLoader->GetDocument();
++      if (doc) {
++        nsIPresShell *presShell = doc->GetShell();
++        if (presShell) {
++          nsPresContext* presCtxt = presShell->GetPresContext();
++          if (presCtxt)
++            isChrome = presCtxt->IsChrome();
++        }
++      }
++    }
+     nscolor rgba;
+-    nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), &rgba);
++    nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), !isChrome,
++                                        &rgba);
+     if (NS_FAILED(rv)) {
+       return rv;
+     }
+diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
+index 827585a..d19524e 100644
+--- a/layout/style/nsRuleNode.cpp
++++ b/layout/style/nsRuleNode.cpp
+@@ -768,7 +768,9 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
+     PRInt32 intValue = aValue.GetIntValue();
+     if (0 <= intValue) {
+       LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
+-      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
++      bool useStandinsForNativeColors = !aPresContext->IsChrome();
++      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
++                                    useStandinsForNativeColors, &aResult))) {
+         result = true;
+       }
+     }
+diff --git a/widget/public/LookAndFeel.h b/widget/public/LookAndFeel.h
+index aae3b28..bb7be3c 100644
+--- a/widget/public/LookAndFeel.h
++++ b/widget/public/LookAndFeel.h
+@@ -445,6 +445,15 @@ public:
+   static nsresult GetColor(ColorID aID, nscolor* aResult);
+ 
+   /**
++   * This variant of GetColor() take an extra Boolean parameter that allows
++   * the caller to ask that hard-coded color values be substituted for
++   * native colors (used when it is desireable to hide system colors to
++   * avoid system fingerprinting).
++   */
++  static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors,
++                           nscolor* aResult);
++
++  /**
+    * GetInt() and GetFloat() return a int or float value for aID.  The result
+    * might be distance, time, some flags or a int value which has particular
+    * meaning.  See each document at definition of each ID for the detail.
+diff --git a/widget/src/xpwidgets/nsXPLookAndFeel.cpp b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
+index 8053432..96937ac 100644
+--- a/widget/src/xpwidgets/nsXPLookAndFeel.cpp
++++ b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
+@@ -502,6 +502,155 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
+   return false;
+ }
+ 
++bool
++nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID)
++{
++  bool result = false;
++
++  switch (aID) {
++    case eColorID_WindowBackground:
++    case eColorID_WindowForeground:
++    case eColorID_WidgetBackground:
++    case eColorID_WidgetForeground:
++    case eColorID_WidgetSelectBackground:
++    case eColorID_WidgetSelectForeground:
++    case eColorID_Widget3DHighlight:
++    case eColorID_Widget3DShadow:
++    case eColorID_TextBackground:
++    case eColorID_TextForeground:
++    case eColorID_TextSelectBackground:
++    case eColorID_TextSelectForeground:
++    case eColorID_TextSelectBackgroundDisabled:
++    case eColorID_TextSelectBackgroundAttention:
++    case eColorID_TextHighlightBackground:
++    case eColorID_TextHighlightForeground:
++    case eColorID_IMERawInputBackground:
++    case eColorID_IMERawInputForeground:
++    case eColorID_IMERawInputUnderline:
++    case eColorID_IMESelectedRawTextBackground:
++    case eColorID_IMESelectedRawTextForeground:
++    case eColorID_IMESelectedRawTextUnderline:
++    case eColorID_IMEConvertedTextBackground:
++    case eColorID_IMEConvertedTextForeground:
++    case eColorID_IMEConvertedTextUnderline:
++    case eColorID_IMESelectedConvertedTextBackground:
++    case eColorID_IMESelectedConvertedTextForeground:
++    case eColorID_IMESelectedConvertedTextUnderline:
++    case eColorID_SpellCheckerUnderline:
++      result = true;
++      break;
++    default:
++      break;
++  }
++
++  return result;
++}
++
++nscolor
++nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID)
++{
++  nscolor result = NS_RGB(0xFF, 0xFF, 0xFF);
++
++  // The stand-in colors are taken from the Windows 7 Aero theme
++  // except Mac-specific colors which are taken from Mac OS 10.7.
++  switch (aID) {
++    // CSS 2 colors:
++    case eColorID_activeborder:      result = NS_RGB(0xB4, 0xB4, 0xB4); break;
++    case eColorID_activecaption:     result = NS_RGB(0x99, 0xB4, 0xD1); break;
++    case eColorID_appworkspace:      result = NS_RGB(0xAB, 0xAB, 0xAB); break;
++    case eColorID_background:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_buttonface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_buttonhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_buttonshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
++    case eColorID_buttontext:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_captiontext:       result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_graytext:          result = NS_RGB(0x6D, 0x6D, 0x6D); break;
++    case eColorID_highlight:         result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID_highlighttext:     result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_inactiveborder:    result = NS_RGB(0xF4, 0xF7, 0xFC); break;
++    case eColorID_inactivecaption:   result = NS_RGB(0xBF, 0xCD, 0xDB); break;
++    case eColorID_inactivecaptiontext:
++      result = NS_RGB(0x43, 0x4E, 0x54); break;
++    case eColorID_infobackground:    result = NS_RGB(0xFF, 0xFF, 0xE1); break;
++    case eColorID_infotext:          result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_menu:              result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_menutext:          result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID_scrollbar:         result = NS_RGB(0xC8, 0xC8, 0xC8); break;
++    case eColorID_threeddarkshadow:  result = NS_RGB(0x69, 0x69, 0x69); break;
++    case eColorID_threedface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID_threedhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_threedlightshadow: result = NS_RGB(0xE3, 0xE3, 0xE3); break;
++    case eColorID_threedshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
++    case eColorID_window:            result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID_windowframe:       result = NS_RGB(0x64, 0x64, 0x64); break;
++    case eColorID_windowtext:        result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_buttondefault:
++      result = NS_RGB(0x69, 0x69, 0x69); break;
++    case eColorID__moz_field:        result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_fieldtext:    result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_dialog:       result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_dialogtext:   result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_dragtargetzone:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_cellhighlight:
++      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_cellhighlighttext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_html_cellhighlight:
++      result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID__moz_html_cellhighlighttext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_buttonhoverface:
++      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
++    case eColorID__moz_buttonhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menuhover:
++      result = NS_RGB(0x33, 0x99, 0xFF); break;
++    case eColorID__moz_menuhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menubartext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_menubarhovertext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_oddtreerow:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_mac_chrome_active:
++      result = NS_RGB(0xB2, 0xB2, 0xB2); break;
++    case eColorID__moz_mac_chrome_inactive:
++      result = NS_RGB(0xE1, 0xE1, 0xE1); break;
++    case eColorID__moz_mac_focusring:
++      result = NS_RGB(0x60, 0x9D, 0xD7); break;
++    case eColorID__moz_mac_menuselect:
++      result = NS_RGB(0x38, 0x75, 0xD7); break;
++    case eColorID__moz_mac_menushadow:
++      result = NS_RGB(0xA3, 0xA3, 0xA3); break;
++    case eColorID__moz_mac_menutextdisable:
++      result = NS_RGB(0x88, 0x88, 0x88); break;
++    case eColorID__moz_mac_menutextselect:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_mac_disabledtoolbartext:
++      result = NS_RGB(0x3F, 0x3F, 0x3F); break;
++    case eColorID__moz_mac_alternateprimaryhighlight:
++      result = NS_RGB(0x38, 0x75, 0xD7); break;
++    case eColorID__moz_mac_secondaryhighlight:
++      result = NS_RGB(0xD4, 0xD4, 0xD4); break;
++    case eColorID__moz_win_mediatext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_win_communicationstext:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    case eColorID__moz_nativehyperlinktext:
++      result = NS_RGB(0x00, 0x66, 0xCC); break;
++    case eColorID__moz_comboboxtext:
++      result = NS_RGB(0x00, 0x00, 0x00); break;
++    case eColorID__moz_combobox:
++      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
++    default:
++      break;
++  }
++
++  return result;
++}
++
+ //
+ // All these routines will return NS_OK if they have a value,
+ // in which case the nsLookAndFeel should use that value;
+@@ -509,7 +658,8 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
+ // platform-specific nsLookAndFeel should use its own values instead.
+ //
+ nsresult
+-nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
++nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
++                              nscolor &aResult)
+ {
+   if (!sInitialized)
+     Init();
+@@ -595,7 +745,10 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
+   }
+ #endif // DEBUG_SYSTEM_COLOR_USE
+ 
+-  if (IS_COLOR_CACHED(aID)) {
++  if (aUseStandinsForNativeColors && ColorIsNotCSSAccessible(aID))
++    aUseStandinsForNativeColors = false;
++
++  if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) {
+     aResult = sCachedColors[aID];
+     return NS_OK;
+   }
+@@ -629,6 +782,12 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
+     return NS_OK;
+   }
+ 
++  if (sUseNativeColors && aUseStandinsForNativeColors)
++  {
++    aResult = GetStandinForNativeColor(aID);
++    return NS_OK;
++  }
++
+   if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
+     if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
+          !IsSpecialColor(aID, aResult)) {
+@@ -719,7 +878,15 @@ namespace mozilla {
+ nsresult
+ LookAndFeel::GetColor(ColorID aID, nscolor* aResult)
+ {
+-  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, *aResult);
++  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, false, *aResult);
++}
++
++nsresult
++LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors,
++                      nscolor* aResult)
++{
++  return nsLookAndFeel::GetInstance()->GetColorImpl(aID,
++                                       aUseStandinsForNativeColors, *aResult);
+ }
+ 
+ // static
+diff --git a/widget/src/xpwidgets/nsXPLookAndFeel.h b/widget/src/xpwidgets/nsXPLookAndFeel.h
+index ce06575..c0ecc32 100644
+--- a/widget/src/xpwidgets/nsXPLookAndFeel.h
++++ b/widget/src/xpwidgets/nsXPLookAndFeel.h
+@@ -84,7 +84,8 @@ public:
+   // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
+   // platform-specific nsLookAndFeel should use its own values instead.
+   //
+-  nsresult GetColorImpl(ColorID aID, nscolor &aResult);
++  nsresult GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
++                        nscolor &aResult);
+   virtual nsresult GetIntImpl(IntID aID, PRInt32 &aResult);
+   virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
+ 
+@@ -111,6 +112,8 @@ protected:
+   void InitColorFromPref(PRInt32 aIndex);
+   virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult) = 0;
+   bool IsSpecialColor(ColorID aID, nscolor &aColor);
++  bool ColorIsNotCSSAccessible(ColorID aID);
++  nscolor GetStandinForNativeColor(ColorID aID);
+ 
+   static int OnPrefChanged(const char* aPref, void* aClosure);
+ 
+-- 
+1.7.5.4
+



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits