Revoke the server API key if it can't be stored locally

The login session creates a key on the server before we try to store it,
so each attempt that failed to save the key left an active key behind.
This commit is contained in:
Dan Stillman 2026-08-31 10:33:02 -04:00
parent c19177a469
commit 30425e024d
2 changed files with 28 additions and 0 deletions

View file

@ -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;

View file

@ -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);