mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-27 07:58:55 -07:00
[rooms] fix subrooms permission gate
This commit is contained in:
@@ -4063,9 +4063,11 @@ const app = new Hono<App>()
|
|||||||
// body is a JSON ARRAY of the entries to change, keyed by (Permission, Role): `Override`
|
// body is a JSON ARRAY of the entries to change, keyed by (Permission, Role): `Override`
|
||||||
// is the client's checkbox, so true stores the entry for that pair and false clears it
|
// is the client's checkbox, so true stores the entry for that pair and false clears it
|
||||||
// back to the default. The stored table then overwrites the matching defaults in
|
// back to the default. The stored table then overwrites the matching defaults in
|
||||||
// `GET /photon_access_token`. Auth-gated (401) and creator-only (403), like the other
|
// `GET /photon_access_token`. Auth-gated (401) and gated to the room's MANAGERS — its
|
||||||
// subroom mutations. Answers an EMPTY 200 — the client fires this and re-reads nothing,
|
// creator or a co-owner (403), the same `canManageRoom` the other room-admin writes
|
||||||
// so there is no envelope to match.
|
// take; a creator-only check here locked out co-owners the client shows the screen to,
|
||||||
|
// and an owner whose room names them in `Roles` rather than `CreatorAccountId`. Answers
|
||||||
|
// an EMPTY 200 — the client fires this and re-reads nothing, so there is no envelope.
|
||||||
.put(
|
.put(
|
||||||
'/rooms/:roomId{[0-9]+}/subrooms/:subRoomId{[0-9]+}/permissions',
|
'/rooms/:roomId{[0-9]+}/subrooms/:subRoomId{[0-9]+}/permissions',
|
||||||
describeRoute({
|
describeRoute({
|
||||||
@@ -4090,8 +4092,8 @@ const app = new Hono<App>()
|
|||||||
'pair the defaults don’t carry (e.g. `CAN_INVITE`) is served too. The overrides apply',
|
'pair the defaults don’t carry (e.g. `CAN_INVITE`) is served too. The overrides apply',
|
||||||
'to the subroom the caller is standing in, resolved from presence.',
|
'to the subroom the caller is standing in, resolved from presence.',
|
||||||
'',
|
'',
|
||||||
'Creator-only — co-owners may build in a room but not decide what a role may do.',
|
'Gated to the room’s managers — its creator or a co-owner (`canManageRoom`), as the',
|
||||||
'The response body is EMPTY: the client doesn’t read one.',
|
'other room-admin writes are. The response body is EMPTY: the client doesn’t read one.',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
security: AUTHED,
|
security: AUTHED,
|
||||||
parameters: [roomIdParam, subRoomIdParam],
|
parameters: [roomIdParam, subRoomIdParam],
|
||||||
@@ -4113,7 +4115,7 @@ const app = new Hono<App>()
|
|||||||
// Scoped through the room so a subroom id from another room can't be written.
|
// Scoped through the room so a subroom id from another room can't be written.
|
||||||
const room = await getRoomById(c.env.DB, roomId)
|
const room = await getRoomById(c.env.DB, roomId)
|
||||||
if (!room || !findSubRoom(room, subRoomId)) return c.notFound()
|
if (!room || !findSubRoom(room, subRoomId)) return c.notFound()
|
||||||
if (room.CreatorAccountId !== accountId) return c.body(null, 403)
|
if (!canManageRoom(room, accountId)) return c.body(null, 403)
|
||||||
|
|
||||||
const permissions = parseRoomPermissions(await c.req.json().catch(() => null))
|
const permissions = parseRoomPermissions(await c.req.json().catch(() => null))
|
||||||
await setSubRoomPermissions(c.env.DB, subRoomId, permissions)
|
await setSubRoomPermissions(c.env.DB, subRoomId, permissions)
|
||||||
|
|||||||
@@ -4818,19 +4818,24 @@ describe('rooms endpoints', () => {
|
|||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
it('is auth-gated and creator-only', async () => {
|
it('is auth-gated and open to the room’s managers only', async () => {
|
||||||
const body = [
|
const body = [
|
||||||
{ Permission: 'CAN_SAVE_INVENTIONS', Role: 30, Override: false, Type: 0, Value: 'True' },
|
{ Permission: 'CAN_SAVE_INVENTIONS', Role: 30, Override: false, Type: 0, Value: 'True' },
|
||||||
]
|
]
|
||||||
// No token → 401.
|
// No token → 401.
|
||||||
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body)).status).toBe(401)
|
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body)).status).toBe(401)
|
||||||
// A valid token that isn't the room's creator → 403.
|
// A valid token that isn't the room's creator or a co-owner → 403.
|
||||||
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body, '999')).status).toBe(
|
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body, '999')).status).toBe(
|
||||||
403
|
403
|
||||||
)
|
)
|
||||||
// Not even a co-owner: account 2 holds Role 30 on the seeded rooms. Co-owners may
|
// A co-owner may: account 2 holds Role 30 on the seeded rooms. (This body clears a
|
||||||
// build in a room but don't decide what a role may do.
|
// pair that was never stored, so it changes nothing.)
|
||||||
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body, '2')).status).toBe(403)
|
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body, '2')).status).toBe(200)
|
||||||
|
// A Host (a lower tier) may not.
|
||||||
|
await setRoles()
|
||||||
|
expect((await putPermissions('/rooms/2/subrooms/2/permissions', body, '748')).status).toBe(
|
||||||
|
403
|
||||||
|
)
|
||||||
// Unknown room / unknown subroom → 404.
|
// Unknown room / unknown subroom → 404.
|
||||||
expect((await putPermissions('/rooms/99999/subrooms/2/permissions', body, '1')).status).toBe(
|
expect((await putPermissions('/rooms/99999/subrooms/2/permissions', body, '1')).status).toBe(
|
||||||
404
|
404
|
||||||
|
|||||||
Reference in New Issue
Block a user