Bug 737955 - Deleting an online storage account should wipe out old credentials. Dropbox now automatically logs out after OAuth keys received. r+a=bienvenu.
--- a/mail/components/cloudfile/cloudFileAccounts.js
+++ b/mail/components/cloudfile/cloudFileAccounts.js
@@ -177,18 +177,27 @@ var cloudFileAccounts = {
getAccount: function(aKey) {
let type = Services.prefs.QueryInterface(Ci.nsIPrefBranch)
.getCharPref(ACCOUNT_ROOT + aKey + ".type");
return this._getInitedProviderForType(aKey, type);
},
removeAccount: function(aKeyOrAccount) {
let key = this._ensureKey(aKeyOrAccount);
+
let type = Services.prefs.QueryInterface(Ci.nsIPrefBranch)
.deleteBranch(ACCOUNT_ROOT + key);
+
+ // Destroy any secret tokens for this accountKey.
+ let logins = Services.logins
+ .findLogins({}, PWDMGR_HOST, null, "");
+ for each (let login in logins) {
+ if (login.username == key)
+ Services.logins.removeLogin(login);
+ }
},
get accounts() {
return [this.getAccount(key)
for each (key in this._accountKeys)
if (this.getAccount(key) != null)];
},
--- a/mail/components/cloudfile/nsDropbox.js
+++ b/mail/components/cloudfile/nsDropbox.js
@@ -28,16 +28,17 @@ const kDeletePath = "fileops/delete/?roo
const kAppKey = "7xkhuze09iqkghm";
const kAppSecret = "3i5kwjkt74rkkjc";
const kSharesPath = "shares/sandbox/";
const kFilesPutPath = "files_put/sandbox/";
var gServerUrl = "https://api.dropbox.com/1/";
var gContentUrl = "https://api-content.dropbox.com/1/";
var gAuthUrl = "https://www.dropbox.com/1/";
+var gLogoutUrl = "https://www.dropbox.com/logout";
function wwwFormUrlEncode(aStr) {
return encodeURIComponent(aStr).replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A');
}
@@ -406,16 +407,17 @@ nsDropbox.prototype = {
/**
* This function is used by our testing framework to override the default
* URL's that nsDropbox connects to.
*/
overrideUrls : function nsDropbox_overrideUrls(aNumUrls, aUrls) {
gServerUrl = aUrls[0];
gContentUrl = aUrls[1];
gAuthUrl = aUrls[2];
+ gLogoutUrl = aUrls[3];
},
/**
* logon to the dropbox account.
*
* @param successCallback - called if logon is successful
* @param failureCallback - called back on error.
* @param aWithUI if false, logon fails if it would have needed to put up UI.
@@ -425,24 +427,49 @@ nsDropbox.prototype = {
logon: function nsDropbox_logon(successCallback, failureCallback, aWithUI) {
let authToken = this._cachedAuthToken;
let authSecret = this._cachedAuthSecret;
if (!aWithUI && (!authToken.length || !authSecret.length)) {
failureCallback();
return;
}
- this._connection = new OAuth(this.displayName, gServerUrl, gAuthUrl, authToken, authSecret,
- kAppKey, kAppSecret);
+ this._connection = new OAuth(this.displayName, gServerUrl, gAuthUrl,
+ authToken, authSecret, kAppKey, kAppSecret);
this._connection.connect(
function () {
this.log.info("success connecting");
this._loggedIn = true;
this._cachedAuthToken = this._connection.token;
this._cachedAuthSecret = this._connection.tokenSecret;
+
+ // Attempt to end the session we just opened to get these tokens...
+ let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ .createInstance(Ci.nsIXMLHttpRequest);
+ xhr.mozBackgroundRequest = true;
+ xhr.open("GET", gLogoutUrl);
+ xhr.onerror = function(aProgressEvent) {
+ this.log.error("Could not end authorization session!");
+ this.log.error("Status was: " + aProgressEvent.target.status);
+ this.log.error("Message was: " + aProgressEvent.target.statusText);
+ }.bind(this);
+
+ xhr.onload = function(aRequest) {
+ if (aRequest.target.status == 200)
+ this.log.info("Successfully ended authorization session.");
+ else {
+ this.log.error("Could not end authorization session!");
+ this.log.error("Status was: " + aRequest.target.status);
+ this.log.error("Message was: " + aRequest.target.statusText);
+ }
+ }.bind(this);
+
+ this.log.info("Sending logout request to: " + gLogoutUrl);
+ xhr.send();
+
successCallback();
}.bind(this),
function () {
this.log.info("failed connecting");
failureCallback();
}.bind(this),
true);
},
--- a/mail/test/mozmill/cloudfile/test-cloudfile-backend-dropbox.js
+++ b/mail/test/mozmill/cloudfile/test-cloudfile-backend-dropbox.js
@@ -172,17 +172,17 @@ function test_deleting_uploads() {
gServer.planForGetFileURL(kFilename,
{url: "http://www.example.com/someFile"});
let requestObserver = gObsManager.create("test_deleting_uploads - upload 1");
provider.uploadFile(file, requestObserver);
mc.waitFor(function() requestObserver.success);
// Try deleting a file
let obs = new ObservationRecorder();
- obs.planFor(kDeleteFile)
+ obs.planFor(kDeleteFile);
Services.obs.addObserver(obs, kDeleteFile, false);
gServer.planForDeleteFile(kFilename);
let deleteObserver = gObsManager.create("test_deleting_uploads - delete 1");
provider.deleteFile(file, deleteObserver);
mc.waitFor(function() deleteObserver.success);
// Check to make sure the file was deleted on the server
@@ -207,8 +207,22 @@ function test_create_existing_account()
done = true;
},
}
provider.createExistingAccount(myObs);
mc.waitFor(function() done);
}
+/**
+ * Test that completing the OAuth procedure results in an attempt to logout.
+ */
+function test_oauth_complete_causes_logout() {
+ let provider = gServer.getPreparedBackend("someNewAccount");
+ let dummyObs = gObsManager.create("test_oauth_complete_causes_logout");
+ let obs = new ObservationRecorder();
+ obs.planFor(kLogout);
+ Services.obs.addObserver(obs, kLogout, false);
+ provider.createExistingAccount(dummyObs);
+ mc.waitFor(function() dummyObs.success);
+ mc.waitFor(function() 1 == obs.numSightings(kLogout));
+ Services.obs.removeObserver(obs, kLogout);
+}
--- a/mail/test/mozmill/shared-modules/test-cloudfile-backend-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-cloudfile-backend-helpers.js
@@ -11,29 +11,31 @@ const MODULE_NAME = 'cloudfile-backend-h
const RELATIVE_ROOT = '../shared-modules';
const MODULE_REQUIRES = ['folder-display-helpers'];
const kUserAuthRequested = "cloudfile:auth";
const kUserDataRequested = "cloudfile:user";
const kUploadFile = "cloudfile:uploadFile";
const kGetFileURL = "cloudfile:getFileURL";
const kDeleteFile = "cloudfile:deleteFile";
+const kLogout = "cloudfile:logout";
Cu.import('resource://mozmill/stdlib/os.js', os);
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
var fdh;
function installInto(module) {
setupModule(module);
module.kUserAuthRequested = kUserAuthRequested;
module.kUserDataRequested = kUserDataRequested;
module.kUploadFile = kUploadFile;
module.kGetFileURL = kGetFileURL;
module.kDeleteFile = kDeleteFile;
+ module.kLogout = kLogout;
module.SimpleRequestObserverManager = SimpleRequestObserverManager;
module.SimpleRequestObserver = SimpleRequestObserver;
}
function setupModule(module) {
fdh = collector.getModule('folder-display-helpers');
}
--- a/mail/test/mozmill/shared-modules/test-cloudfile-dropbox-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-cloudfile-dropbox-helpers.js
@@ -25,16 +25,18 @@ const kContentURL = kServerRoot + kConte
const kAuthURL = kServerRoot + kAuthPath;
const kOAuthTokenPath = "oauth/request_token";
const kOAuthAuthorizePath = "oauth/authorize";
const kOAuthAccessTokenPath = "oauth/access_token";
const kUserInfoPath = "account/info";
const kPutFilePath = "files_put/sandbox/";
const kSharesPath = "shares/sandbox/";
const kDeletePath = "fileops/delete/";
+const kLogoutPath = "/logout";
+const kLogoutURL = kServerRoot + kLogoutPath;
const kDefaultConfig = {
port: kDefaultServerPort
}
const kAuthTokenString = "oauth_token=requestkey&oauth_token_secret=requestsecret";
const kDefaultUser = {
@@ -99,17 +101,17 @@ function MockDropboxServer() {}
MockDropboxServer.prototype = {
_server: null,
_toDelete: [],
getPreparedBackend: function MDBS_getPreparedBackend(aAccountKey) {
let dropbox = Cc["@mozilla.org/mail/dropbox;1"]
.getService(Ci.nsIMsgCloudFileProvider);
- let urls = [kServerURL, kContentURL, kAuthURL];
+ let urls = [kServerURL, kContentURL, kAuthURL, kLogoutURL];
dropbox.overrideUrls(urls.length, urls);
dropbox.init(aAccountKey);
return dropbox;
},
init: function MDBS_init(aConfig) {
this._config = kDefaultConfig;
@@ -242,16 +244,20 @@ MockDropboxServer.prototype = {
kAuthTokenString);
this._server.registerPathHandler(kServerPath + kOAuthTokenPath,
authFunc);
this._server.registerPathHandler(kServerPath + kOAuthAccessTokenPath,
authFunc);
this._server.registerPathHandler(kAuthPath + kOAuthAuthorizePath,
this._authHandler);
+
+ let logoutFunc = this._noteAndReturnString("cloudfile:logout", "",
+ "Successfully logged out!");
+ this._server.registerPathHandler(kLogoutPath, logoutFunc);
},
_authHandler: function MDBS__authHandler(meta, response) {
response.setStatusLine(null, 302, "Found");
response.setHeader("Location", "http://oauthcallback.local/",
false);
},
}