mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
docs: refresh api.md, protocol.md, schema.md against current code (D7)
One-PR spec refresh per decision D7, using the 2026-07-19 audit's
conformance matrix as the checklist:
api.md
- Remove the deleted version field from /health and /api/v1/info
(anti-fingerprinting C-2) and document the removal.
- Document the profile surface (PATCH /users/me, PUT /users/me/password,
GET/DELETE /users/me/sessions), the user-blocks surface
(GET/PUT/DELETE /api/v1/blocks), and the plugin admin surface
(/api/v1/admin/plugins).
- Correct GET /api/v1/files/{id}: auth is required and caching is
'private, no-cache' (was documented as public/immutable, unauthenticated).
- Add search (30/min) and upload (10/min) rate limits; note announcement
channel type as planned-only.
protocol.md
- Document auth_ok.replay_source and the 3-tier reconnect replay
(ring buffer -> events table -> full resync) with the visibility
watermark.
- Add the Voice End-to-End Encryption section (voice_e2ee_announce/offer
in both directions, key-holder semantics, rate limits) and
voice_token.is_key_holder.
- Document user_update; mark voice_speakers and member_leave as defined
but not currently emitted; extend voice_config fields.
- Update the reference tables (19 client->server / 30 server->client)
and point them at protocol-schema.json as the generated inventory.
schema.md
- Correct the migration history to the real 001-015 numbering.
- Document the previously missing tables: login_attempts, settings,
emoji, sounds (dead schema), rate_lockouts, user_blocks, events,
plugins, plugin_kv; add attachments.uploader_id and new indexes.
- Fix the channel-type list to text/voice/dm (013 triggers) and correct
the permission formula to (base & ~deny) | allow to match
permissions.EffectivePerms.
- Note the sqlc/dbgen layer and link the architecture data-model doc.
Also correct the audit_log_v6 claim (transient rename inside migration
003, not a coexisting table) in the audit and data-model blueprint, and
update the audit/decisions trackers (A-2026-07-03 closed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UA17KPvqGBX3XbXYnMf1rA
This commit is contained in:
+191
-9
@@ -343,6 +343,103 @@ Disable TOTP for the authenticated user.
|
||||
|
||||
---
|
||||
|
||||
## User Profile & Sessions
|
||||
|
||||
### PATCH /api/v1/users/me
|
||||
|
||||
Update the authenticated user's profile (username and/or avatar).
|
||||
Broadcasts a `user_update` WebSocket message to all clients on success.
|
||||
|
||||
**Auth:** Required
|
||||
**Rate limit:** 10 requests/minute
|
||||
|
||||
#### Request
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "newname",
|
||||
"avatar": "upload-uuid.png"
|
||||
}
|
||||
```
|
||||
|
||||
Both fields optional; `avatar` may be `null` to clear it.
|
||||
|
||||
#### Response 200 OK
|
||||
|
||||
Returns the updated user object (same shape as `GET /api/v1/auth/me`).
|
||||
|
||||
---
|
||||
|
||||
### PUT /api/v1/users/me/password
|
||||
|
||||
Change the authenticated user's password. Verifies the old password, enforces
|
||||
password strength, and revokes all *other* sessions on success.
|
||||
|
||||
**Auth:** Required
|
||||
**Rate limit:** 5 requests/minute, plus a failed-confirmation lockout on
|
||||
repeated wrong old passwords
|
||||
|
||||
#### Request
|
||||
|
||||
```json
|
||||
{
|
||||
"old_password": "OldPass!1",
|
||||
"new_password": "NewStr0ng!Pass"
|
||||
}
|
||||
```
|
||||
|
||||
#### Response 204 No Content
|
||||
|
||||
Password changed and other sessions revoked. If the password change committed
|
||||
but revoking other sessions failed, the endpoint returns **200 OK** with a
|
||||
warning body instead (the new password is in effect — do not retry with the
|
||||
old one).
|
||||
|
||||
#### Errors
|
||||
|
||||
| Status | Code | Cause |
|
||||
| ------ | ---- | ----- |
|
||||
| 400 | `INVALID_INPUT` | Weak new password, or new password equals old |
|
||||
| 403 | `FORBIDDEN` | Incorrect old password |
|
||||
| 429 | `RATE_LIMITED` | Too many attempts / lockout |
|
||||
|
||||
---
|
||||
|
||||
### GET /api/v1/users/me/sessions
|
||||
|
||||
List the authenticated user's active sessions.
|
||||
|
||||
**Auth:** Required
|
||||
|
||||
#### Response 200 OK
|
||||
|
||||
```json
|
||||
{
|
||||
"sessions": [
|
||||
{
|
||||
"id": 12,
|
||||
"device": "Mozilla/5.0 ...",
|
||||
"ip": "192.168.1.100",
|
||||
"created_at": "2026-07-01T10:00:00Z",
|
||||
"last_used": "2026-07-19T09:00:00Z",
|
||||
"is_current": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DELETE /api/v1/users/me/sessions/{id}
|
||||
|
||||
Revoke one of the authenticated user's sessions by ID.
|
||||
|
||||
**Auth:** Required
|
||||
|
||||
#### Response 204 No Content
|
||||
|
||||
---
|
||||
|
||||
## Channel Endpoints
|
||||
|
||||
### GET /api/v1/channels
|
||||
@@ -372,7 +469,7 @@ List all channels the authenticated user has `READ_MESSAGES` permission for. DM
|
||||
| ----- | ---- | ----------- |
|
||||
| `id` | int64 | Channel ID |
|
||||
| `name` | string | Channel name |
|
||||
| `type` | string | `text`, `voice`, or `announcement` |
|
||||
| `type` | string | `text` or `voice` (`announcement` is planned; the DB currently rejects it) |
|
||||
| `topic` | string | Channel topic/description |
|
||||
| `category` | string | Category grouping |
|
||||
| `position` | int | Sort order within category |
|
||||
@@ -492,6 +589,7 @@ Unpin a message from a channel.
|
||||
Full-text search across messages in channels the user can read. Uses SQLite FTS5 for matching.
|
||||
|
||||
**Auth:** Required
|
||||
**Rate limit:** 30 requests/minute
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
@@ -598,6 +696,47 @@ Close a DM channel for the authenticated user (hides it from their sidebar). The
|
||||
|
||||
---
|
||||
|
||||
## User Blocks
|
||||
|
||||
Blocking a user prevents DM creation and messaging in both directions
|
||||
(backed by the `user_blocks` table).
|
||||
|
||||
### GET /api/v1/blocks
|
||||
|
||||
List the IDs of users the authenticated user has blocked.
|
||||
|
||||
**Auth:** Required
|
||||
|
||||
#### Response 200 OK
|
||||
|
||||
```json
|
||||
{ "blocked_user_ids": [2, 7] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### PUT /api/v1/blocks/{userId}
|
||||
|
||||
Block a user.
|
||||
|
||||
**Auth:** Required
|
||||
|
||||
#### Response 200 OK
|
||||
|
||||
```json
|
||||
{ "message": "user blocked" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DELETE /api/v1/blocks/{userId}
|
||||
|
||||
Unblock a user.
|
||||
|
||||
**Auth:** Required
|
||||
|
||||
---
|
||||
|
||||
## Invite Endpoints
|
||||
|
||||
All invite endpoints require authentication and the `MANAGE_INVITES` permission.
|
||||
@@ -667,6 +806,7 @@ Revoke an invite by its code string.
|
||||
Upload a file as multipart form data.
|
||||
|
||||
**Auth:** Required
|
||||
**Rate limit:** 10 requests/minute
|
||||
**Body size limit:** 100 MiB
|
||||
**Content-Type:** `multipart/form-data`
|
||||
|
||||
@@ -694,10 +834,12 @@ Files are validated against blocked magic bytes (PE executables, ELF binaries, M
|
||||
|
||||
Serve a previously uploaded file by its UUID.
|
||||
|
||||
**Auth:** None (URLs are unguessable UUIDs)
|
||||
**Caching:** `Cache-Control: public, max-age=31536000, immutable`
|
||||
**Auth:** Required (Bearer token) — downloads are access-controlled
|
||||
**Caching:** `Cache-Control: private, no-cache` (never stored by shared/proxy caches; browsers must revalidate)
|
||||
|
||||
Supports HTTP range requests and conditional requests.
|
||||
Supports HTTP range requests and conditional requests. MIME types that could
|
||||
execute under the app origin (HTML, SVG, XML, PDF) are served with
|
||||
`Content-Disposition: attachment` to force download.
|
||||
|
||||
---
|
||||
|
||||
@@ -707,12 +849,12 @@ Supports HTTP range requests and conditional requests.
|
||||
|
||||
### GET /api/v1/health
|
||||
|
||||
Public health check endpoint, no authentication required.
|
||||
Public health check endpoint, no authentication required. The server version
|
||||
is deliberately not exposed here (anti-fingerprinting hardening, C-2).
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "1.0.0",
|
||||
"uptime": 86400,
|
||||
"online_users": 3
|
||||
}
|
||||
@@ -724,14 +866,14 @@ Public health check endpoint, no authentication required.
|
||||
|
||||
### GET /api/v1/info
|
||||
|
||||
Returns the server name and version.
|
||||
Returns the server name. The version field was removed from this
|
||||
unauthenticated endpoint (anti-fingerprinting hardening, C-2).
|
||||
|
||||
**Auth:** None
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "My OwnCord Server",
|
||||
"version": "1.2.0"
|
||||
"name": "My OwnCord Server"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -760,6 +902,46 @@ Runtime server metrics. Restricted to admin-allowed CIDRs.
|
||||
|
||||
---
|
||||
|
||||
## Plugin Administration
|
||||
|
||||
Manage WASM plugins. These endpoints sit behind **both** the admin IP
|
||||
restriction (allowed CIDRs) **and** admin bearer-token authentication.
|
||||
Plugin execution additionally requires a server built with `-tags wazero`
|
||||
and `plugins.enabled: true` in config.
|
||||
|
||||
### GET /api/v1/admin/plugins
|
||||
|
||||
List installed plugins.
|
||||
|
||||
#### Response 200 OK
|
||||
|
||||
Array of plugin rows: `ID`, `Name`, `Version`, `Enabled`, `ManifestJSON`,
|
||||
`InstalledAt`.
|
||||
|
||||
### POST /api/v1/admin/plugins/install
|
||||
|
||||
Install a plugin from an uploaded zip (multipart form). The archive is
|
||||
size-capped (16 MiB compressed / 64 MiB uncompressed) and hardened against
|
||||
zip-slip and symlinks; installation is staged and atomically renamed.
|
||||
|
||||
#### Response 201 Created
|
||||
|
||||
```json
|
||||
{ "name": "plugin-name" }
|
||||
```
|
||||
|
||||
### POST /api/v1/admin/plugins/{id}/enable
|
||||
|
||||
### POST /api/v1/admin/plugins/{id}/disable
|
||||
|
||||
Enable or disable an installed plugin.
|
||||
|
||||
### DELETE /api/v1/admin/plugins/{id}
|
||||
|
||||
Uninstall a plugin.
|
||||
|
||||
---
|
||||
|
||||
## LiveKit Endpoints
|
||||
|
||||
These endpoints are only registered when LiveKit voice is configured.
|
||||
|
||||
Reference in New Issue
Block a user