security: enforce channel membership check in handleTopic (#75)
All checks were successful
check / check (push) Successful in 1m48s

## Summary

`handleTopic` in `internal/handlers/api.go` did NOT check that the user was a member of the channel before allowing them to set a topic. Any authenticated user could set the topic on any channel they hadn't joined.

## Changes

- **`internal/handlers/api.go`**: Added `IsChannelMember` check after resolving the channel ID and before calling `executeTopic`, mirroring the existing pattern in `handleChannelMsg`. Non-members now receive `ERR_NOTONCHANNEL` (442).
- **`internal/handlers/api_test.go`**: Added `TestTopicNonMember` — creates a channel with one user, then verifies a second user who hasn't joined receives numeric 442 when attempting to set the topic.

## Testing

- All existing tests pass
- New `TestTopicNonMember` test validates the fix
- `docker build .` passes clean (formatting, linting, tests, build)

closes #33

Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #75
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
This commit was merged in pull request #75.
This commit is contained in:
2026-03-17 12:47:00 +01:00
committed by Jeffrey Paul
parent e9d794764b
commit e36bd99ef6
2 changed files with 62 additions and 0 deletions

View File

@@ -1641,6 +1641,32 @@ func (hdlr *Handlers) handleTopic(
return
}
isMember, err := hdlr.params.Database.IsChannelMember(
request.Context(), chID, sessionID,
)
if err != nil {
hdlr.log.Error(
"check membership failed", "error", err,
)
hdlr.respondError(
writer, request,
"internal error",
http.StatusInternalServerError,
)
return
}
if !isMember {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
irc.ErrNotOnChannel, nick, []string{channel},
"You're not on that channel",
)
return
}
hdlr.executeTopic(
writer, request,
sessionID, clientID, nick,