fix(dashboard): temporary accounts can delete themselves again

The server reports oidc_only for every passwordless account, temporary
ones included, so the shared user-protected helper sent a temporary
account into the linked-provider sign-in, which has no URL for it, and the
deletion never went out. Temporary accounts post directly, as the route
admits them without credentials.
This commit is contained in:
Nariman Jelveh committed 2026-10-22 16:59:08 -07:00
1 parent df2c5978b1
commit 8bcfd0c620
3 files changed
+18 -2

No files matched your search

@@ -226,7 +226,8 @@ describe('create API token', () => {
describe('delete account', () => {
it('asks a temporary account to type confirm', async () => {
window.user = { username: 'guest', is_temp: true };
// What the server sends for a temporary account: no password, so `oidc_only` too.
window.user = { username: 'guest', is_temp: true, oidc_only: true };
fetch.mockResolvedValueOnce(reply(200, { success: true }));
dialogs.openDeleteAccountDialog();
@@ -235,6 +236,7 @@ describe('delete account', () => {
expect(fetch).not.toHaveBeenCalled();
await submitWith({ confirm: ' Confirm ' });
expect(openRevalidatePopup).not.toHaveBeenCalled();
expect(bodyOf(0)).toEqual({});
expect(window.logout).toHaveBeenCalled();
});
+3 -1
View File
@@ -76,7 +76,9 @@ export default async function postUserProtected (route, body, { password, onReva
};
const revalidateFailed = () => ({ ok: false, data: {}, message: i18n('revalidate_failed', [], false) });
if ( window.user?.oidc_only && ! password ) {
// A temporary account has no password either, but no linked provider: the
// routes that admit it (deleting it) need no proof of identity at all.
if ( window.user?.oidc_only && ! window.user.is_temp && ! password ) {
if ( ! await revalidate() ) return revalidateFailed();
return settle(await post(body));
}
@@ -65,6 +65,18 @@ describe('postUserProtected', () => {
expect(window.handleReauthRequired).toHaveBeenCalled();
});
// The server reports `oidc_only` for any passwordless account, temporary ones included.
it('posts straight away for a temporary account, with no sign-in popup', async () => {
window.user = { oidc_only: true, is_temp: true };
fetch.mockResolvedValueOnce(reply(200, { success: true }));
const result = await postUserProtected('delete-own-user', {});
expect(openRevalidatePopup).not.toHaveBeenCalled();
expect(bodyOf(0)).toEqual({});
expect(result).toEqual({ ok: true, data: { success: true } });
});
it('signs a provider-only account in first and sends no password', async () => {
window.user = { oidc_only: true, oidc_revalidate_url: 'https://puter.test/revalidate' };
const onRevalidate = vi.fn();