chore: add system docs, specs, and misc updates from other sessions
- Add complete docs/systems/ reference (18 system docs) - Add federation relay status doc and prior spec/plan docs - Remove superseded docs/federation-dm-s2s.md (replaced by docs/systems/federation.md) - CLAUDE.md updates - Minor fixes in social.ts, types.ts, AddDmMemberModal, NewDmModal, UserSettings
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# Permission System
|
||||
|
||||
Source files:
|
||||
- `packages/shared/src/permissions.ts` — Bit definitions, constants
|
||||
- `packages/server/src/utils/permissions.ts` — Server-side resolution
|
||||
- `packages/web/src/utils/permissions.ts` — Client-side helpers
|
||||
|
||||
Storage: Bigint decimal strings in SQLite TEXT columns (bigint not JSON-safe).
|
||||
|
||||
---
|
||||
|
||||
## Permission Bits
|
||||
|
||||
| Bit | Name | Description |
|
||||
|-----|------|-------------|
|
||||
| 0 | ADMINISTRATOR | Full access, bypasses all checks |
|
||||
| 1 | VIEW_CHANNEL | See channel, read messages |
|
||||
| 2 | MANAGE_CHANNELS | Create/edit/delete channels + categories |
|
||||
| 3 | MANAGE_ROLES | Create/edit/delete roles, assign roles |
|
||||
| 4 | MANAGE_SPACE | Edit space settings, manage join requests |
|
||||
| 5 | CREATE_INVITE | Generate invite codes |
|
||||
| 6 | KICK_MEMBERS | Remove members |
|
||||
| 7 | BAN_MEMBERS | Ban members |
|
||||
| 10 | SEND_MESSAGES | Post in text channels |
|
||||
| 11 | MANAGE_MESSAGES | Delete others' messages |
|
||||
| 12 | ATTACH_FILES | Upload files |
|
||||
| 13 | READ_MESSAGE_HISTORY | View message history |
|
||||
| 14 | ADD_REACTIONS | Add emoji reactions |
|
||||
| 20 | CONNECT | Join voice channels |
|
||||
| 21 | SPEAK | Transmit audio |
|
||||
| 22 | MUTE_MEMBERS | Space-mute others |
|
||||
| 23 | DEAFEN_MEMBERS | Space-deafen others |
|
||||
| 24 | MOVE_MEMBERS | Move between voice channels |
|
||||
| 25 | STREAM | Screen share |
|
||||
| 26 | DISCONNECT_MEMBERS | Disconnect from voice |
|
||||
|
||||
**Default @everyone:** VIEW_CHANNEL, SEND_MESSAGES, CREATE_INVITE, CONNECT, SPEAK, ATTACH_FILES, READ_MESSAGE_HISTORY, ADD_REACTIONS, STREAM
|
||||
|
||||
---
|
||||
|
||||
## Resolution Algorithm
|
||||
|
||||
`computePermissions(userId, spaceId, channelId?)` → bigint
|
||||
|
||||
### Step 1: Owner/Admin Check
|
||||
- Space owner OR instance admin (`isAdmin === 1`) → return ALL_PERMISSIONS
|
||||
|
||||
### Step 2: Compute Base (space-level)
|
||||
- Start with @everyone role permissions (role where `id === spaceId`)
|
||||
- OR together all permissions from user's assigned roles
|
||||
- If ADMINISTRATOR bit set → return ALL_PERMISSIONS
|
||||
|
||||
### Step 3: Apply Overrides (if channelId provided)
|
||||
|
||||
Three tiers, each applied category-first then channel-second:
|
||||
|
||||
**Tier 1 — @everyone override** (targetType='role', targetId=spaceId):
|
||||
```
|
||||
if categoryOverride: base = (base & ~deny) | allow
|
||||
if channelOverride: base = (base & ~deny) | allow
|
||||
```
|
||||
|
||||
**Tier 2 — Role overrides** (combined across all assigned roles):
|
||||
```
|
||||
catAllow = 0, catDeny = 0
|
||||
for each role: catAllow |= roleOverride.allow; catDeny |= roleOverride.deny
|
||||
base = (base & ~catDeny) | catAllow
|
||||
|
||||
chanAllow = 0, chanDeny = 0
|
||||
for each role: chanAllow |= roleOverride.allow; chanDeny |= roleOverride.deny
|
||||
base = (base & ~chanDeny) | chanAllow
|
||||
```
|
||||
|
||||
**Tier 3 — Member override** (targetType='member', targetId=userId):
|
||||
```
|
||||
if categoryOverride: base = (base & ~deny) | allow
|
||||
if channelOverride: base = (base & ~deny) | allow
|
||||
```
|
||||
|
||||
**Key rule:** Channel bits always win — applied after category, overwriting conflicting bits. Deny applied first (clears bits), then allow (sets bits).
|
||||
|
||||
---
|
||||
|
||||
## Helper Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `hasPermissionBit(perms, bit)` | Check if bit is set; true if ADMINISTRATOR |
|
||||
| `permissionsToString(perms)` | Bigint → decimal string for JSON |
|
||||
| `stringToPermissions(str)` | Decimal string → bigint (supports legacy JSON array format) |
|
||||
| `computePermissions(userId, spaceId, channelId?)` | Full resolution algorithm |
|
||||
| `computeCategoryPermissions(userId, spaceId, categoryId)` | Stops at category level (no channel overrides) |
|
||||
| `hasPermission(userId, spaceId, permission, channelId?)` | Boolean wrapper |
|
||||
| `getMember/isMember/isSpaceOwner` | Membership checks |
|
||||
| `isDmMember/isBanned` | DM/ban checks |
|
||||
| `getChannelSpaceId(channelId)` | Resolve channel's space |
|
||||
Reference in New Issue
Block a user