Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions relay/channel/zhipu_4v/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {

func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
channel.SetupApiRequestHeader(info, c, req)
token := getZhipuToken(info.ApiKey)
req.Set("Authorization", token)
req.Set("Authorization", "Bearer "+info.ApiKey)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Harden header construction: trim, handle pre-prefixed keys, and empty key guard.

Minor robustness improvements:

  • Return an explicit error if info.ApiKey is empty to avoid a guaranteed 401.
  • Trim whitespace and avoid double “Bearer ” when the configured key is already prefixed.

Apply this diff within SetupRequestHeader:

-  req.Set("Authorization", "Bearer "+info.ApiKey)
+  if strings.TrimSpace(info.ApiKey) == "" {
+    return errors.New("missing API key for Zhipu channel")
+  }
+  ak := strings.TrimSpace(info.ApiKey)
+  if strings.HasPrefix(strings.ToLower(ak), "bearer ") {
+    req.Set("Authorization", ak)
+  } else {
+    req.Set("Authorization", "Bearer "+ak)
+  }

And add the import:

import "strings"

Verification (ensure no stale JWT usage remains and check for already-prefixed keys):


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find any references to the removed JWT helper to prevent build-time surprises.
rg -n --hidden --glob '!*dist*' --glob '!*build*' 'getZhipuToken|jwt' || echo "No references to getZhipuToken/jwt found."

# Spot other Authorization constructions for consistency.
rg -n 'Authorization"\s*,\s*"Bearer\s*\+.*ApiKey' -A2 -B2 || true

# Find places where API keys may already include 'Bearer ' to gauge risk.
rg -n 'ApiKey.*Bearer' -A2 -B2 || true

Length of output: 2387


Let's locate and inspect SetupRequestHeader in the zhipu_4v adapter to verify if the trimming/prefix patch has already been applied:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the zhipu_4v adaptor file
echo "Searching for zhipu_4v/adaptor.go..."
find relay/channel -type f | grep 'zhipu_4v/adaptor.go' || true

# Show the SetupRequestHeader implementation around line 57
echo "Extracting SetupRequestHeader definition from zhipu_4v/adaptor.go..."
rg -n -A5 -B5 'func SetupRequestHeader' relay/channel/zhipu_4v/adaptor.go || true

Length of output: 422


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for occurrences of info.ApiKey to locate the header setup
echo "Searching for info.ApiKey usages..."
rg -n 'info\.ApiKey' -A5 -B5

Length of output: 28759


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Display the package declaration and imports for relay/channel/zhipu_4v/adaptor.go
sed -n '1,60p' relay/channel/zhipu_4v/adaptor.go

Length of output: 1700


Improve Zhipu 4v Authorization header handling

Please harden SetupRequestHeader in relay/channel/zhipu_4v/adaptor.go to guard against empty or already-prefixed API keys:

• Return an explicit error when info.ApiKey is blank.
• Trim surrounding whitespace.
• Detect and avoid double-“Bearer ” prefixes.

Apply this patch:

diff --git a/relay/channel/zhipu_4v/adaptor.go b/relay/channel/zhipu_4v/adaptor.go
index abc1234..def5678 100644
--- a/relay/channel/zhipu_4v/adaptor.go
+++ b/relay/channel/zhipu_4v/adaptor.go
@@ -1,7 +1,8 @@
 import (
     "errors"
+    "strings"
     "fmt"
     "io"
     "net/http"
@@ -55,7 +56,16 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
     channel.SetupApiRequestHeader(info, c, req)
-    req.Set("Authorization", "Bearer "+info.ApiKey)
+    // Guard empty key
+    if strings.TrimSpace(info.ApiKey) == "" {
+        return errors.New("missing API key for Zhipu channel")
+    }
+    // Trim and handle existing Bearer prefix
+    ak := strings.TrimSpace(info.ApiKey)
+    if strings.HasPrefix(strings.ToLower(ak), "bearer ") {
+        req.Set("Authorization", ak)
+    } else {
+        req.Set("Authorization", "Bearer "+ak)
+    }
     return nil
 }

This ensures consistent behavior and clearer errors when the key is invalid.

🤖 Prompt for AI Agents
In relay/channel/zhipu_4v/adaptor.go at line 57, improve the SetupRequestHeader
function by first checking if info.ApiKey is empty or only whitespace and return
an explicit error if so. Then trim any surrounding whitespace from info.ApiKey.
Before setting the Authorization header, detect if the key already starts with
"Bearer " to avoid double prefixing. If it does not, prepend "Bearer " to the
trimmed key. This ensures the header is set consistently and errors are clear
when the API key is invalid.

return nil
}

Expand Down
59 changes: 0 additions & 59 deletions relay/channel/zhipu_4v/relay-zhipu_v4.go
Original file line number Diff line number Diff line change
@@ -1,69 +1,10 @@
package zhipu_4v

import (
"github.com/golang-jwt/jwt"
"one-api/common"
"one-api/dto"
"strings"
"sync"
"time"
)

// https://open.bigmodel.cn/doc/api#chatglm_std
// chatglm_std, chatglm_lite
// https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/invoke
// https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/sse-invoke

var zhipuTokens sync.Map
var expSeconds int64 = 24 * 3600

func getZhipuToken(apikey string) string {
data, ok := zhipuTokens.Load(apikey)
if ok {
tokenData := data.(tokenData)
if time.Now().Before(tokenData.ExpiryTime) {
return tokenData.Token
}
}

split := strings.Split(apikey, ".")
if len(split) != 2 {
common.SysError("invalid zhipu key: " + apikey)
return ""
}

id := split[0]
secret := split[1]

expMillis := time.Now().Add(time.Duration(expSeconds)*time.Second).UnixNano() / 1e6
expiryTime := time.Now().Add(time.Duration(expSeconds) * time.Second)

timestamp := time.Now().UnixNano() / 1e6

payload := jwt.MapClaims{
"api_key": id,
"exp": expMillis,
"timestamp": timestamp,
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)

token.Header["alg"] = "HS256"
token.Header["sign_type"] = "SIGN"

tokenString, err := token.SignedString([]byte(secret))
if err != nil {
return ""
}

zhipuTokens.Store(apikey, tokenData{
Token: tokenString,
ExpiryTime: expiryTime,
})

return tokenString
}

func requestOpenAI2Zhipu(request dto.GeneralOpenAIRequest) *dto.GeneralOpenAIRequest {
messages := make([]dto.Message, 0, len(request.Messages))
for _, message := range request.Messages {
Expand Down