thoka
(Thomas Kalka)
4월 22, 2026, 7:47오후
1
Private Topics Plugin - #109 by thoka 을 조사하던 중, 제한된 카테고리에서 대문자가 포함된 사용자명을 멘션할 경우 해당 멘션이 보고되지 않는다는 사실을 발견했습니다.
@SomeUser를 멘션하면 에디터가
/composer/mentions.json?names[]=SomeUser&topic_id=10728
을 요청하며, 결과로 사용자명이 소문자로 반환되고 user_reasons가 설정되지 않은 상태입니다.
소문자로 된 사용자명으로 쿼리를 실행하면 "user_reasons": {"someuser":"category"}가 반환됩니다.
컴포저에서 사용자명을 소문자로 입력하면, 권한이 부족한 사용자에 대한 경고가 표시됩니다.
에디터에서 제공하는 자동완성을 사용하면, 입력된 소문자 사용자명이 대문자 이름으로 대체되어 보고되지 않습니다.
3개의 좋아요
RGJ
(Richard - Communiteq)
4월 22, 2026, 9:26오후
2
좋은 발견이네요 @thoka !
문제는 여기에 있습니다.
users는 {"username_lower" => User object }를 반환합니다.
하지만 name이 소문자로 변환되지 않으면 users[name]은 존재하지 않습니다.
수정 방법:
if user = users[name.downcase]
...nelsif group = groups[name.downcase]
...
아니면 더 좋은 방법은: 메서드 시작 부분에서 모든 이름을 소문자로 변환하는 것입니다. 여기에는 많은 문제가 있는데, groups는 .where("lower(name) IN (?)", @names.map(&:downcase))를 잘 수행하지만, visible_group_ids_for_allowed_check, topic_allowed_group_ids, mentionable_group_ids 및 members_visible_group_ids와 같은 함수들은 모두 where(name: @names)를 사용하여 대소문자 구분 문제를 유발합니다.
3개의 좋아요
올바른 수정 방법은
main ← fix/unicode-username-lookups
closed 02:15AM - 14 Apr 26 UTC
Leverages Rails' built-in `normalizes` feature to handle username
normalization … consistently throughout the codebase. When you call
`User.where(username_lower: value)` or `find_by(username_lower: value)`,
ActiveRecord now automatically normalizes the input value.
Key changes:
- Adds `normalizes :username` (unicode normalize) and
`normalizes :username_lower` (unicode normalize + downcase) to User
- Adds `normalizes :email` (strip + downcase) to UserEmail
- Removes manual `.downcase` and `.map(&:downcase)` calls before AR queries
- Adds `User#matches_username?` method for comparing usernames
- Simplifies `filter_by_username` and `filter_by_username_or_email` scopes
to use `ILIKE ANY(ARRAY[?])` instead of branching on array vs single value
- Updates `filter_by_username` to normalize input for ILIKE patterns
- Updates `find_by_username` to rely on AR normalization
- Fixes a SQL injection vulnerability in search user ordering
- Uses before_save callback for username_lower assignment to ensure it
runs even when validation is skipped (e.g., finish installation flow)
- Adds shoulda matcher tests for username normalizations
The `normalize_username` class method is kept for cases where AR can't help:
raw SQL queries, ILIKE patterns, and direct comparisons.
Ref - https://meta.discourse.org/t/393646
이지만, 지금은 변경 사항이 너무 커서 머지하는 것이 부담스럽습니다
대신, 리뷰를 더 쉽게 하고 위험을 줄이기 위해 각 "endpoints"를 하나씩 수정하겠습니다.
여기 첫 번째 단계입니다
main ← fix-composer-mention-case-sensitivity
merged 07:33PM - 12 May 26 UTC
Mentioning `@SomeUser` in a topic the mentioned user can't see (restricted categ… ory, PM they aren't invited to, topic they've muted) silently skipped the "cannot see this mention" warning popup whenever the typed name contained any uppercase letter. Same for mixed-case group names. Mention validation itself worked because of an existing client-side `.toLowerCase()` workaround, so the bug was easy to miss — mentions stayed `<a class="mention">` but the user got no signal that the mentioned account wouldn't actually be notified.
Server side, `ComposerController#mentions` builds its `users` lookup keyed by `username_lower` and `groups` keyed by the case-preserved DB `name`, then iterated `@names.each { |n| users[n] || groups[n] }` without normalizing — so any uppercase character missed both hashes and `user_reasons`/`group_reasons` came back empty. Four downstream group helpers (`mentionable_group_ids`, `members_visible_group_ids`, `topic_allowed_group_ids`, `visible_group_ids_for_allowed_check`) used `where(name: @names)` which is case-sensitive in PostgreSQL, and the `SiteSetting.here_mention` membership test compared raw strings.
Client side, `link-mentions.js` cached `foundUsers` / `userReasons` / `foundGroups` / `groupReasons` by the case as typed, and the prosemirror `mention.js` warning lookup did `response.users.includes(name)` plus `response.user_reasons[name]` with the original case — both of which the server only ever returned in the casing it had on hand.
Normalize the controller's `@names` and `@allowed_names` once at the top of the action, switch all four group helpers to `LOWER(name) IN (?)`, lower-case the response keys, and lower-case client caches and lookups end to end. Also extract the inline notified-member query into `already_notified_member_count` and tighten the request specs to cover users, mentionable groups, group reasons in PMs, and `allowed_names` (both user and group branches) with mixed-case input.
https://meta.discourse.org/t/401292
7개의 좋아요
Ethsim2
(Ethan )
5월 13, 2026, 3:03오후
5
645cb014c0에서 102c93e2ea 까지의 188개 커밋으로 discourse를 다시 빌드한 후, 마크다운 작성기에서 회귀(regression)로 보이는 문제를 발견했습니다.
이 경우 경고 메시지는 다소 오해의 소지가 있을 수 있지만, 제 커스텀 에이전트 @Forum_Research_Assis를 호출하려고 할 때마다 매번 나타납니다.
동영상 재현 자료에 따라 이 문제를 일관되게 재현할 수 있습니다.
해당 커밋 에는 사용자가 AI 에이전트를 멘션할 때 우회하도록 하는 로직이 누락된 것으로 보입니다.
준비가 되시면 새로운 풀 리퀘트를 시작할 수 있지만, 제 유일한 GitHub 계정에는 이미 열린 풀 리퀘트가 하나 있습니다.
1개의 좋아요
내 "수정"으로 인해 AI 에이전트에서 이 문제가 드러난 것 같다
main ← fix-composer-mention-warning-ai-bots
merged 04:44PM - 13 May 26 UTC
Mentioning an AI bot (e.g. `@Forum_Research_Assis`) in a topic the bot's User re… cord can't see — like a category restricted to a group the bot isn't part of — surfaced the "this user cannot see this mention" warning popup in the composer. The warning is misleading: AI bots reply via `PostCreator.create!(... skip_guardian: true)` (`playground.rb`), so they respond regardless of whether their User can `Guardian#can_see?` the topic.
The previous case-insensitive fix (9a4cca29) exposed this latent behavior. Pre-fix, mixed-case names hit a case-sensitive hash miss in `ComposerController#mentions` and silently returned an empty `user_reasons`. Post-fix, the lookup hits correctly and the reachability check — which was always there — now fires for AI bot users that genuinely can't see the topic.
Adds a `:composer_mention_user_reason` plugin modifier, applied after the standard reason is computed in `user_reason`, so plugins can clear or transform it. The AI plugin registers against the modifier and returns `nil` for any user in `DiscourseAi::AiBot::EntryPoint.all_bot_ids` (covering both AI agent users and chat-bot-enabled LLM model users).
discobot and the system user are intentionally unaffected: discobot's `PostCreator.create!` does not skip the guardian, so the reachability warning remains accurate for it.
https://meta.discourse.org/t/401292
3개의 좋아요