From ce0b2d0e1524ccd4d5d69d7fbbfaa449f198a824 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Thu, 9 Apr 2026 02:15:44 +0200 Subject: [PATCH] feat: allow any group DM member to add friends, not just owner Remove the owner-only gate on POST /api/dm/:id/members. The S2S relay already accepts member_add from any HMAC-verified peer, and the UI already shows the add button to all group DM members. Only the server-side check was blocking non-owners. --- docs/systems/dm-system.md | 13 ++++++------- packages/server/src/routes/dm.ts | 4 +--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/systems/dm-system.md b/docs/systems/dm-system.md index 1ad3b5e9..b16e71ae 100644 --- a/docs/systems/dm-system.md +++ b/docs/systems/dm-system.md @@ -24,7 +24,7 @@ Related specs: `docs/systems/federation.md` (wire protocol, outbox worker, peer |----------|-----------|----------| | `ownerId` | `NULL` | Creator's local user ID (never NULL) | | `federatedId` format | 32-char hex (SHA-256 hash) | 36-char UUID (random) | -| Mutable membership | No (immutable pair) | Yes (owner adds, anyone leaves) | +| Mutable membership | No (immutable pair) | Yes (any member adds, anyone leaves) | | Max members | 2 | 10 | | Friendship required | No | Yes (for new adds; exempt for existing DM members during 1-on-1 upgrade) | | Soft-close | Yes (`closed=1` on dm_members) | Yes (same) | @@ -184,11 +184,10 @@ Close and reopen are relayed to all peer instances that hold a copy of the DM: **Validation:** 1. Caller must be a member of the channel 2. Channel must be a group DM (`ownerId` is not NULL) -3. Caller must be the group owner (`dmChannel.ownerId === request.userId`) -4. Target user must exist -5. Caller and target must be friends -6. Target must not already be a member -7. Current member count must be < 10 +3. Target user must exist +4. Caller and target must be friends +5. Target must not already be a member +6. Current member count must be < 10 **Lazy federation setup:** - If the channel lacks a `federatedId` and the new member (or any existing member) is remote: @@ -633,7 +632,7 @@ const normalized = homeInstance.startsWith('http') | `POST` | `/api/dm` | JWT | Create or get existing 1-on-1 DM. Accepts `{ userId }` (local) or `{ homeUserId, homeInstance }` (federated) | | `POST` | `/api/dm/group` | JWT | Create group DM with multiple members | | `DELETE` | `/api/dm/:id` | JWT | Soft-close DM for caller | -| `POST` | `/api/dm/:id/members` | JWT | Add member to group DM (owner only). Accepts `{ userId }` or `{ homeUserId, homeInstance }` | +| `POST` | `/api/dm/:id/members` | JWT | Add member to group DM (any member). Accepts `{ userId }` or `{ homeUserId, homeInstance }` | | `DELETE` | `/api/dm/:id/members` | JWT | Leave group DM | | `GET` | `/api/dm/:id/messages` | JWT | Get messages with cursor pagination | | `POST` | `/api/dm/:id/messages` | JWT | Send message (rate-limited: 5/5s) | diff --git a/packages/server/src/routes/dm.ts b/packages/server/src/routes/dm.ts index afe8d684..532e8c5f 100644 --- a/packages/server/src/routes/dm.ts +++ b/packages/server/src/routes/dm.ts @@ -902,9 +902,7 @@ export async function dmRoutes(app: FastifyInstance): Promise { if (!dmChannel.ownerId) { return reply.code(400).send({ error: 'Cannot add members to a 1-on-1 DM. Use POST /api/dm/group to create a group.', statusCode: 400 }); } - if (dmChannel.ownerId !== request.userId) { - return reply.code(403).send({ error: 'Only the group owner can add members', statusCode: 403 }); - } + // Any group DM member can add friends (not just the owner) // Validate the adder and target are friends const friendship = db.select().from(schema.friends).where(