Przeglądaj źródła

接入小七sdk

lt 1 miesiąc temu
rodzic
commit
8f23d894b6

+ 73 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_msg.go

@@ -126,6 +126,10 @@ func init() {
 				LoginVerifyDNGoogleAndroidSign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId, msg.CryptPass)
 			case model.SDKPlatform_Xuan_Google_Ios:
 				LoginVerifyDNGoogleIosSign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId, msg.CryptPass)
+			case model.SDKPlatform_QI_Ios:
+				fallthrough
+			case model.SDKPlatform_QI_Android:
+				LoginVerifyHwXiaoQiSign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId)
 			}
 			return
 
@@ -513,6 +517,75 @@ func LoginVerifyHwQuickSign(clientId uint64, GateServiceNode string, platform st
 	}()
 }
 
+func getmd5(s string) string {
+	hash := md5.Sum([]byte(s))
+	return hex.EncodeToString(hash[:])
+}
+
+// 海外小七
+func LoginVerifyHwXiaoQiSign(clientId uint64, GateServiceNode string, platform string, token string, openId string) {
+	go func() {
+		defer func() {
+			//打印奔溃信息
+			if err := recover(); err != nil {
+				util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
+			}
+		}()
+		sign := getmd5("appkey") + getmd5(token)
+		//tmpRequest := &XiaoQILoginResp{}
+		urlPath := "https://api.x7sy.com/user/check_v4_login?tokenkey=" + token + "&sign=" + sign
+		util.InfoF("urlPath=%v", urlPath)
+
+		resp, err := http.Get(urlPath)
+		if err != nil {
+			util.ErrorF("login sdk check error:%v", err)
+		}
+		defer resp.Body.Close() // 确保关闭响应体
+
+		// 读取响应体
+		body, _ := io.ReadAll(resp.Body)
+		res := string(body)
+		//err := httpNode.(rocommon.HTTPConnector).Request("GET", urlPath, tmpRequest)
+		util.InfoF("tmpRequest.ResMsg:%v", res)
+		tmpResMsg := &SDKHwQuickLoginAuthCheckResp{
+			Status: true,
+		}
+		var resRu XiaoQILoginResp
+		err = json.Unmarshal(body, &resRu)
+		if err != nil {
+			util.ErrorF("auth login json Unmarshal err:%v", err)
+		}
+
+		tmpResMsg.Message = strconv.Itoa(int(resRu.Errorno))
+		tmpResMsg.ClientId = clientId
+		tmpResMsg.ServiceId = GateServiceNode
+		tmpResMsg.OpenId = openId
+		tmpResMsg.Platform = platform
+		if err != nil || tmpResMsg.Message != "0" {
+			tmpResMsg.Status = false
+			util.ErrorF("uid=%v http Request openid=%v err=%v", clientId, openId, err)
+			util.ErrorF("uid=%v http Request2 openid=%v err=%v", clientId, openId, resRu)
+		}
+		GetAuthCheckMag().AddCheckList(tmpResMsg)
+	}()
+}
+
+type XiaoQILoginResp struct {
+	Errorno  int32  `json:"errorno"`
+	Errormsg string `json:"errormsg"`
+	Data     Data   `json:"data"`
+}
+
+type Data struct {
+	Guid       string `json:"guid"`
+	Username   string `json:"username"`
+	IsRealUser string `json:"is_real_user"`
+	IsEighteen string `json:"is_eighteen"`
+	Si         string `json:"si"`
+	Pi         string `json:"pi"`
+	Di         string `json:"di"`
+}
+
 func LoginVerifyGNQuickSign(clientId uint64, GateServiceNode string, platform string, token string, openId string) {
 	//authHttpAddr := ""
 	urlPath := ""

+ 2 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/orm_common.go

@@ -26,6 +26,8 @@ const (
 	SDKPlatform_Xuan_Ios            = "XUAN_YOU_IOS"
 	SDKPlatform_Xuan_Google_Android = "XUAN_YOU_Google_Android"
 	SDKPlatform_Xuan_Google_Ios     = "XUAN_YOU_Google_Ios"
+	SDKPlatform_QI_Android          = "Android_X7" //东南亚
+	SDKPlatform_QI_Ios              = "IOS_X7"
 
 	/* sub_platform
 	changemeng_xjgl    畅梦包

+ 3 - 2
RO_Server_Trunk-branch_0.1.39/roserver/gmweb/main.go

@@ -167,8 +167,9 @@ func main() {
 		router.POST("/pay/hwQucikFromS1GmWeb", msg.WebPayHwQuickNotifyFromS1GmWeb) // 海外quick 1服转发到其他服,这里接收
 		//router.POST("/pay/nb", msg.WebPayNBSDKNotify)	// 畅梦牛逼SDK
 		router.POST("/pay/uni", msg.WebPayUniSDKNotify)
-		router.POST("/pay/nbh5", msg.WebPayNBH5Notify)   // 畅梦h5
-		router.POST("/pay/mycard", msg.WebPayNBH5Notify) // mycard回调
+		router.POST("/pay/nbh5", msg.WebPayNBH5Notify)       // 畅梦h5
+		router.POST("/pay/mycard", msg.WebPayNBH5Notify)     // mycard回调
+		router.POST("/pay/xiaoqi", msg.WebPayHwXiaoQiNotify) // 海外小七回调
 
 		//
 		r1.GET("/guildbattle", msg.WebGmProcessGuildBattle)

+ 333 - 16
RO_Server_Trunk-branch_0.1.39/roserver/gmweb/msg/web_paymsg.go

@@ -2,11 +2,18 @@ package msg
 
 import (
 	"bytes"
+	"crypto"
 	"crypto/hmac"
 	"crypto/md5"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/x509"
 	"database/sql"
+	"encoding/base64"
 	"encoding/hex"
 	"encoding/json"
+	"encoding/pem"
 	"encoding/xml"
 	"fmt"
 	"io"
@@ -159,6 +166,29 @@ func getMd5Sign(callbackKey string, params map[string]string) string {
 	return hex.EncodeToString(hash[:])
 }
 
+func getMd5SignXiaoqi(params map[string]string) string {
+	// 删除参数中的 sign 字段
+	delete(params, "sign_data")
+
+	// 按参数名进行升序排序
+	var keys []string
+	for key := range params {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+
+	// 拼接参数和值
+	var signKey strings.Builder
+	for _, key := range keys {
+		signKey.WriteString(key)
+		signKey.WriteString("=")
+		signKey.WriteString(params[key])
+		signKey.WriteString("&")
+	}
+
+	return signKey.String()
+}
+
 func getMd5RuSign(callbackKey string, params map[string]string) string {
 	// 删除参数中的 sign 字段
 	delete(params, "sign")
@@ -318,25 +348,312 @@ func WebPayHwQuickNotify(c *gin.Context) {
 	}
 	webPayNotify(ntfData, float32(f64), c)
 
-	//// 简单粗暴,直接给其他服转发,不需要确认是哪个服
-	//payPostRouter := service.GetServiceConfig().SDKConfig.PayPostRouter
-	//util.WarnF("paycallback payPostRouter:%v\n", payPostRouter)
-	//// 组装转发body
-	//params["sign"] = sign
-	//var routerStr strings.Builder
-	//for key, value := range params {
-	//	routerStr.WriteString(key)
-	//	routerStr.WriteString("=")
-	//	routerStr.WriteString(value)
-	//	routerStr.WriteString("&")
-	//}
-	//routerString := routerStr.String()
-	//util.WarnF("paycallback routerString:%v\n", routerString)
-	//go sendPosts(payPostRouter, routerString)
-
 	c.String(http.StatusOK, "SUCCESS")
 }
 
+// 海外版xiaoqi回调
+func WebPayHwXiaoQiNotify(c *gin.Context) {
+	//util.DebugF("支付回调信息:%v", c.Request.PostForm)
+	params := make(map[string]string)
+	if err := c.Request.ParseForm(); err != nil {
+		util.InfoF("parseForm falied")
+		c.String(http.StatusOK, "FAILED")
+		return
+	}
+	util.DebugF("支付回调信息2:%v", c.Request.PostForm)
+	for key, value := range c.Request.PostForm {
+		params[key] = value[0] // 假设每个参数只有一个值
+	}
+	info2 := params["extends_info_data"]
+	info := strings.ReplaceAll(info2, "\\", "")
+	var extras Extras
+	err := json.Unmarshal([]byte(info), &extras)
+	if err != nil {
+		util.ErrorF("支付回调参数解析错误:%v", err)
+	}
+	util.InfoF("xiaoqi 透传参数:%v   params:%v", extras, params)
+	if extras.Platform == "IOS_X7" || extras.Bima == "IOS_X7" {
+		util.ErrorF("xiaoqi ios 支付签名认证:%v", info)
+		b, err2 := VerifySignature(params, "key")
+		if err2 != nil || !b {
+			util.ErrorF("签名错误%v", err2)
+			c.String(http.StatusOK, "FAILED")
+			return
+		}
+	} else {
+		util.ErrorF("android 支付签名认证:%v", info)
+		b, err2 := VerifySignature(params, "key")
+		if err2 != nil || !b {
+			util.ErrorF("签名错误%v", err2)
+			c.String(http.StatusOK, "FAILED")
+			return
+		}
+	}
+	myData, err3 := DecryptDataToMap(params["encryp_data"], "key")
+	if err3 != nil {
+		util.ErrorF("解析encryp_data error:%v", err3)
+		c.String(http.StatusOK, "FAILED")
+		return
+	}
+	uid := myData["uid"]
+	cpOrderId := myData["game_orderid"]
+	if cpOrderId == "" {
+		if extras.CpOrderId != "" {
+			cpOrderId = extras.CpOrderId
+		} else {
+			util.ErrorF("mycard pay cporderId is nil extras:%v", extras)
+		}
+	}
+	orderNo := myData["xiao7_goid"]
+	payCurrency := myData["game_currency"]
+	payType := myData["game_currency"]
+	usdAmount := myData["pay_price"]
+	ntfData := &WebNotifyData{}
+	ntfData.CpOrderId = cpOrderId
+	ntfData.SdkOrderId = orderNo
+	ntfData.PayMethod = payType
+	ntfData.PayCurrency = payCurrency
+	ntfData.PayTime = uint64(util.GetTimeSeconds())
+	ntfData.PayChannel = "xiaoqi"
+	util.WarnF("paycallback uid=%v cpOrderNo=%v orderNo=%v payAmount=%v payCurrency=%v payType=%v usdAmount=%v",
+		uid, cpOrderId, orderNo, usdAmount, payCurrency, payType, usdAmount)
+	f64, err := strconv.ParseFloat(usdAmount, 32)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	webPayNotify(ntfData, float32(f64), c)
+
+	c.String(http.StatusOK, "success")
+}
+func DecryptDataToMap(encrypDataBase64 string, privateKeyStr string) (map[string]string, error) {
+	// 1. Base64 解码得到 raw_encryp_data
+	rawEncrypData, err := base64.StdEncoding.DecodeString(encrypDataBase64)
+	if err != nil {
+		return nil, fmt.Errorf("base64解码失败: %v", err)
+	}
+
+	// 2. 使用 RSA 私钥解密
+	decryptedData, err := rsaPrivateDecrypt(rawEncrypData, privateKeyStr)
+	if err != nil {
+		return nil, fmt.Errorf("RSA解密失败: %v", err)
+	}
+
+	// 3. 解析查询字符串为 map
+	return parseQueryStringToMap(string(decryptedData)), nil
+}
+
+// rsaPrivateDecrypt RSA私钥解密
+func rsaPrivateDecrypt(ciphertext []byte, privateKeyStr string) ([]byte, error) {
+	// 解析私钥
+	privateKey, err := parsePrivateKey(privateKeyStr)
+	if err != nil {
+		return nil, err
+	}
+
+	// RSA 私钥解密(PKCS1v15 填充)
+	plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, ciphertext)
+	if err != nil {
+		return nil, fmt.Errorf("解密失败: %v", err)
+	}
+
+	return plaintext, nil
+}
+
+// parsePrivateKey 解析 PEM 格式的私钥
+func parsePrivateKey(privateKeyStr string) (*rsa.PrivateKey, error) {
+	// 去除空白字符
+	privateKeyStr = strings.TrimSpace(privateKeyStr)
+
+	// 确保是 PEM 格式
+	if !strings.Contains(privateKeyStr, "-----BEGIN") {
+		privateKeyStr = "-----BEGIN RSA PRIVATE KEY-----\n" +
+			privateKeyStr +
+			"\n-----END RSA PRIVATE KEY-----"
+	}
+
+	// 解码 PEM
+	block, _ := pem.Decode([]byte(privateKeyStr))
+	if block == nil {
+		return nil, fmt.Errorf("PEM解码失败")
+	}
+
+	// 解析私钥(支持 PKCS1 和 PKCS8 格式)
+	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		// 尝试 PKCS8 格式
+		key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+		if err != nil {
+			return nil, fmt.Errorf("解析私钥失败: %v", err)
+		}
+		var ok bool
+		privateKey, ok = key.(*rsa.PrivateKey)
+		if !ok {
+			return nil, fmt.Errorf("不是RSA私钥")
+		}
+		return privateKey, nil
+	}
+
+	return privateKey, nil
+}
+
+// parseQueryStringToMap 解析查询字符串为 map
+func parseQueryStringToMap(queryStr string) map[string]string {
+	params := make(map[string]string)
+
+	if queryStr == "" {
+		return params
+	}
+
+	pairs := strings.Split(queryStr, "&")
+	for _, pair := range pairs {
+		if pair == "" {
+			continue
+		}
+
+		kv := strings.SplitN(pair, "=", 2)
+		if len(kv) == 2 {
+			params[kv[0]] = kv[1]
+		} else if len(kv) == 1 {
+			params[kv[0]] = ""
+		}
+	}
+
+	return params
+}
+
+func VerifySignature(params map[string]string, publicKeyStr string) (bool, error) {
+	// 1. 获取并解码 sign_data 参数
+	signDataBase64, ok := params["sign_data"]
+	if !ok {
+		return false, fmt.Errorf("缺少 sign_data 参数")
+	}
+
+	// base64_decode 得到 raw_sign_data
+	rawSignData, err := base64.StdEncoding.DecodeString(signDataBase64)
+	if err != nil {
+		return false, fmt.Errorf("base64解码失败: %v", err)
+	}
+
+	// 2. 构建 source_str(排除 sign_data,其他参数按字典序排序)
+	sourceStr := buildSourceString(params)
+
+	// 3. 验证签名
+	err = verifyWithPublicKey(sourceStr, rawSignData, publicKeyStr)
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+// buildSourceString 构建查询字符串(排除 sign_data,按字典序排序)
+func buildSourceString(params map[string]string) string {
+	// 收集除 sign_data 外的所有键
+	keys := make([]string, 0)
+	for key := range params {
+		if key != "sign_data" {
+			keys = append(keys, key)
+		}
+	}
+
+	// 字典序排序
+	sort.Strings(keys)
+
+	// 拼接成 key=value&key=value 格式
+	var pairs []string
+	for _, key := range keys {
+		value := params[key]
+		pairs = append(pairs, fmt.Sprintf("%s=%s", key, value))
+	}
+
+	return strings.Join(pairs, "&")
+}
+
+// verifyWithPublicKey 使用公钥验证签名
+func verifyWithPublicKey(data string, signature []byte, publicKeyStr string) error {
+	// 1. 解析公钥(支持多种格式)
+	publicKey, err := parsePublicKey(publicKeyStr)
+	if err != nil {
+		return fmt.Errorf("解析公钥失败: %v", err)
+	}
+
+	// 2. 计算 SHA1 哈希
+	hash := sha1.Sum([]byte(data))
+
+	// 3. 验证签名
+	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hash[:], signature)
+	if err != nil {
+		return fmt.Errorf("签名验证失败: %v", err)
+	}
+
+	return nil
+}
+
+// parsePublicKey 解析 PEM 格式的公钥
+func parsePublicKey(publicKeyStr string) (*rsa.PublicKey, error) {
+	// 去除空白字符
+	publicKeyStr = strings.TrimSpace(publicKeyStr)
+
+	// 如果公钥字符串不包含 PEM 头,尝试添加
+	if !strings.Contains(publicKeyStr, "-----BEGIN") {
+		publicKeyStr = "-----BEGIN PUBLIC KEY-----\n" +
+			publicKeyStr +
+			"\n-----END PUBLIC KEY-----"
+	}
+
+	// 解码 PEM
+	block, _ := pem.Decode([]byte(publicKeyStr))
+	if block == nil {
+		return nil, fmt.Errorf("PEM解码失败")
+	}
+
+	// 解析公钥
+	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	publicKey, ok := pubInterface.(*rsa.PublicKey)
+	if !ok {
+		return nil, fmt.Errorf("不是RSA公钥")
+	}
+
+	return publicKey, nil
+}
+
+// parsePublicKey 解析 PEM 格式的公钥
+//func parsePublicKey(publicKeyStr string) (*rsa.PublicKey, error) {
+//	// 去除可能的空白字符
+//	publicKeyStr = strings.TrimSpace(publicKeyStr)
+//
+//	// 如果公钥字符串不包含 PEM 头,尝试添加
+//	if !strings.Contains(publicKeyStr, "-----BEGIN") {
+//		publicKeyStr = "-----BEGIN PUBLIC KEY-----\n" +
+//			publicKeyStr +
+//			"\n-----END PUBLIC KEY-----"
+//	}
+//
+//	// 解码 PEM
+//	block, _ := pem.Decode([]byte(publicKeyStr))
+//	if block == nil {
+//		return nil, fmt.Errorf("PEM 解码失败")
+//	}
+//
+//	// 解析公钥
+//	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
+//	if err != nil {
+//		return nil, err
+//	}
+//
+//	publicKey, ok := pubInterface.(*rsa.PublicKey)
+//	if !ok {
+//		return nil, fmt.Errorf("不是 RSA 公钥")
+//	}
+//
+//	return publicKey, nil
+//}
+
 func WebPayHwRuNotify(c *gin.Context) {
 	//util.DebugF("支付回调信息:%v", c.Request.PostForm)
 	params := make(map[string]string)