fix(accounts): keep invalid accounts disabled

Require the silent activation refresh to return a valid account state before persisting the enabled setting. Invalid or expired sessions now roll back the optimistic toggle and cannot trigger an interactive login from active downloads.
This commit is contained in:
Sucukdeluxe
2026-08-15 21:43:30 +02:00
parent 82303dc94a
commit 31560cfbe0
3 changed files with 21 additions and 7 deletions
+4 -4
View File
@@ -2861,7 +2861,7 @@ export function App(): ReactElement {
const persistAccountToggle = async (
nextDraft: RendererSettingsDraft,
refreshBeforePersist?: () => Promise<void>
refreshBeforePersist?: () => ReturnType<typeof window.rd.checkAccountCredentials>
): Promise<RendererSettings> => {
const previousDraft = settingsDraft;
const previousDirty = settingsDirtyRef.current;
@@ -2905,7 +2905,7 @@ export function App(): ReactElement {
};
await persistAccountToggle(
nextDraft,
enabled ? async () => { await window.rd.checkAccountCredentials({ kind: "debridlink-api", accountId: key.id }); } : undefined
enabled ? () => window.rd.checkAccountCredentials({ kind: "debridlink-api", accountId: key.id }) : undefined
);
showToast(
enabled
@@ -2953,7 +2953,7 @@ export function App(): ReactElement {
megaDebridApiDisabledAccountIds: apiDisabledIds,
megaDebridWebDisabledAccountIds: webDisabledIds
}, enabled
? async () => { await window.rd.checkAccountCredentials({ kind, accountId }); }
? () => window.rd.checkAccountCredentials({ kind, accountId })
: undefined
);
showToast(enabled ? "Account aktiviert" : "Account deaktiviert", 2000);
@@ -3010,7 +3010,7 @@ export function App(): ReactElement {
disabledProviders: nextState.disabledProviders,
realDebridDisabledAccountIds: nextState.disabledAccountIds
}, enabled
? async () => { await window.rd.checkAccountCredentials({ kind, accountId }); }
? () => window.rd.checkAccountCredentials({ kind, accountId })
: undefined
);
showToast(enabled ? "Account aktiviert" : "Account deaktiviert", 2000);
+5 -2
View File
@@ -146,11 +146,14 @@ export async function runOptimisticAccountUpdate<T>(
}
export async function runAccountEnableRefresh<T>(
refresh: (() => Promise<void>) | undefined,
refresh: (() => Promise<{ valid: boolean; message?: string }>) | undefined,
persist: () => Promise<T>
): Promise<T> {
if (refresh) {
await refresh();
const status = await refresh();
if (!status.valid) {
throw new Error(status.message || "Accountprüfung fehlgeschlagen");
}
}
return persist();
}
+12 -1
View File
@@ -141,7 +141,7 @@ describe("account activation refresh", () => {
const events: string[] = [];
await runAccountEnableRefresh(
async () => { events.push("check"); },
async () => { events.push("check"); return { valid: true, message: "Premium aktiv" }; },
async () => { events.push("persist"); }
);
@@ -158,4 +158,15 @@ describe("account activation refresh", () => {
expect(events).toEqual(["persist"]);
});
it("does not enable an account whose silent refresh is invalid", async () => {
const events: string[] = [];
await expect(runAccountEnableRefresh(
async () => { events.push("check"); return { valid: false, message: "Sitzung abgelaufen" }; },
async () => { events.push("persist"); }
)).rejects.toThrow("Sitzung abgelaufen");
expect(events).toEqual(["check"]);
});
});