fix: 修复CodeReview发现的安全问题和代码质量问题 | fix security and code quality issues identified by CodeReview

- 修复JSON注入漏洞:使用json.Marshal()安全转义字符串内容
- 定义常量CHARS_PER_TOKEN替换硬编码的token估算数字4
- 处理UnmarshalJSON错误,避免静默失败并记录错误日志
- 定义常量替换硬编码的API端点路径,提高可维护性

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Deadwalk
2025-09-28 16:41:48 +08:00
parent e27612a620
commit 48396d3f33
3 changed files with 26 additions and 7 deletions

View File

@@ -14,6 +14,13 @@ import (
"github.com/songquanpeng/one-api/relay/relaymode" "github.com/songquanpeng/one-api/relay/relaymode"
) )
const (
// NativeAnthropicEndpoint is the endpoint for native Anthropic API
NativeAnthropicEndpoint = "/v1/messages"
// ThirdPartyAnthropicEndpoint is the endpoint for third-party providers supporting Anthropic protocol
ThirdPartyAnthropicEndpoint = "/anthropic/v1/messages"
)
type Adaptor struct { type Adaptor struct {
} }
@@ -24,13 +31,13 @@ func (a *Adaptor) Init(meta *meta.Meta) {
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) { func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
// For native Anthropic API // For native Anthropic API
if strings.Contains(meta.BaseURL, "api.anthropic.com") { if strings.Contains(meta.BaseURL, "api.anthropic.com") {
return fmt.Sprintf("%s/v1/messages", meta.BaseURL), nil return fmt.Sprintf("%s%s", meta.BaseURL, NativeAnthropicEndpoint), nil
} }
// For third-party providers supporting Anthropic protocol (like DeepSeek) // For third-party providers supporting Anthropic protocol (like DeepSeek)
// They typically expose the endpoint at /anthropic/v1/messages // They typically expose the endpoint at /anthropic/v1/messages
baseURL := strings.TrimSuffix(meta.BaseURL, "/") baseURL := strings.TrimSuffix(meta.BaseURL, "/")
return fmt.Sprintf("%s/anthropic/v1/messages", baseURL), nil return fmt.Sprintf("%s%s", baseURL, ThirdPartyAnthropicEndpoint), nil
} }
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error { func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {

View File

@@ -93,9 +93,15 @@ func ConvertRequest(textRequest model.GeneralOpenAIRequest) *Request {
if message.Role == "system" && claudeRequest.System.IsEmpty() { if message.Role == "system" && claudeRequest.System.IsEmpty() {
// Create a SystemPrompt from the string content // Create a SystemPrompt from the string content
systemPrompt := SystemPrompt{} systemPrompt := SystemPrompt{}
systemData := []byte(`"` + message.StringContent() + `"`) // Wrap in JSON string quotes systemData, err := json.Marshal(message.StringContent()) // Safely escape string for JSON
_ = systemPrompt.UnmarshalJSON(systemData) if err != nil {
claudeRequest.System = systemPrompt logger.SysError(fmt.Sprintf("Failed to marshal system prompt: %v", err))
} else {
if err := systemPrompt.UnmarshalJSON(systemData); err != nil {
logger.SysError(fmt.Sprintf("Failed to unmarshal system prompt: %v", err))
}
claudeRequest.System = systemPrompt
}
continue continue
} }
claudeMessage := Message{ claudeMessage := Message{

View File

@@ -142,6 +142,12 @@ func getAnthropicRequestBody(c *gin.Context, anthropicRequest *anthropic.Request
return bytes.NewBuffer(jsonData), nil return bytes.NewBuffer(jsonData), nil
} }
const (
// CHARS_PER_TOKEN represents the rough character-to-token ratio for Anthropic models
// This is a conservative estimate: approximately 1 token per 4 characters
CHARS_PER_TOKEN = 4
)
func estimateAnthropicTokens(request *anthropic.Request) int { func estimateAnthropicTokens(request *anthropic.Request) int {
// Simple token estimation for Anthropic requests // Simple token estimation for Anthropic requests
// This is a rough estimation, actual implementation might need more sophisticated logic // This is a rough estimation, actual implementation might need more sophisticated logic
@@ -150,14 +156,14 @@ func estimateAnthropicTokens(request *anthropic.Request) int {
// Count tokens in system prompt // Count tokens in system prompt
if !request.System.IsEmpty() { if !request.System.IsEmpty() {
systemText := request.System.String() systemText := request.System.String()
totalTokens += len(systemText) / 4 // rough estimate: 1 token per 4 characters totalTokens += len(systemText) / CHARS_PER_TOKEN // rough estimate: 1 token per 4 characters
} }
// Count tokens in messages // Count tokens in messages
for _, message := range request.Messages { for _, message := range request.Messages {
for _, content := range message.Content { for _, content := range message.Content {
if content.Type == "text" { if content.Type == "text" {
totalTokens += len(content.Text) / 4 totalTokens += len(content.Text) / CHARS_PER_TOKEN
} }
} }
} }