package utils import ( "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "net/http" "net/url" "strings" "time" "github.com/google/uuid" "github.com/sirupsen/logrus" ) var ( log = logrus.New() client = &http.Client{} ) const ( endpointURL = "https://dev.microsofttranslator.com/apps/endpoint?api-version=1.0" userAgent = "okhttp/4.5.0" clientVersion = "4.0.530a 5fe1dc6c" homeGeographicRegion = "zh-Hans-CN" voiceDecodeKey = "oik6PdDdMnOXemTbwvMn9de/h9lFnfBaCWbGMMZqqoSaQaqUOqjVGm5NqsmjcBI1x+sS9ugjB55HEJWRiFXYFw==" ) func generateUserID() string { // 创建一个字节切片来存储随机数据 bytes := make([]byte, 8) // 8 字节 = 64 位 = 16 位十六进制字符串 _, err := rand.Read(bytes) if err != nil { return "" } // 将字节切片转换为十六进制字符串 userID := hex.EncodeToString(bytes) return userID } // GetEndpoint 获取语音合成服务的端点信息 func GetEndpoint() (map[string]interface{}, error) { signature := Sign(endpointURL) headers := map[string]string{ "Accept-Language": "zh-Hans", "X-ClientVersion": clientVersion, "X-UserId": generateUserID(), "X-HomeGeographicRegion": homeGeographicRegion, "X-ClientTraceId": uuid.New().String(), "X-MT-Signature": signature, "User-Agent": userAgent, "Content-Type": "application/json; charset=utf-8", "Content-Length": "0", "Accept-Encoding": "gzip", } req, err := http.NewRequest("POST", endpointURL, nil) if err != nil { return nil, err } for k, v := range headers { req.Header.Set(k, v) } resp, err := client.Do(req) if err != nil { log.Error("failed to do request: ", err) return nil, err } defer resp.Body.Close() var result map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&result) if err != nil { return nil, err } return result, nil } // Sign 生成签名 func Sign(urlStr string) string { u := strings.Split(urlStr, "://")[1] encodedUrl := url.QueryEscape(u) uuidStr := strings.ReplaceAll(uuid.New().String(), "-", "") formattedDate := strings.ToLower(time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")) + "gmt" bytesToSign := fmt.Sprintf("MSTranslatorAndroidApp%s%s%s", encodedUrl, formattedDate, uuidStr) bytesToSign = strings.ToLower(bytesToSign) decode, _ := base64.StdEncoding.DecodeString(voiceDecodeKey) hash := hmac.New(sha256.New, decode) hash.Write([]byte(bytesToSign)) secretKey := hash.Sum(nil) signBase64 := base64.StdEncoding.EncodeToString(secretKey) return fmt.Sprintf("MSTranslatorAndroidApp::%s::%s::%s", signBase64, formattedDate, uuidStr) }