feat(webapi): differentiate no-room-permission from not-a-member error

- If a user is not a room member, HTTP 404 code=not_found will be
  returned. This also happen for posting into not-joined public rooms,
  and it can be interpreted as "room member is not found".

- If a user is a member but lacks the member permission to perform an
  action, HTTP 403 code=permission_denied will be returned.
This commit is contained in:
oxalica 2024-09-10 07:56:25 -04:00
parent 35b5aace08
commit 1a0347337c
2 changed files with 45 additions and 25 deletions

View file

@ -603,7 +603,13 @@ fn get_room_if_readable<T>(
f, f,
) )
.optional()? .optional()?
.ok_or_else(|| error_response!(StatusCode::NOT_FOUND, "not_found", "room not found")) .ok_or_else(|| {
error_response!(
StatusCode::NOT_FOUND,
"not_found",
"the room does not exist or the user is not a room member",
)
})
} }
/// Get room items with pagination parameters, /// Get room items with pagination parameters,
@ -675,7 +681,7 @@ async fn room_item_post(
let (cid, txs) = { let (cid, txs) = {
let conn = st.db.get(); let conn = st.db.get();
let Some((uid, _perm)) = conn let (uid, perm) = conn
.query_row( .query_row(
r" r"
SELECT `uid`, `room_member`.`permission` SELECT `uid`, `room_member`.`permission`
@ -696,14 +702,21 @@ async fn room_item_post(
}, },
) )
.optional()? .optional()?
.filter(|(_, perm)| perm.contains(MemberPermission::POST_CHAT)) .ok_or_else(|| {
else { error_response!(
StatusCode::NOT_FOUND,
"not_found",
"the room does not exist or the user is not a room member",
)
})?;
if !perm.contains(MemberPermission::POST_CHAT) {
return Err(error_response!( return Err(error_response!(
StatusCode::FORBIDDEN, StatusCode::FORBIDDEN,
"permission_denied", "permission_denied",
"the user does not have permission to post in this room", "the user does not have permission to post item in the room",
)); ));
}; }
let cid = Id::gen(); let cid = Id::gen();
conn.execute( conn.execute(
@ -825,7 +838,7 @@ async fn room_join(
return Err(error_response!( return Err(error_response!(
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
"not_found", "not_found",
"room does not exists or user is not allowed to join this room", "the room does not exist or the user is not allowed to join the room",
)); ));
} }
@ -866,7 +879,7 @@ async fn room_leave(st: &AppState, rid: Id, user: UserKey) -> Result<(), ApiErro
let mut conn = st.db.get(); let mut conn = st.db.get();
let txn = conn.transaction()?; let txn = conn.transaction()?;
let Some(uid) = txn let uid = txn
.query_row( .query_row(
r" r"
SELECT `uid` SELECT `uid`
@ -882,13 +895,14 @@ async fn room_leave(st: &AppState, rid: Id, user: UserKey) -> Result<(), ApiErro
|row| row.get::<_, u64>("uid"), |row| row.get::<_, u64>("uid"),
) )
.optional()? .optional()?
else { .ok_or_else(|| {
return Err(error_response!( error_response!(
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
"not_found", "not_found",
"room does not exists or user is not a room member", "the room does not exist or user is not a room member",
)); )
}; })?;
txn.execute( txn.execute(
r" r"
DELETE FROM `room_member` DELETE FROM `room_member`
@ -929,7 +943,7 @@ async fn room_item_mark_seen(
return Err(error_response!( return Err(error_response!(
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
"not_found", "not_found",
"room does not exists or user is not a room member", "the room does not exist or the user is not a room member",
)); ));
} }
Ok(StatusCode::NO_CONTENT) Ok(StatusCode::NO_CONTENT)

View file

@ -170,17 +170,18 @@ paths:
204: 204:
description: Operation completed. description: Operation completed.
409: 404:
description: description: |
Operation is already done, eg. joining an already joined room. Room does not exist or the user does not have permission for the
operation.
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/ApiError' $ref: '#/components/schemas/ApiError'
404: 409:
description: | description:
Room does not exist or the user does not have permission for management. Operation is already done, eg. joining an already joined room.
content: content:
application/json: application/json:
schema: schema:
@ -271,10 +272,15 @@ paths:
type: string type: string
description: Newly created item `cid`. description: Newly created item `cid`.
# FIXME: Distinguish this from 404?
403: 403:
description: | description: The user does not have permission to post in this room.
The user does not have permission to post in this room, or the room does not exist. content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
404:
description: The room does not exist or the user is not a room member.
content: content:
application/json: application/json:
schema: schema: