Bug 769285 - Use separate access tokens for private and public geolocation requests. r=dougt
☠☠ backed out by 9659f41bda78 ☠ ☠
authorJosh Matthews <josh@joshmatthews.net>
Wed, 28 Nov 2012 11:20:20 -0500
changeset 114371 7c45205a61a0d6681f5302d4670bc74d9bed6636
parent 114370 8a84d0ad94c1a7c08a8d4b140858f214f441ef19
child 114372 9c0bd1afbf063a651899ea2275442f8bfe83986d
push idunknown
push userunknown
push dateunknown
reviewersdougt
bugs769285
milestone20.0a1
Bug 769285 - Use separate access tokens for private and public geolocation requests. r=dougt
browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
dom/src/geolocation/nsGeolocation.cpp
dom/src/geolocation/nsGeolocation.h
dom/system/GPSDGeolocationProvider.js
dom/system/NetworkGeolocationProvider.js
dom/system/gonk/GonkGPSGeolocationProvider.cpp
xpcom/system/nsIGeolocationProvider.idl
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -438,20 +438,16 @@ PrivateBrowsingService.prototype = {
       case "quit-application-granted":
         this._unload();
         break;
       case "private-browsing":
         // clear all auth tokens
         let sdr = Cc["@mozilla.org/security/sdr;1"].
                   getService(Ci.nsISecretDecoderRing);
         sdr.logoutAndTeardown();
-    
-        try {
-          this._prefs.deleteBranch("geo.wifi.access_token.");
-        } catch (ex) {}
 
         if (!this._inPrivateBrowsing) {
           // Clear the error console
           let consoleService = Cc["@mozilla.org/consoleservice;1"].
                                getService(Ci.nsIConsoleService);
           consoleService.logStringMessage(null); // trigger the listeners
           consoleService.reset();
         }
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -387,20 +387,25 @@ nsGeolocationRequest::Cancel()
 
   NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGeolocationRequest::Allow()
 {
-  nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
+  nsCOMPtr<nsIDOMWindow> window;
+  GetWindow(getter_AddRefs(window));
+  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
+  bool isPrivate = loadContext && loadContext->UsePrivateBrowsing();
 
   // Kick off the geo device, if it isn't already running
-  nsresult rv = gs->StartDevice();
+  nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
+  nsresult rv = gs->StartDevice(isPrivate);
 
   if (NS_FAILED(rv)) {
     // Location provider error
     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMGeoPosition> lastPosition = gs->GetCachedPosition();
@@ -914,17 +919,17 @@ nsGeolocationService::SetCachedPosition(
 
 nsIDOMGeoPosition*
 nsGeolocationService::GetCachedPosition()
 {
   return mLastPosition;
 }
 
 nsresult
-nsGeolocationService::StartDevice()
+nsGeolocationService::StartDevice(bool aRequestPrivate)
 {
   if (!sGeoEnabled || sGeoInitPending) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // we do not want to keep the geolocation devices online
   // indefinitely.  Close them down after a reasonable period of
   // inactivivity
@@ -939,17 +944,17 @@ nsGeolocationService::StartDevice()
   // Start them up!
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs) {
     return NS_ERROR_FAILURE;
   }
 
   for (int32_t i = 0; i < mProviders.Count(); i++) {
     mProviders[i]->Startup();
-    mProviders[i]->Watch(this);
+    mProviders[i]->Watch(this, aRequestPrivate);
     obs->NotifyObservers(mProviders[i],
                          "geolocation-device-events",
                          NS_LITERAL_STRING("starting").get());
   }
 
   return NS_OK;
 }
 
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -120,17 +120,17 @@ public:
   void AddLocator(nsGeolocation* locator);
   void RemoveLocator(nsGeolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
   nsIDOMGeoPosition* GetCachedPosition();
   PRBool IsBetterPosition(nsIDOMGeoPosition *aSomewhere);
 
   // Find and startup a geolocation device (gps, nmea, etc.)
-  nsresult StartDevice();
+  nsresult StartDevice(bool aRequestPrivate);
 
   // Stop the started geolocation device (gps, nmea, etc.)
   void     StopDevice();
 
   // create, or reinitalize the callback timer
   void     SetDisconnectTimer();
 
   // request higher accuracy, if possible
--- a/dom/system/GPSDGeolocationProvider.js
+++ b/dom/system/GPSDGeolocationProvider.js
@@ -116,17 +116,17 @@ GPSDProvider.prototype = {
   
   shutdown: function() {
     LOG("shutdown called\n"); 
     this.outputStream.close();
     this.inputStream.close();
     this.transport.close(Components.results.NS_OK);
   },
   
-  watch: function(c) {
+  watch: function(c, isPrivate) {
     LOG("watch called\n");    
     try {
         // Go into "watcher" mode
         var mode = '?WATCH={"enable":true,"json":true}';
         this.outputStream.write(mode, mode.length);
     } catch (e) { return; }
 
     var dataListener = {
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -11,16 +11,19 @@ Components.utils.import("resource://gre/
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 let gLoggingEnabled = false;
 let gTestingEnabled = false;
 
+let gPrivateAccessToken = '';
+let gPrivateAccessTime = 0;
+
 function LOG(aMsg) {
   if (gLoggingEnabled)
   {
     aMsg = "*** WIFI GEO: " + aMsg + "\n";
     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
     dump(aMsg);
   }
 }
@@ -53,29 +56,37 @@ WifiGeoPositionObject.prototype = {
   QueryInterface:   XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition]),
 
   // Class Info is required to be able to pass objects back into the DOM.
   classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPosition],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "wifi geo location position object"}),
 };
 
+function privateBrowsingObserver(aSubject, aTopic, aData) {
+  gPrivateAccessToken = '';
+  gPrivateAccessTime = 0;
+}
+
 function WifiGeoPositionProvider() {
   try {
     gLoggingEnabled = Services.prefs.getBoolPref("geo.wifi.logging.enabled");
   } catch (e) {}
 
   try {
     gTestingEnabled = Services.prefs.getBoolPref("geo.wifi.testing");
   } catch (e) {}
 
   this.wifiService = null;
   this.timer = null;
   this.hasSeenWiFi = false;
   this.started = false;
+  this.lastRequestPrivate = false;
+
+  Services.obs.addObserver(privateBrowsingObserver, "last-pb-context-exited", false);
 }
 
 WifiGeoPositionProvider.prototype = {
   classID:          Components.ID("{77DA64D3-7458-4920-9491-86CC9914F904}"),
   QueryInterface:   XPCOMUtils.generateQI([Ci.nsIGeolocationProvider,
                                            Ci.nsIWifiListener,
                                            Ci.nsITimerCallback]),
   startup:  function() {
@@ -91,26 +102,28 @@ WifiGeoPositionProvider.prototype = {
     // always sending data.  It doesn't matter if we have an access point or not.
     this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     if (!gTestingEnabled)
       this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
     else
       this.timer.initWithCallback(this, 200, this.timer.TYPE_REPEATING_SLACK);
   },
 
-  watch: function(c) {
+  watch: function(c, requestPrivate) {
     LOG("watch called");
     if (!this.wifiService) {
       this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
       this.wifiService.startWatching(this);
+      this.lastRequestPrivate = requestPrivate;
     }
     if (this.hasSeenWiFi) {
       this.hasSeenWiFi = false;
       this.wifiService.stopWatching(this);
       this.wifiService.startWatching(this);
+      this.lastRequestPrivate = requestPrivate;
     }
   },
 
   shutdown: function() { 
     LOG("shutdown called");
     if(this.wifiService) {
       this.wifiService.stopWatching(this);
       this.wifiService = null;
@@ -133,21 +146,30 @@ WifiGeoPositionProvider.prototype = {
   setHighAccuracy: function(enable) {
   },
 
   getAccessTokenForURL: function(url)
   {
     // check to see if we have an access token:
     let accessToken = "";
     try {
-      let accessTokenPrefName = "geo.wifi.access_token." + url;
-      accessToken = Services.prefs.getCharPref(accessTokenPrefName);
+      if (this.lastRequestPrivate) {
+        accessToken = gPrivateAccessToken;
+      } else {
+        let accessTokenPrefName = "geo.wifi.access_token." + url;
+        accessToken = Services.prefs.getCharPref(accessTokenPrefName);
+      }
 
       // check to see if it has expired
-      let accessTokenDate = Services.prefs.getIntPref(accessTokenPrefName + ".time");
+      let accessTokenDate;
+      if (this.lastRequestPrivate) {
+        accessTokenDate = gPrivateAccessTime;
+      } else {
+        Services.prefs.getIntPref(accessTokenPrefName + ".time");
+      }
       
       let accessTokenInterval = 1209600;  // seconds in 2 weeks
       try {
         accessTokenInterval = Services.prefs.getIntPref("geo.wifi.access_token.recycle_interval");
       } catch (e) {}
             
       if ((Date.now() / 1000) - accessTokenDate > accessTokenInterval)
         accessToken = "";
@@ -247,27 +269,36 @@ WifiGeoPositionProvider.prototype = {
         }
 
         // Check to see if we have a new access token
         let newAccessToken = response.access_token;
         if (newAccessToken !== undefined)
         {
           let accessToken = "";
           let accessTokenPrefName = "geo.wifi.access_token." + providerUrlBase;
-          try { accessToken = Services.prefs.getCharPref(accessTokenPrefName); } catch (e) {}
+          if (this.lastRequestPrivate) {
+            accessTokenPrefName = gPrivateAccessToken;
+          } else {
+            try { accessToken = Services.prefs.getCharPref(accessTokenPrefName); } catch (e) {}
+          }
 
           if (accessToken != newAccessToken) {
             // no match, lets cache
-              LOG("New Access Token: " + newAccessToken + "\n" + accessTokenPrefName);
+            LOG("New Access Token: " + newAccessToken + "\n" + accessTokenPrefName);
+            if (this.lastRequestPrivate) {
+              gPrivateAccessToken = newAccessToken;
+              gPrivateAccessTime = nowInSeconds();
+            } else {
               try {
                 Services.prefs.setIntPref(accessTokenPrefName + ".time", nowInSeconds());
                 Services.prefs.setCharPref(accessTokenPrefName, newAccessToken);
               } catch (x) {
                   // XXX temporary hack for bug 575346 to allow geolocation to function
               }
+            }
           }
         }
     }, false);
 
     LOG("************************************* ------>>>> sending.");
     xhr.send(null);
   },
 
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp
+++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp
@@ -580,17 +580,17 @@ GonkGPSGeolocationProvider::Startup()
   mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init),
                         NS_DISPATCH_NORMAL);
 
   mStarted = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
+GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback, bool aPrivate)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mLocationCallback = aCallback;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/xpcom/system/nsIGeolocationProvider.idl
+++ b/xpcom/system/nsIGeolocationProvider.idl
@@ -30,30 +30,33 @@ interface nsIGeolocationUpdate : nsISupp
 
 
 /**
  * Interface provides location information to the nsGeolocator
  * via the nsIDOMGeolocationCallback interface.  After
  * startup is called, any geo location change should call
  * callback.update().
  */
-[scriptable, uuid(483BE98B-F747-490A-8AF1-53146D2D5373)]
+[scriptable, uuid(d32b87b3-fe96-4f42-81ab-2f39f7ec43ff)]
 interface nsIGeolocationProvider : nsISupports {
 
   /**
    * Start up the provider.  This is called before any other
    * method.  may be called multiple times.
    */
   void startup();
 
   /**
    * watch
-   * When a location change is observed, notify the callback
+   * When a location change is observed, notify the callback. The privacy
+   * argument informs the provider whether the initiating request came from
+   * a private context; it is up to the provider to use that information
+   * in a sensible manner.
    */
-  void watch(in nsIGeolocationUpdate callback);
+  void watch(in nsIGeolocationUpdate callback, in boolean requestPrivate);
 
   /**
    * shutdown
    * Shuts down the location device.
    */
   void shutdown();
 
   /**