setup: Use the number of completed password changes for race detection.

The start time of the last password change was the wrong time to use,
because we could start a password change, start another request,
finish the password change, and then observe that the other request
failed due to the password change.

We could use the end time, but a counter is more robust to
sub-millisecond race conditions.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2021-04-01 12:08:36 -07:00
committed by Tim Abbott
parent b8eb3d676a
commit 2595fa88a0

View File

@@ -7,12 +7,13 @@ import * as util from "./util";
// Miscellaneous early setup.
export let password_change_in_progress = false;
export let last_password_change_start_time = null;
export let password_changes = 0;
const xhr_password_changes = new WeakMap();
export function set_password_change_in_progress(value) {
password_change_in_progress = value;
if (value) {
last_password_change_start_time = new Date();
if (!value) {
password_changes += 1;
}
}
@@ -46,21 +47,17 @@ $(() => {
return this.outerWidth(...args) || 0;
};
// Attach the time when the request was initiated to its XHR
// object. This allows us to detect race situations where a
// password change completed before we got a response that failed
// due to the ongoing password change.
// Remember the number of completed password changes when the
// request was initiated. This allows us to detect race
// situations where a password change occurred before we got a
// response that failed due to the ongoing password change.
$(document).ajaxSend((event, xhr) => {
xhr.initiatedTime = new Date();
xhr_password_changes.set(xhr, password_changes);
});
// For some reason, jQuery wants this to be attached to an element.
$(document).ajaxError((event, xhr) => {
if (
password_change_in_progress ||
(last_password_change_start_time &&
xhr.initiatedTime <= last_password_change_start_time)
) {
if (password_change_in_progress || xhr_password_changes.get(xhr) !== password_changes) {
// The backend for handling password change API requests
// will replace the user's session; this results in a
// brief race where any API request will fail with a 401