fix: default permissions to true on API failure to prevent UI hiding
- When the permission check API call fails (timeout, network error, etc.), permissions now default to true instead of false - This prevents UI elements like the WiFi tab from disappearing when the permission check has a transient failure - The API still enforces access server-side, so no security impact - Added __checkFailed flag to PermissionMap for observability
This commit is contained in:
@@ -51,12 +51,14 @@ describe("permissions helpers", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("defaults requested permissions to false on API error", async () => {
|
||||
it("defaults requested permissions to true on API error and marks __checkFailed", async () => {
|
||||
mockCheckPermissions.mockRejectedValueOnce(new Error("request failed"));
|
||||
|
||||
const result = await checkPermissions("token", ["a", "b"]);
|
||||
|
||||
expect(result).toEqual({ a: false, b: false });
|
||||
expect(result.a).toBe(true);
|
||||
expect(result.b).toBe(true);
|
||||
expect(result.__checkFailed).toBe(true);
|
||||
});
|
||||
|
||||
it("hasPermission returns true only for explicit true values", () => {
|
||||
|
||||
+13
-6
@@ -1,6 +1,9 @@
|
||||
import { optima } from "$lib";
|
||||
|
||||
export type PermissionMap = Record<string, boolean>;
|
||||
export type PermissionMap = Record<string, boolean> & {
|
||||
/** Set to `true` when the permission check itself failed (API error, timeout, etc.) */
|
||||
__checkFailed?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check multiple permissions for the current user and return a map of
|
||||
@@ -34,11 +37,15 @@ export async function checkPermissions(
|
||||
}, {});
|
||||
} catch (err) {
|
||||
console.error("Permission check failed:", err);
|
||||
// Default every requested permission to false on failure
|
||||
return permissions.reduce<PermissionMap>((map, p) => {
|
||||
map[p] = false;
|
||||
return map;
|
||||
}, {});
|
||||
// Default every requested permission to true on failure so the UI
|
||||
// doesn't hide features that the user may actually be allowed to use.
|
||||
// The API will still enforce access if the user truly lacks permission.
|
||||
const map = permissions.reduce<PermissionMap>((m, p) => {
|
||||
m[p] = true;
|
||||
return m;
|
||||
}, {} as PermissionMap);
|
||||
map.__checkFailed = true;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,14 +85,19 @@
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<form action="?/login" method="POST" onsubmit={handleSubmit} use:enhance={() => {
|
||||
// Called when the form action response comes back from the server
|
||||
return async ({ update }) => {
|
||||
formActionDone = true;
|
||||
$loading = false;
|
||||
await update();
|
||||
};
|
||||
}}>
|
||||
<form
|
||||
action="?/login"
|
||||
method="POST"
|
||||
onsubmit={handleSubmit}
|
||||
use:enhance={() => {
|
||||
// Called when the form action response comes back from the server
|
||||
return async ({ update }) => {
|
||||
formActionDone = true;
|
||||
$loading = false;
|
||||
await update();
|
||||
};
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="callbackKey" value={uriData.callbackKey} />
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
Reference in New Issue
Block a user