diff --git a/chrome/content/zotero/preferences/preferences_account.jsx b/chrome/content/zotero/preferences/preferences_account.jsx index f945c4121b..8efe289f30 100644 --- a/chrome/content/zotero/preferences/preferences_account.jsx +++ b/chrome/content/zotero/preferences/preferences_account.jsx @@ -237,6 +237,17 @@ Zotero_Preferences.Sync = { await Zotero.Sync.Runner.checkLoginSession(sessionToken, result); } catch (e) { + // The session already created a key on the server, so revoke it rather than + // leaving an active key we can't use + if (result.apiKey) { + try { + await Zotero.Sync.Runner.getAPIClient({ apiKey: result.apiKey }) + .deleteAPIKey(); + } + catch (e2) { + Zotero.logError(e2); + } + } this._pendingSessionToken = null; this._showLoginDefault(); throw e; diff --git a/test/tests/preferences_accountTest.js b/test/tests/preferences_accountTest.js index 66ec046a3d..9b3531ec32 100644 --- a/test/tests/preferences_accountTest.js +++ b/test/tests/preferences_accountTest.js @@ -116,6 +116,23 @@ describe("Account Preferences", function () { }); + it("should revoke the API key when it can't be stored locally", async function () { + var setAPIKeyStub = sinon.stub(Zotero.Sync.Data.Local, 'setAPIKey') + .rejects(new Error("User canceled OS unlock entry")); + try { + let e = await getPromiseError(performLogin("Username")); + assert.ok(e); + assert.isTrue(deleteAPIKey.calledOnce); + assert.equal(deleteAPIKey.firstCall.thisValue.apiKey, apiKey); + assert.equal(doc.querySelector('.account-login-default').hidden, false); + assert.equal(doc.querySelector('.account-login-pending').hidden, true); + } + finally { + setAPIKeyStub.restore(); + } + }); + + it("should delete API key and display auth form when 'Unlink Account' clicked", async function () { await performLogin("Username"); assert.equal(await Zotero.Sync.Data.Local.getAPIKey(), apiKey);