Files
compute-engine/controller/channel_authz.go
T
Pine 28e53d90fc feat: 算力引擎 Go 后端核心(new-api)
- 统一 OpenAI 兼容 /v1 中继 + 渠道/额度/令牌/流水
- 各领域包:relay 模型网关、model 数据层、controller 管理 API
2026-08-23 22:38:46 +08:00

137 lines
4.5 KiB
Go

package controller
import "github.com/QuantumNous/new-api/model"
func channelHasSensitiveChanges(channel *PatchChannel, origin *model.Channel, requestData map[string]any) bool {
if _, ok := requestData["type"]; ok && channel.Type != origin.Type {
return true
}
if _, ok := requestData["key"]; ok && channel.Key != "" && channel.Key != origin.Key {
return true
}
if _, ok := requestData["base_url"]; ok && !equalStringPtr(channel.BaseURL, origin.BaseURL) {
return true
}
if _, ok := requestData["openai_organization"]; ok && !equalStringPtr(channel.OpenAIOrganization, origin.OpenAIOrganization) {
return true
}
if _, ok := requestData["header_override"]; ok && !equalStringPtr(channel.HeaderOverride, origin.HeaderOverride) {
return true
}
if _, ok := requestData["param_override"]; ok && !equalStringPtr(channel.ParamOverride, origin.ParamOverride) {
return true
}
if _, ok := requestData["setting"]; ok && !equalStringPtr(channel.Setting, origin.Setting) {
return true
}
if _, ok := requestData["other"]; ok && channel.Other != origin.Other {
return true
}
if _, ok := requestData["settings"]; ok && channel.OtherSettings != origin.OtherSettings {
return true
}
if _, ok := requestData["key_mode"]; ok && channel.KeyMode != nil {
return true
}
// Fail closed: any field present in the request that is neither a known
// sensitive field (gated above) nor an explicitly classified non-sensitive
// field must be treated as sensitive. This keeps a newly added channel field
// from silently becoming editable by ChannelWrite-only admins until it is
// consciously classified in channelNonSensitiveFields.
for field := range requestData {
if _, ok := channelSensitiveFields[field]; ok {
continue
}
if _, ok := channelNonSensitiveFields[field]; ok {
continue
}
if _, ok := channelOperationalFields[field]; ok {
continue
}
if _, ok := channelReadOnlyFields[field]; ok {
continue
}
return true
}
return false
}
// channelSensitiveFields lists the channel fields whose modification requires
// ChannelSensitiveWrite. They are each checked individually in
// channelHasSensitiveChanges with a precise old-vs-new comparison; this set is
// used to exclude them from the fail-closed scan for unknown fields.
var channelSensitiveFields = map[string]struct{}{
"type": {},
"key": {},
"base_url": {},
"openai_organization": {},
"header_override": {},
"param_override": {},
"setting": {},
"other": {},
"settings": {},
"key_mode": {},
}
// channelOperationalFields lists fields managed by operation endpoints instead
// of the general channel edit endpoint.
var channelOperationalFields = map[string]struct{}{
"status": {},
}
// channelReadOnlyFields lists server-managed/accounting fields that the general
// channel edit endpoint must ignore even if a client sends them.
var channelReadOnlyFields = map[string]struct{}{
"created_time": {},
"test_time": {},
"response_time": {},
"balance": {},
"balance_updated_time": {},
"used_quota": {},
}
func clearChannelReadOnlyFields(channel *PatchChannel, requestData map[string]any) {
if _, ok := requestData["created_time"]; ok {
channel.CreatedTime = 0
}
if _, ok := requestData["test_time"]; ok {
channel.TestTime = 0
}
if _, ok := requestData["response_time"]; ok {
channel.ResponseTime = 0
}
if _, ok := requestData["balance"]; ok {
channel.Balance = 0
}
if _, ok := requestData["balance_updated_time"]; ok {
channel.BalanceUpdatedTime = 0
}
if _, ok := requestData["used_quota"]; ok {
channel.UsedQuota = 0
}
}
// channelNonSensitiveFields lists routing / server-managed channel
// fields a ChannelWrite admin may edit without ChannelSensitiveWrite. When a new
// field is added to model.Channel it must be added to either this set or
// channelSensitiveFields or channelOperationalFields; otherwise it falls through
// to the fail-closed branch and is treated as sensitive. The
// TestChannelFieldsAreClassified guard test enforces this.
var channelNonSensitiveFields = map[string]struct{}{
"id": {},
"test_model": {},
"name": {},
"weight": {},
"models": {},
"group": {},
"model_mapping": {},
"status_code_mapping": {},
"priority": {},
"auto_ban": {},
"other_info": {},
"tag": {},
"remark": {},
"channel_info": {},
"multi_key_mode": {},
}