docs: update access control spec — fail-closed on corrupted permissions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,12 +33,12 @@ interface ParsedUser {
|
||||
id: number;
|
||||
name: string;
|
||||
role: 'admin' | 'viewer';
|
||||
allowedMuseums: string[]; // [] = unrestricted
|
||||
allowedChannels: string[]; // [] = unrestricted
|
||||
allowedMuseums: string[] | null; // [] = unrestricted, null = parse error (show nothing)
|
||||
allowedChannels: string[] | null; // [] = unrestricted, null = parse error (show nothing)
|
||||
}
|
||||
```
|
||||
|
||||
**Convention:** empty array = full access. Existing users require no migration (missing fields parsed as `[]`).
|
||||
**Convention:** `[]` = full access (admins), `string[]` = restricted to list, `null` = corrupted value (fail-closed: no data shown). Existing users require no migration (missing fields parsed as `[]`).
|
||||
|
||||
### NocoDB Users table
|
||||
|
||||
@@ -54,7 +54,7 @@ Both default to `"[]"` (unrestricted).
|
||||
|
||||
### 1. `src/services/usersService.ts`
|
||||
|
||||
- Update `fetchUsers()` to parse `AllowedMuseums` and `AllowedChannels` JSON strings into `string[]` (with safe fallback to `[]` on parse error)
|
||||
- Update `fetchUsers()` to parse `AllowedMuseums` and `AllowedChannels` JSON strings into `string[]`; on parse error return `null` (fail-closed — no data shown to the user)
|
||||
- Update `createUser()` to serialize `allowedMuseums`/`allowedChannels` arrays as JSON strings
|
||||
- **Add `updateUser(id, fields)`** — new function required (see Prerequisites below)
|
||||
|
||||
@@ -127,6 +127,8 @@ const visibleChannels = allowedChannels.length > 0
|
||||
**Layer 2 — Data filtered at base:**
|
||||
```typescript
|
||||
const permissionFilteredData = useMemo(() => {
|
||||
// null = corrupted stored value → show nothing (fail-closed)
|
||||
if (allowedMuseums === null || allowedChannels === null) return [];
|
||||
let d = data;
|
||||
if (allowedMuseums.length > 0)
|
||||
d = d.filter(r => allowedMuseums.includes(r.museum_name));
|
||||
@@ -167,7 +169,7 @@ Page reload
|
||||
| Admin user | `allowedMuseums: []`, `allowedChannels: []` — full access |
|
||||
| URL param references disallowed museum | Base filter removes it silently |
|
||||
| New museum added to data, not in user's list | Not visible to restricted user |
|
||||
| JSON parse error on stored value | Falls back to `[]` (unrestricted, fail-open) |
|
||||
| JSON parse error on stored value | `null` returned → no data shown (fail-closed) |
|
||||
| Page reload | Session restores access lists from server |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user