fix: GetAllChannels ignores group filter parameter#4847
Conversation
When users filter channels by group without entering a search keyword, the frontend calls GetAllChannels (GET /api/channel/) instead of SearchChannels. However, GetAllChannels did not process the group query parameter, causing the filter to have no effect. Added group filtering logic to GetAllChannels for both normal mode and tag mode, using the same CONCAT/|| pattern as SearchChannels for cross-database compatibility (MySQL, PostgreSQL, SQLite).
WalkthroughThe ChangesChannel group filtering
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@controller/channel.go`:
- Around line 139-146: The code hardcodes the reserved column name "group" when
filtering by groupFilter; replace those literals with the shared variable
commonGroupCol (as used in model/channel.go) so quoting/concatenation is
consistent across dialects: update the branch that checks common.UsingMySQL and
the else branch to use commonGroupCol in the CONCAT/|| expressions and keep the
same LIKE pattern logic applied to baseQuery.Where, referencing baseQuery,
groupFilter, and common.UsingMySQL.
- Around line 139-146: The LIKE pattern concatenation using groupFilter is
vulnerable to wildcard interpretation; update the code that builds the pattern
(the baseQuery.Where calls that use groupFilter) to first escape '!' then '%'
and '_' in groupFilter (e.g. replace "!" -> "!!", "%" -> "!%", "_" -> "!_"),
then use the escaped value in the bound parameter and append " ESCAPE '!'" to
the SQL fragment; do this for both MySQL and non-MySQL branches (the CONCAT/(','
|| "group" || ',') patterns) and apply the same escaping strategy to the other
affected call sites in model/channel.go that use keyword, model, and group
parameters so all LIKE queries use the same escape character and escaped inputs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4656c00a-7fc2-4cdb-824b-937e24d064c8
📒 Files selected for processing (1)
controller/channel.go
| if groupFilter != "" && groupFilter != "null" { | ||
| if common.UsingMySQL { | ||
| baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%") | ||
| } else { | ||
| // SQLite, PostgreSQL | ||
| baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%") | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify commonGroupCol is defined and check usage patterns
echo "=== Checking if commonGroupCol is defined in model/main.go ==="
rg -n "commonGroupCol" model/main.go
echo -e "\n=== Finding other usages of commonGroupCol in the codebase ==="
rg -n "commonGroupCol" --type=go -C3
echo -e "\n=== Finding raw SQL references to 'group' column (potential violations) ==="
rg -nP '(CONCAT|WHERE).*[`"]group[`"]' --type=go -C2Repository: QuantumNous/new-api
Length of output: 8077
Use commonGroupCol variable for the reserved-word column per coding guidelines.
The group column is a SQL reserved word. The coding guidelines require using the commonGroupCol variable from model/main.go instead of hardcoding column quoting. This same pattern is correctly implemented in model/channel.go lines 370–379 and 862–871 using commonGroupCol, ensuring consistent handling across all database dialects.
The fix applies the pattern already established elsewhere in the codebase:
Proposed fix
if groupFilter != "" && groupFilter != "null" {
if common.UsingMySQL {
- baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+ baseQuery = baseQuery.Where("CONCAT(',', "+model.commonGroupCol+", ',') LIKE ?", "%,"+groupFilter+",%")
} else {
// SQLite, PostgreSQL
- baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%")
+ baseQuery = baseQuery.Where("(',' || "+model.commonGroupCol+" || ',') LIKE ?", "%,"+groupFilter+",%")
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/channel.go` around lines 139 - 146, The code hardcodes the
reserved column name "group" when filtering by groupFilter; replace those
literals with the shared variable commonGroupCol (as used in model/channel.go)
so quoting/concatenation is consistent across dialects: update the branch that
checks common.UsingMySQL and the else branch to use commonGroupCol in the
CONCAT/|| expressions and keep the same LIKE pattern logic applied to
baseQuery.Where, referencing baseQuery, groupFilter, and common.UsingMySQL.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if SearchChannels/model layer has same LIKE pattern without escaping
echo "=== Checking model.SearchChannels for group LIKE pattern ==="
rg -n "LIKE.*group" model/ --type=go -C5
echo -e "\n=== Searching for LIKE escape utilities in common package ==="
rg -n "EscapeLike|escapeLike|LIKE.*escape" common/ --type=go -C3
echo -e "\n=== Finding other LIKE patterns with user input in controller ==="
rg -nP 'LIKE.*\%.*\+.*\+' controller/ --type=go -C2Repository: QuantumNous/new-api
Length of output: 2636
🏁 Script executed:
#!/bin/bash
# Search for all LIKE patterns with user input concatenation in the codebase
echo "=== Finding all LIKE patterns with potential unescaped user input ==="
rg -n 'LIKE.*\%.*\+' controller/ model/ --type=go -C3 | head -100
echo -e "\n=== Check if keyword, model parameters are also vulnerable ==="
rg -n '"keyword"|"model"|"group"' controller/channel.go model/channel.go --type=go -B2 -A2 | grep -E "(keyword|model|group)" | head -20
echo -e "\n=== Check if there are any existing string escaping utilities ==="
rg -n "ReplaceAll|Escape|escape" common/ --type=go | grep -i "like\|sql\|escape" | head -20Repository: QuantumNous/new-api
Length of output: 1208
🏁 Script executed:
#!/bin/bash
# Find all LIKE patterns with string concatenation (simpler approach)
echo "=== All LIKE query patterns in controller/channel.go ==="
rg -n 'LIKE' controller/channel.go --type=go -B2 -A2
echo -e "\n=== All LIKE query patterns in model/channel.go ==="
rg -n 'LIKE' model/channel.go --type=go -B2 -A2
echo -e "\n=== Check if groupFilter is used elsewhere ==="
rg -n 'groupFilter' controller/ --type=go -C2
echo -e "\n=== Verify if ESCAPE clause is properly supported ==="
rg -n 'ESCAPE' . --type=go -C2Repository: QuantumNous/new-api
Length of output: 5398
🏁 Script executed:
#!/bin/bash
# Check if sanitizeLikePattern is exported (uppercase) and could be reused
echo "=== Check sanitizeLikePattern function definition ==="
rg -n 'func sanitizeLikePattern' model/token.go --type=go -A15
echo -e "\n=== Check how it's used in token.go ==="
rg -n 'sanitizeLikePattern' model/token.go --type=go -B2 -A2
echo -e "\n=== Check if function is called from controller ==="
rg -n 'sanitizeLikePattern' controller/ --type=go
echo -e "\n=== Check the full context of the vulnerable code in controller ==="
sed -n '130,150p' controller/channel.goRepository: QuantumNous/new-api
Length of output: 2288
Escape SQL LIKE wildcards in groupFilter to prevent unintended pattern matching.
The groupFilter value is concatenated directly into the LIKE pattern without escaping SQL wildcard characters (% and _). If groupFilter contains these characters, they will be interpreted as wildcards rather than literal characters. For example, filtering by "admin%" would incorrectly match "admin", "administrator", and "admin_team".
A similar vulnerability exists in model/channel.go (lines 379, 871) with the keyword, model, and group parameters. The codebase already defines a sanitization pattern in model/token.go using ! as the ESCAPE character, which should be adopted here for consistency.
Suggested fix
+ // Escape LIKE wildcards in groupFilter
+ escapedGroupFilter := strings.ReplaceAll(strings.ReplaceAll(groupFilter, "!", "!!"), "_", "!_")
+
if groupFilter != "" && groupFilter != "null" {
if common.UsingMySQL {
- baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+ baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
} else {
// SQLite, PostgreSQL
- baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+escapedGroupFilter+",%")
+ baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@controller/channel.go` around lines 139 - 146, The LIKE pattern concatenation
using groupFilter is vulnerable to wildcard interpretation; update the code that
builds the pattern (the baseQuery.Where calls that use groupFilter) to first
escape '!' then '%' and '_' in groupFilter (e.g. replace "!" -> "!!", "%" ->
"!%", "_" -> "!_"), then use the escaped value in the bound parameter and append
" ESCAPE '!'" to the SQL fragment; do this for both MySQL and non-MySQL branches
(the CONCAT/(',' || "group" || ',') patterns) and apply the same escaping
strategy to the other affected call sites in model/channel.go that use keyword,
model, and group parameters so all LIKE queries use the same escape character
and escaped inputs.
Problem
When users filter channels by group without entering a search keyword, the group filter has no effect.
Root cause: The frontend determines whether to call
GetAllChannels(GET /api/channel/) orSearchChannels(GET /api/channel/search) based on whether a keyword/model filter is present. When only the group filter is selected,GetAllChannelsis called, but it completely ignores thegroupquery parameter.Fix
Added group filtering logic to
GetAllChannels()incontroller/channel.go:CONCAT(',', group, ',') LIKE ?(MySQL) /(',' || "group" || ',') LIKE ?(PostgreSQL/SQLite)strings.ContainsThis matches the existing pattern used in
SearchChannels()andmodel.SearchChannels().Testing
问题
用户在渠道列表页面仅按分组筛选(不输入搜索关键词)时,筛选无效,返回全部渠道。
根因: 前端根据是否有关键词/模型筛选来决定调用
GetAllChannels(GET /api/channel/)还是SearchChannels(GET /api/channel/search)。当只选择了分组筛选时,走的是GetAllChannels,但该函数完全忽略了group查询参数。修复
在
controller/channel.go的GetAllChannels()中补充了分组筛选逻辑:CONCAT(',', group, ',') LIKE ?(MySQL)/(',' || "group" || ',') LIKE ?(PostgreSQL/SQLite),兼容三种数据库strings.Contains匹配逗号分隔的分组字段实现方式与已有的
SearchChannels()和model.SearchChannels()保持一致。测试
Summary by CodeRabbit