From 42a61f8868f183108ac3da4d99611e3dc343eac2 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Tue, 28 Jul 2026 20:49:06 -0400 Subject: [PATCH] Fix OAuth-secret reveal modal race in the resource modal (#123) saveResource() called app.modal.close() then, after an intervening await loadResources(), conditionally app.modal.open() to show a newly created OAuth client's secret. app.modal is a singleton -- close() immediately followed by open() in the same tick collides with Bootstrap's hide-transition guard (show() silently no-ops while _isTransitioning is still true from the just-started hide()). The await made this race unlikely to lose in practice, but not guaranteed to -- found while fixing the same bug (with no such await, so guaranteed to lose) in jump-host and proxy's API-token create flows. Now the resource-edit modal is only closed when we're NOT about to immediately show the OAuth secret; app.modal.open() alone already overwrites the (already-visible) modal's content in place, no close() needed first. --- nodejs/views/directory.ejs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nodejs/views/directory.ejs b/nodejs/views/directory.ejs index e9aa7b6..c2fd2dc 100644 --- a/nodejs/views/directory.ejs +++ b/nodejs/views/directory.ejs @@ -756,11 +756,19 @@ res = await app.api.post('directory-admin/resources', data); } - app.modal.close(); await loadResources(); if (!id && data.kind === 'oauth' && res.results && res.results._raw_secret) { + // Deliberately no app.modal.close() before this -- app.modal is a + // singleton, and close() immediately followed by open() in the same + // tick collides with Bootstrap's hide-transition guard (show() + // silently no-ops while _isTransitioning is still true from the + // just-started hide()). open() alone already overwrites the + // (already-visible) modal's content in place. The await above made + // this race unlikely to lose in practice, but not guaranteed to. app.modal.open({title: 'OAuth Secret', bodyHtml: 'Save this client secret, it will not be shown again:

' + res.results._raw_secret + ''}); + } else { + app.modal.close(); } } catch (err) { console.error(err);