fix(cloudflare): Token 解码兼容 URL-safe base64 并发布 v1.6.6

This commit is contained in:
2026-09-28 17:48:09 +08:00
parent 3caff9fd8e
commit 26dd84abaa
9 changed files with 80 additions and 22 deletions
+26 -5
View File
@@ -20,12 +20,9 @@ func DecodeToken(token string) (accountTag, tunnelID, tunnelSecret string, err e
if clean == "" {
return "", "", "", fmt.Errorf("token 为空")
}
if remainder := len(clean) % 4; remainder != 0 {
clean += strings.Repeat("=", 4-remainder)
}
raw, err := base64.StdEncoding.DecodeString(clean)
raw, err := decodeBase64(clean)
if err != nil {
return "", "", "", fmt.Errorf("token base64 解码失败: %w", err)
return "", "", "", err
}
var payload tokenPayload
if err := json.Unmarshal(raw, &payload); err != nil || payload.TunnelID == "" {
@@ -45,6 +42,30 @@ func DecodeToken(token string) (accountTag, tunnelID, tunnelSecret string, err e
return payload.AccountTag, payload.TunnelID, payload.TunnelSecret, nil
}
// decodeBase64 同时兼容标准 base64 与 URL-safe base64,并兼容有无填充两种形式。
// Cloudflare 面板生成的 Tunnel Token 使用 URL-safe 编码,直接用标准 base64 会在 '-' / '_' 处失败。
func decodeBase64(input string) ([]byte, error) {
encodings := []*base64.Encoding{
base64.StdEncoding, base64.RawStdEncoding,
base64.URLEncoding, base64.RawURLEncoding,
}
for _, encoding := range encodings {
if data, err := encoding.DecodeString(input); err == nil {
return data, nil
}
}
padded := input
if remainder := len(padded) % 4; remainder != 0 {
padded += strings.Repeat("=", 4-remainder)
}
for _, encoding := range encodings {
if data, err := encoding.DecodeString(padded); err == nil {
return data, nil
}
}
return nil, fmt.Errorf("token base64 解码失败:请确认粘贴的是完整的 Cloudflare 隧道 token")
}
// CredentialsJSON 生成 cloudflared 需要的 creds.json 内容。
func CredentialsJSON(accountTag, tunnelID, tunnelSecret string) string {
data, _ := json.MarshalIndent(map[string]string{
+23
View File
@@ -1,6 +1,7 @@
package cloudflared
import (
"bytes"
"encoding/base64"
"strings"
"testing"
@@ -32,6 +33,28 @@ func TestDecodeTokenRejectsInvalid(t *testing.T) {
}
}
func TestDecodeTokenURLSafe(t *testing.T) {
payload := `{"a":"account-1","t":"tunnel-2","s":"secret-3"}`
encoded := base64.RawURLEncoding.EncodeToString([]byte(payload))
if _, _, _, err := DecodeToken(encoded); err != nil {
t.Fatalf("URL-safe token 应可解码: %v", err)
}
}
func TestDecodeBase64Flexible(t *testing.T) {
raw := []byte{0xfb, 0xef, 0xbe, 0xad}
for _, encoded := range []string{
base64.RawURLEncoding.EncodeToString(raw),
base64.URLEncoding.EncodeToString(raw),
base64.RawStdEncoding.EncodeToString(raw),
} {
got, err := decodeBase64(encoded)
if err != nil || !bytes.Equal(got, raw) {
t.Fatalf("编码 %q 解码失败:%v", encoded, err)
}
}
}
func TestBuildIngressInvariants(t *testing.T) {
got := BuildIngress([]string{"B.example.com", "a.example.com", "a.example.com", " "}, "http://127.0.0.1:80")
if len(got) != 3 {