web_paymsg.go 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  1. package msg
  2. import (
  3. "bytes"
  4. "crypto"
  5. "crypto/hmac"
  6. "crypto/md5"
  7. "crypto/rsa"
  8. "crypto/sha1"
  9. "crypto/x509"
  10. "database/sql"
  11. "encoding/base64"
  12. "encoding/hex"
  13. "encoding/json"
  14. "encoding/pem"
  15. "encoding/xml"
  16. "fmt"
  17. "io"
  18. "math/big"
  19. "net/http"
  20. "net/url"
  21. "rocommon/service"
  22. "rocommon/socket/mysql"
  23. "rocommon/util"
  24. "roserver/baseserver/model"
  25. gmweb "roserver/gmweb/model"
  26. selfmodel "roserver/gmweb/model"
  27. "roserver/serverproto"
  28. "sort"
  29. "strconv"
  30. "strings"
  31. "time"
  32. "github.com/gin-gonic/gin"
  33. )
  34. // https://blog.csdn.net/chunyouhai5703/article/details/100978656?utm_medium=distribute.pc_relevant.none-task-blog-title-1&spm=1001.2101.3001.4242
  35. type QuickPayNotify struct {
  36. XMLName xml.Name `xml:"quicksdk_message"`
  37. Message QuickTBData `xml:"message"`
  38. }
  39. type QuickTBData struct {
  40. IsTest bool `xml:"is_test"`
  41. Channel string `xml:"channel"`
  42. ChannelUid string `xml:"channel_uid"`
  43. GameOrder string `xml:"game_order"`
  44. PayTime string `xml:"pay_time"`
  45. Amount float32 `xml:"amount"`
  46. Status int32 `xml:"status"`
  47. ExtrasParams string `xml:"extras_params"`
  48. }
  49. /*
  50. <?xml version="1.0" encoding="UTF-8" standalone="no">
  51. <quicksdk_message>
  52. <message>
  53. <is_test>0</is_test>
  54. <channel>8888</channel>
  55. <channel_uid>231845</channel_uid>
  56. <game_order>123456789</game_order>
  57. <order_no>12520160612114220441168433</order_no>
  58. <pay_time>2016-06-12 11:42:20</pay_time>
  59. <amount>1.00</amount>
  60. <status>0</status>
  61. <extras_params>{1}_{2}</extras_params>
  62. </message>
  63. </quicksdk_message>
  64. */
  65. func WebPayQuickNotify(c *gin.Context) {
  66. //ntData := c.PostForm("nt_data")
  67. //sign := c.PostForm("sign")
  68. //md5Sign := c.PostForm("md5Sign")
  69. //
  70. //data := ntData + sign + service.GetServiceConfig().SDKConfig.QuickMd5key
  71. //tmpSign := md5.Sum([]byte(data))
  72. //md5Str := fmt.Sprintf("%x", tmpSign)
  73. //util.DebugF("WebPayQuickNotify ntData=%v sign=%v md5sign=%v tmpsign=%v", ntData, sign, md5Sign, md5Str)
  74. //if md5Str == md5Sign {
  75. // util.InfoF("WebPayQuickNotify ok")
  76. //} else {
  77. // util.ErrorF("WebPayQuickNotify sign invalid!!!")
  78. // c.JSON(http.StatusOK, "FAILED")
  79. // return
  80. //}
  81. //
  82. ////decode nt_data
  83. //tmpNtDataList := strings.Split(ntData, "@")
  84. //tmpNtData := make([]byte, len(tmpNtDataList))
  85. //tmpKeyData := []byte(service.GetServiceConfig().SDKConfig.QuickCallbackKey)
  86. //for idx := 1; idx < len(tmpNtDataList); idx++ {
  87. // tmpVal, _ := strconv.Atoi(tmpNtDataList[idx])
  88. // tmpNtData[idx] = (byte)(tmpVal - (int)(0xff&tmpKeyData[(idx-1)%len(tmpKeyData)]))
  89. //}
  90. ////字符串最前面会有一个空格
  91. //if string(tmpNtData[0]) == "\u0000" {
  92. // tmpNtData = append(tmpNtData[:0], tmpNtData[1:]...)
  93. //}
  94. //util.InfoF("WebPayQuickNotify ntdata=%v", string(tmpNtData))
  95. //
  96. //tmpSt := &QuickPayNotify{}
  97. //err := xml.Unmarshal(tmpNtData, tmpSt)
  98. //if err != nil {
  99. // util.ErrorF("WebPayQuickNotify xml decode err=%v", err)
  100. // c.JSON(http.StatusOK, "FAILED")
  101. // return
  102. //}
  103. //
  104. //ntfData := &WebNotifyData{}
  105. //ntfData.CpOrderId = tmpSt.Message.GameOrder
  106. //ntfData.SdkOrderId = ""
  107. //ntfData.PayMethod = ""
  108. //ntfData.PayCurrency = ""
  109. //ntfData.PayTime = uint64(util.GetTimeSeconds())
  110. //ntfData.PayChannel = ""
  111. //webPayNotify(ntfData, tmpSt.Message.Amount, c)
  112. //c.JSON(http.StatusOK, "SUCCESS")
  113. game_order := c.PostForm("game_order") //游戏订单号
  114. order_no := c.PostForm("order_no") //SDK订单ID
  115. amount := c.PostForm("amount") //充值金额
  116. PayChannel := c.PostForm("channel") //充值渠道
  117. serverId := c.PostForm("server_id") //充值服ID
  118. util.DebugF("收到充值订单:GameOrder=%v, SdkOfderId=%v, PauAmount=%v, PayChannel=%v, serverId=%v", game_order, order_no, amount, PayChannel, serverId)
  119. checkPayAmount, _ := model.Str2Float32(amount)
  120. ntfData := &WebNotifyData{}
  121. ntfData.CpOrderId = game_order
  122. ntfData.SdkOrderId = order_no
  123. ntfData.PayMethod = ""
  124. ntfData.PayCurrency = ""
  125. ntfData.PayTime = uint64(util.GetTimeSeconds())
  126. ntfData.PayChannel = PayChannel
  127. retState := webPayNotify(ntfData, checkPayAmount, c)
  128. //c.JSON(http.StatusOK, `success`)
  129. c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte(retState))
  130. }
  131. func getMd5Sign(callbackKey string, params map[string]string) string {
  132. // 删除参数中的 sign 字段
  133. delete(params, "sign")
  134. // 按参数名进行升序排序
  135. var keys []string
  136. for key := range params {
  137. keys = append(keys, key)
  138. }
  139. sort.Strings(keys)
  140. // 拼接参数和值
  141. var signKey strings.Builder
  142. for _, key := range keys {
  143. signKey.WriteString(key)
  144. signKey.WriteString("=")
  145. signKey.WriteString(params[key])
  146. signKey.WriteString("&")
  147. }
  148. // 添加回调密钥
  149. signKey.WriteString(callbackKey)
  150. // 计算 MD5
  151. hash := md5.Sum([]byte(signKey.String()))
  152. return hex.EncodeToString(hash[:])
  153. }
  154. func getMd5SignXiaoqi(params map[string]string) string {
  155. // 删除参数中的 sign 字段
  156. delete(params, "sign_data")
  157. // 按参数名进行升序排序
  158. var keys []string
  159. for key := range params {
  160. keys = append(keys, key)
  161. }
  162. sort.Strings(keys)
  163. // 拼接参数和值
  164. var signKey strings.Builder
  165. for _, key := range keys {
  166. signKey.WriteString(key)
  167. signKey.WriteString("=")
  168. signKey.WriteString(params[key])
  169. signKey.WriteString("&")
  170. }
  171. return signKey.String()
  172. }
  173. func getMd5RuSign(callbackKey string, params map[string]string) string {
  174. // 删除参数中的 sign 字段
  175. delete(params, "sign")
  176. // 按参数名进行升序排序
  177. var keys []string
  178. for key := range params {
  179. keys = append(keys, key)
  180. }
  181. sort.Strings(keys)
  182. // 拼接参数和值
  183. var signKey strings.Builder
  184. for i, key := range keys {
  185. signKey.WriteString(key)
  186. signKey.WriteString("=")
  187. signKey.WriteString(params[key])
  188. if i != len(keys)-1 {
  189. signKey.WriteString("&")
  190. }
  191. }
  192. // 添加回调密钥
  193. signKey.WriteString(callbackKey)
  194. // 计算 MD5
  195. hash := md5.Sum([]byte(signKey.String()))
  196. return hex.EncodeToString(hash[:])
  197. }
  198. func getMd5DnSign(callbackKey string, username, order_id, server, amount, extra, sandbox, timestamp string) string {
  199. // 拼接参数和值
  200. var signKey strings.Builder
  201. signKey.WriteString(username)
  202. signKey.WriteString(order_id)
  203. signKey.WriteString(server)
  204. signKey.WriteString(amount)
  205. signKey.WriteString(extra)
  206. signKey.WriteString(sandbox)
  207. signKey.WriteString(timestamp)
  208. // 添加回调密钥
  209. signKey.WriteString(callbackKey)
  210. // 计算 MD5
  211. hash := md5.Sum([]byte(signKey.String()))
  212. return hex.EncodeToString(hash[:])
  213. }
  214. type Extras struct {
  215. ServerId int `json:"serverId"`
  216. Platform string `json:"platform"`
  217. SubPlatform string `json:"subPlatform"`
  218. Bima string `json:"bima"`
  219. CpOrderId string `json:"cpOrderId"`
  220. }
  221. type ExtrasRu struct {
  222. AccountId string `json:"accountId"`
  223. Money string `json:"money"`
  224. Addtime string `json:"addtime"`
  225. OrderId string `json:"orderId"`
  226. CustomorderId string `json:"customorderId"`
  227. Paytype string `json:"paytype"`
  228. Success string `json:"success"`
  229. }
  230. type ExtrasDn struct {
  231. OrderNo string `json:"orderNo"`
  232. Uid string `json:"uid"`
  233. Platform string `json:"platform"`
  234. GoodsId int32 `json:"goodsId"`
  235. GoodsType int32 `json:"goodsType"`
  236. }
  237. type ExtrasDnIos struct {
  238. OrderNo string `json:"biwb"`
  239. Uid string `json:"uid"`
  240. Platform string `json:"bivz"`
  241. GoodsId int32 `json:"goodsId"`
  242. GoodsType int32 `json:"goodsType"`
  243. }
  244. // 海外版quick回调
  245. func WebPayHwQuickNotify(c *gin.Context) {
  246. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  247. params := make(map[string]string)
  248. if err := c.Request.ParseForm(); err != nil {
  249. util.InfoF("parseForm falied")
  250. c.String(http.StatusOK, "FAILED")
  251. return
  252. }
  253. util.DebugF("支付回调信息2:%v", c.Request.PostForm)
  254. for key, value := range c.Request.PostForm {
  255. params[key] = value[0] // 假设每个参数只有一个值
  256. }
  257. sign := params["sign"]
  258. info2 := params["extrasParams"]
  259. info := strings.ReplaceAll(info2, "\\", "")
  260. var extras Extras
  261. err := json.Unmarshal([]byte(info), &extras)
  262. if err != nil {
  263. util.ErrorF("支付回调参数解析错误:%v", err)
  264. }
  265. util.InfoF("支付签名认证:%v params:%v", extras, params)
  266. if extras.Platform == "SDKYOUYI_IOS" || extras.Bima == "SDKYOUYI_IOS" {
  267. util.ErrorF("ios 支付签名认证:%v", info)
  268. newSign := getMd5Sign("58696021497436514481898335416221", params)
  269. if newSign != sign {
  270. util.ErrorF("签名错误%v", sign)
  271. c.String(http.StatusOK, "FAILED")
  272. return
  273. }
  274. } else if extras.Platform == "SDKYOUYI_IOS_MyCard" || extras.Platform == "SDKHwQuick_MyCard" {
  275. util.ErrorF("mycard 支付签名认证:%v", info)
  276. newSign := getMd5Sign("03422134397322604272901806704074", params)
  277. if newSign != sign {
  278. util.ErrorF("签名错误%v", sign)
  279. c.String(http.StatusOK, "FAILED")
  280. return
  281. }
  282. } else {
  283. util.ErrorF("android 支付签名认证:%v", info)
  284. newSign := getMd5Sign("47409863970932353623015025039223", params)
  285. if newSign != sign {
  286. util.ErrorF("签名错误%v", sign)
  287. c.String(http.StatusOK, "FAILED")
  288. return
  289. }
  290. }
  291. uid := c.PostForm("uid")
  292. cpOrderId := c.PostForm("cpOrderNo")
  293. if cpOrderId == "" {
  294. if extras.CpOrderId != "" {
  295. cpOrderId = extras.CpOrderId
  296. } else {
  297. util.ErrorF("mycard pay cporderId is nil extras:%v", extras)
  298. }
  299. }
  300. orderNo := c.PostForm("orderNo")
  301. payAmount := c.PostForm("payAmount")
  302. payCurrency := c.PostForm("payCurrency")
  303. payType := c.PostForm("payType")
  304. usdAmount := c.PostForm("usdAmount")
  305. ntfData := &WebNotifyData{}
  306. ntfData.CpOrderId = cpOrderId
  307. ntfData.SdkOrderId = orderNo
  308. ntfData.PayMethod = payType
  309. ntfData.PayCurrency = payCurrency
  310. ntfData.PayTime = uint64(util.GetTimeSeconds())
  311. ntfData.PayChannel = "qk_hw"
  312. util.WarnF("paycallback uid=%v cpOrderNo=%v orderNo=%v payAmount=%v payCurrency=%v payType=%v usdAmount=%v",
  313. uid, cpOrderId, orderNo, payAmount, payCurrency, payType, usdAmount)
  314. f64, err := strconv.ParseFloat(usdAmount, 32)
  315. if err != nil {
  316. fmt.Println("Error:", err)
  317. return
  318. }
  319. webPayNotify(ntfData, float32(f64), c)
  320. c.String(http.StatusOK, "SUCCESS")
  321. }
  322. // 海外版xiaoqi回调
  323. func WebPayHwXiaoQiNotify(c *gin.Context) {
  324. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  325. params := make(map[string]string)
  326. if err := c.Request.ParseForm(); err != nil {
  327. util.InfoF("parseForm falied")
  328. c.String(http.StatusOK, "FAILED")
  329. return
  330. }
  331. util.DebugF("支付回调信息2:%v", c.Request.PostForm)
  332. for key, value := range c.Request.PostForm {
  333. params[key] = value[0] // 假设每个参数只有一个值
  334. }
  335. info2 := params["extends_info_data"]
  336. info := strings.ReplaceAll(info2, "\\", "")
  337. var extras Extras
  338. err := json.Unmarshal([]byte(info), &extras)
  339. if err != nil {
  340. util.ErrorF("支付回调参数解析错误:%v", err)
  341. }
  342. util.InfoF("xiaoqi 透传参数:%v params:%v", extras, params)
  343. if extras.Platform == "IOS_X7" || extras.Bima == "IOS_X7" {
  344. util.ErrorF("xiaoqi ios 支付签名认证:%v", info)
  345. b, err2 := VerifySignature(params, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCfYd3FqSaWqCpWLSktBSSgAelt0F6T+tO4C25YKR/6X/sPacDBbX662/0fW+H+YbXigHWFB/yangkhiZTpD/VmiOo5lISX6L0/m+13ti9b8jzTZcfVngfLsP+Ztbk81N1Jk0gWF4bndZxREJ3IxcEDHnIrwXgLGA2GJ89kdgudwIDAQAB")
  346. if err2 != nil || !b {
  347. util.ErrorF("签名错误%v", err2)
  348. c.String(http.StatusOK, "FAILED")
  349. return
  350. }
  351. } else {
  352. util.ErrorF("android 支付签名认证:%v", info)
  353. b, err2 := VerifySignature(params, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCfYd3FqSaWqCpWLSktBSSgAelt0F6T+tO4C25YKR/6X/sPacDBbX662/0fW+H+YbXigHWFB/yangkhiZTpD/VmiOo5lISX6L0/m+13ti9b8jzTZcfVngfLsP+Ztbk81N1Jk0gWF4bndZxREJ3IxcEDHnIrwXgLGA2GJ89kdgudwIDAQAB")
  354. if err2 != nil || !b {
  355. util.ErrorF("签名错误%v", err2)
  356. c.String(http.StatusOK, "FAILED")
  357. return
  358. }
  359. }
  360. myData, err3 := DecryptDataToMap(params["encryp_data"], "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCfYd3FqSaWqCpWLSktBSSgAelt0F6T+tO4C25YKR/6X/sPacDBbX662/0fW+H+YbXigHWFB/yangkhiZTpD/VmiOo5lISX6L0/m+13ti9b8jzTZcfVngfLsP+Ztbk81N1Jk0gWF4bndZxREJ3IxcEDHnIrwXgLGA2GJ89kdgudwIDAQAB")
  361. if err3 != nil {
  362. util.ErrorF("解析encryp_data error:%v", err3)
  363. c.String(http.StatusOK, "FAILED")
  364. return
  365. }
  366. uid := myData["uid"]
  367. cpOrderId := myData["game_orderid"]
  368. if cpOrderId == "" {
  369. if extras.CpOrderId != "" {
  370. cpOrderId = extras.CpOrderId
  371. } else {
  372. util.ErrorF("mycard pay cporderId is nil extras:%v", extras)
  373. }
  374. }
  375. orderNo := myData["xiao7_goid"]
  376. payCurrency := myData["game_currency"]
  377. payType := myData["game_currency"]
  378. usdAmount := myData["pay_price"]
  379. ntfData := &WebNotifyData{}
  380. ntfData.CpOrderId = cpOrderId
  381. ntfData.SdkOrderId = orderNo
  382. ntfData.PayMethod = payType
  383. ntfData.PayCurrency = payCurrency
  384. ntfData.PayTime = uint64(util.GetTimeSeconds())
  385. ntfData.PayChannel = "xiaoqi"
  386. util.WarnF("paycallback uid=%v cpOrderNo=%v orderNo=%v payAmount=%v payCurrency=%v payType=%v usdAmount=%v",
  387. uid, cpOrderId, orderNo, usdAmount, payCurrency, payType, usdAmount)
  388. f64, err := strconv.ParseFloat(usdAmount, 32)
  389. if err != nil {
  390. fmt.Println("Error:", err)
  391. return
  392. }
  393. webPayNotify(ntfData, float32(f64), c)
  394. c.String(http.StatusOK, "success")
  395. }
  396. // 使用公钥解密(对应 PHP 的 openssl_public_decrypt)
  397. func DecryptDataToMap(encrypDataBase64 string, publicKeyStr string) (map[string]string, error) {
  398. // 1. Base64 解码得到 raw_encryp_data
  399. rawEncrypData, err := decodeBase64Compat(encrypDataBase64)
  400. if err != nil {
  401. return nil, fmt.Errorf("base64解码失败: %v", err)
  402. }
  403. // 2. 使用 RSA 公钥解密
  404. decryptedData, err := rsaPublicDecrypt(rawEncrypData, publicKeyStr)
  405. if err != nil {
  406. return nil, fmt.Errorf("RSA解密失败: %v", err)
  407. }
  408. // 3. 解析查询字符串为 map
  409. return parseQueryStringToMap(string(decryptedData)), nil
  410. }
  411. func rsaPublicDecrypt(ciphertext []byte, publicKeyStr string) ([]byte, error) {
  412. // 解析公钥
  413. publicKey, err := parsePublicKey(publicKeyStr)
  414. if err != nil {
  415. return nil, fmt.Errorf("解析公钥失败: %v", err)
  416. }
  417. keySize := (publicKey.N.BitLen() + 7) / 8
  418. if keySize == 0 {
  419. return nil, fmt.Errorf("无效RSA公钥")
  420. }
  421. if len(ciphertext)%keySize != 0 {
  422. return nil, fmt.Errorf("密文长度非法: len=%d keySize=%d", len(ciphertext), keySize)
  423. }
  424. // 兼容长消息分段密文(每段一个 RSA block)。
  425. plainData := make([]byte, 0, len(ciphertext))
  426. e := big.NewInt(int64(publicKey.E))
  427. for offset := 0; offset < len(ciphertext); offset += keySize {
  428. block := ciphertext[offset : offset+keySize]
  429. c := new(big.Int).SetBytes(block)
  430. if c.Cmp(publicKey.N) > 0 {
  431. return nil, fmt.Errorf("密文块超出模数范围")
  432. }
  433. m := new(big.Int).Exp(c, e, publicKey.N)
  434. em := leftPadToSize(m.Bytes(), keySize)
  435. plainBlock, err := unpadPKCS1v15ForPublicDecrypt(em)
  436. if err != nil {
  437. return nil, fmt.Errorf("块解密失败: %v", err)
  438. }
  439. plainData = append(plainData, plainBlock...)
  440. }
  441. return plainData, nil
  442. }
  443. func decodeBase64Compat(raw string) ([]byte, error) {
  444. // form-urlencoded 场景下,+ 可能被自动转为空格。
  445. s := strings.TrimSpace(strings.ReplaceAll(raw, " ", "+"))
  446. if s == "" {
  447. return nil, fmt.Errorf("空字符串")
  448. }
  449. encodings := []*base64.Encoding{
  450. base64.StdEncoding,
  451. base64.RawStdEncoding,
  452. base64.URLEncoding,
  453. base64.RawURLEncoding,
  454. }
  455. var lastErr error
  456. for _, enc := range encodings {
  457. data, err := enc.DecodeString(s)
  458. if err == nil {
  459. return data, nil
  460. }
  461. lastErr = err
  462. }
  463. return nil, lastErr
  464. }
  465. func leftPadToSize(src []byte, size int) []byte {
  466. if len(src) >= size {
  467. return src
  468. }
  469. dst := make([]byte, size)
  470. copy(dst[size-len(src):], src)
  471. return dst
  472. }
  473. // unpadPKCS1v15ForPublicDecrypt 兼容 openssl_public_decrypt 的 PKCS#1 v1.5 去填充。
  474. func unpadPKCS1v15ForPublicDecrypt(em []byte) ([]byte, error) {
  475. if len(em) < 11 {
  476. return nil, fmt.Errorf("EM 长度过短")
  477. }
  478. if em[0] != 0x00 {
  479. return nil, fmt.Errorf("EM 格式错误: 缺少前导0x00")
  480. }
  481. switch em[1] {
  482. case 0x01:
  483. i := 2
  484. for i < len(em) && em[i] == 0xFF {
  485. i++
  486. }
  487. if i < 10 {
  488. return nil, fmt.Errorf("PKCS#1 type1 填充长度不足")
  489. }
  490. if i >= len(em) || em[i] != 0x00 {
  491. return nil, fmt.Errorf("PKCS#1 type1 分隔符缺失")
  492. }
  493. return em[i+1:], nil
  494. case 0x02:
  495. // 某些渠道可能走普通公钥加密块,这里也做兼容。
  496. i := 2
  497. for i < len(em) && em[i] != 0x00 {
  498. i++
  499. }
  500. if i < 10 {
  501. return nil, fmt.Errorf("PKCS#1 type2 填充长度不足")
  502. }
  503. if i >= len(em) || em[i] != 0x00 {
  504. return nil, fmt.Errorf("PKCS#1 type2 分隔符缺失")
  505. }
  506. return em[i+1:], nil
  507. default:
  508. return nil, fmt.Errorf("不支持的填充类型: 0x%02x", em[1])
  509. }
  510. }
  511. // 解析查询字符串为 map
  512. func parseQueryStringToMap(queryStr string) map[string]string {
  513. result := make(map[string]string)
  514. // 按 & 分割
  515. pairs := strings.Split(queryStr, "&")
  516. for _, pair := range pairs {
  517. if pair == "" {
  518. continue
  519. }
  520. // 按 = 分割
  521. kv := strings.SplitN(pair, "=", 2)
  522. if len(kv) == 2 {
  523. // URL decode 值(如果需要)
  524. value, err := url.QueryUnescape(kv[1])
  525. if err != nil {
  526. value = kv[1]
  527. }
  528. result[kv[0]] = value
  529. } else if len(kv) == 1 {
  530. result[kv[0]] = ""
  531. }
  532. }
  533. return result
  534. }
  535. func VerifySignature(params map[string]string, publicKeyStr string) (bool, error) {
  536. // 1. 获取并解码 sign_data 参数
  537. signDataBase64, ok := params["sign_data"]
  538. if !ok {
  539. return false, fmt.Errorf("缺少 sign_data 参数")
  540. }
  541. // base64_decode 得到 raw_sign_data
  542. rawSignData, err := decodeBase64Compat(signDataBase64)
  543. if err != nil {
  544. return false, fmt.Errorf("base64解码失败: %v", err)
  545. }
  546. // 2. 构建 source_str(排除 sign_data,其他参数按字典序排序)
  547. sourceStr := buildSourceString(params)
  548. // 3. 验证签名
  549. err = verifyWithPublicKey(sourceStr, rawSignData, publicKeyStr)
  550. if err != nil {
  551. return false, err
  552. }
  553. return true, nil
  554. }
  555. // buildSourceString 构建查询字符串(排除 sign_data,按字典序排序)
  556. func buildSourceString(params map[string]string) string {
  557. // 收集除 sign_data 外的所有键
  558. keys := make([]string, 0)
  559. for key := range params {
  560. if key != "sign_data" {
  561. keys = append(keys, key)
  562. }
  563. }
  564. // 字典序排序
  565. sort.Strings(keys)
  566. // 拼接成 key=value&key=value 格式
  567. var pairs []string
  568. for _, key := range keys {
  569. value := params[key]
  570. pairs = append(pairs, fmt.Sprintf("%s=%s", key, value))
  571. }
  572. return strings.Join(pairs, "&")
  573. }
  574. // verifyWithPublicKey 使用公钥验证签名
  575. func verifyWithPublicKey(data string, signature []byte, publicKeyStr string) error {
  576. // 1. 解析公钥(支持多种格式)
  577. publicKey, err := parsePublicKey(publicKeyStr)
  578. if err != nil {
  579. return fmt.Errorf("解析公钥失败: %v", err)
  580. }
  581. // 2. 计算 SHA1 哈希
  582. hash := sha1.Sum([]byte(data))
  583. // 3. 验证签名
  584. err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hash[:], signature)
  585. if err != nil {
  586. return fmt.Errorf("签名验证失败: %v", err)
  587. }
  588. return nil
  589. }
  590. // parsePublicKey 解析 PEM 格式的公钥
  591. func parsePublicKey(publicKeyStr string) (*rsa.PublicKey, error) {
  592. // 去除空白字符
  593. publicKeyStr = strings.TrimSpace(publicKeyStr)
  594. // 如果公钥字符串不包含 PEM 头,尝试添加
  595. if !strings.Contains(publicKeyStr, "-----BEGIN") {
  596. publicKeyStr = "-----BEGIN PUBLIC KEY-----\n" +
  597. publicKeyStr +
  598. "\n-----END PUBLIC KEY-----"
  599. }
  600. // 解码 PEM
  601. block, _ := pem.Decode([]byte(publicKeyStr))
  602. if block == nil {
  603. return nil, fmt.Errorf("PEM解码失败")
  604. }
  605. // 解析公钥
  606. pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  607. if err != nil {
  608. return nil, err
  609. }
  610. publicKey, ok := pubInterface.(*rsa.PublicKey)
  611. if !ok {
  612. return nil, fmt.Errorf("不是RSA公钥")
  613. }
  614. return publicKey, nil
  615. }
  616. // parsePublicKey 解析 PEM 格式的公钥
  617. //func parsePublicKey(publicKeyStr string) (*rsa.PublicKey, error) {
  618. // // 去除可能的空白字符
  619. // publicKeyStr = strings.TrimSpace(publicKeyStr)
  620. //
  621. // // 如果公钥字符串不包含 PEM 头,尝试添加
  622. // if !strings.Contains(publicKeyStr, "-----BEGIN") {
  623. // publicKeyStr = "-----BEGIN PUBLIC KEY-----\n" +
  624. // publicKeyStr +
  625. // "\n-----END PUBLIC KEY-----"
  626. // }
  627. //
  628. // // 解码 PEM
  629. // block, _ := pem.Decode([]byte(publicKeyStr))
  630. // if block == nil {
  631. // return nil, fmt.Errorf("PEM 解码失败")
  632. // }
  633. //
  634. // // 解析公钥
  635. // pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  636. // if err != nil {
  637. // return nil, err
  638. // }
  639. //
  640. // publicKey, ok := pubInterface.(*rsa.PublicKey)
  641. // if !ok {
  642. // return nil, fmt.Errorf("不是 RSA 公钥")
  643. // }
  644. //
  645. // return publicKey, nil
  646. //}
  647. func WebPayHwRuNotify(c *gin.Context) {
  648. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  649. params := make(map[string]string)
  650. if err := c.Request.ParseForm(); err != nil {
  651. util.InfoF("parseForm falied")
  652. c.String(http.StatusOK, "FAILED")
  653. return
  654. }
  655. util.DebugF("支付回调信息2:%v", c.Request.PostForm)
  656. for key, value := range c.Request.PostForm {
  657. params[key] = value[0] // 假设每个参数只有一个值
  658. }
  659. sign := params["sign"]
  660. info2 := params["custominfo"]
  661. info := strings.ReplaceAll(info2, "\\", "")
  662. var extras Extras
  663. err := json.Unmarshal([]byte(info), &extras)
  664. if err != nil {
  665. util.ErrorF("支付回调参数解析错误:%v", err)
  666. }
  667. util.InfoF("支付签名认证:%v params:%v", extras, params)
  668. if extras.Platform == "ZT_IOS" || extras.Bima == "ZT_IOS" {
  669. util.ErrorF("ios 支付签名认证:%v", info)
  670. newSign := getMd5RuSign("80c648e7df8aaa72", params)
  671. if newSign != sign {
  672. util.ErrorF("签名错误%v", sign)
  673. c.String(http.StatusOK, "FAILED")
  674. return
  675. }
  676. } else if extras.Platform == "SDKYOUYI_IOS_MyCard" || extras.Platform == "SDKHwQuick_MyCard" {
  677. util.ErrorF("mycard 支付签名认证:%v", info)
  678. newSign := getMd5Sign("03422134397322604272901806704074", params)
  679. if newSign != sign {
  680. util.ErrorF("签名错误%v", sign)
  681. c.String(http.StatusOK, "FAILED")
  682. return
  683. }
  684. } else {
  685. util.ErrorF("android 支付签名认证:%v", info)
  686. newSign := getMd5RuSign("80c648e7df8aaa72", params)
  687. if newSign != sign {
  688. util.ErrorF("签名错误%v", sign)
  689. c.String(http.StatusOK, "FAILED")
  690. return
  691. }
  692. }
  693. uid := c.PostForm("account")
  694. cpOrderId := c.PostForm("customorderid")
  695. orderNo := c.PostForm("orderid")
  696. payAmount := c.PostForm("money")
  697. payCurrency := c.PostForm("currency")
  698. payType := c.PostForm("paytype")
  699. usdAmount := c.PostForm("doller")
  700. ntfData := &WebNotifyData{}
  701. ntfData.CpOrderId = cpOrderId
  702. ntfData.SdkOrderId = orderNo
  703. ntfData.PayMethod = payType
  704. ntfData.PayCurrency = payCurrency
  705. ntfData.PayTime = uint64(util.GetTimeSeconds())
  706. ntfData.PayChannel = "qk_hw"
  707. util.WarnF("paycallback uid=%v cpOrderNo=%v orderNo=%v payAmount=%v payCurrency=%v payType=%v usdAmount=%v",
  708. uid, cpOrderId, orderNo, payAmount, payCurrency, payType, usdAmount)
  709. f64, err := strconv.ParseFloat(payAmount, 32)
  710. if err != nil {
  711. fmt.Println("Error:", err)
  712. return
  713. }
  714. webPayNotify(ntfData, float32(f64), c)
  715. //// 简单粗暴,直接给其他服转发,不需要确认是哪个服
  716. //payPostRouter := service.GetServiceConfig().SDKConfig.PayPostRouter
  717. //util.WarnF("paycallback payPostRouter:%v\n", payPostRouter)
  718. //// 组装转发body
  719. //params["sign"] = sign
  720. //var routerStr strings.Builder
  721. //for key, value := range params {
  722. // routerStr.WriteString(key)
  723. // routerStr.WriteString("=")
  724. // routerStr.WriteString(value)
  725. // routerStr.WriteString("&")
  726. //}
  727. //routerString := routerStr.String()
  728. //util.WarnF("paycallback routerString:%v\n", routerString)
  729. //go sendPosts(payPostRouter, routerString)
  730. c.String(http.StatusOK, "success")
  731. }
  732. func WebPayHwDn2Notify(c *gin.Context) {
  733. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  734. orderId := c.DefaultQuery("order_id", "")
  735. payAmount := c.DefaultQuery("amount", "")
  736. sign := c.DefaultQuery("sign", "")
  737. extra := c.DefaultQuery("extra", "")
  738. username := c.DefaultQuery("username", "")
  739. server := c.DefaultQuery("server", "")
  740. sandbox := c.DefaultQuery("sandbox", "")
  741. timestamp := c.DefaultQuery("timestamp", "")
  742. var extras ExtrasDn
  743. err := json.Unmarshal([]byte(extra), &extras)
  744. if err != nil {
  745. util.ErrorF("支付回调参数解析错误:%v", err)
  746. }
  747. //cpOrderId := extras.OrderNo
  748. util.ErrorF("支付回调信息东南亚2:orderId:%v,payAmount:%v,sign:%v,extra:%v,username:%v,server:%v,sandbox:%v,timestamp:%v", orderId, payAmount, sign, extra, username, server, sandbox, timestamp)
  749. if extras.Platform == "XUAN_YOU_Google_Android" {
  750. if sign != getMd5DnSign("e81c2bd2ffb7feb7f0df477dc02b0bbd", username, orderId, server, payAmount, extra, sandbox, timestamp) {
  751. c.JSON(http.StatusOK, gin.H{"status": 1, "msg": "sign error"})
  752. return
  753. }
  754. } else if extras.Platform == "XUAN_YOU_IOS" {
  755. if sign != getMd5DnSign("3f8e9fec0794443f76d3a27cd41e2711", username, orderId, server, payAmount, extra, sandbox, timestamp) {
  756. c.JSON(http.StatusOK, gin.H{"status": 1, "msg": "sign error"})
  757. return
  758. }
  759. } else {
  760. if sign != getMd5DnSign("cee1b45a9aa02a75f9d720d6b9e7b7d4", username, orderId, server, payAmount, extra, sandbox, timestamp) {
  761. c.JSON(http.StatusOK, gin.H{"status": 1, "msg": "sign error"})
  762. return
  763. }
  764. }
  765. cpOrderId := extras.OrderNo
  766. if cpOrderId != "" {
  767. //f64, err := strconv.ParseFloat(payAmount, 64)
  768. //if err != nil {
  769. // fmt.Println("Error:", err)
  770. // return
  771. //}
  772. util.WarnF("paycallbackDn2 uid=%v cpOrderNo=%v orderNo=%v payAmount=%v",
  773. extras.Uid, cpOrderId, orderId, payAmount)
  774. res := webPayNotifyDn(cpOrderId, payAmount, orderId)
  775. if res == "SUCCESS" {
  776. c.JSON(http.StatusOK, gin.H{"status": 0})
  777. } else {
  778. c.JSON(http.StatusOK, gin.H{"status": 1, "msg": "order already complete"})
  779. }
  780. } else { //走的网页支付流程游戏这边没有orderid,只发代金券礼包
  781. for _, v := range ResDnyPayInfo.GiftList {
  782. if v.Id == strconv.Itoa(int(extras.GoodsId)) {
  783. //发送对应奖励
  784. var bfInfo *WebBriefInfo
  785. service.GetMysql().Operate(func(rawClient interface{}) interface{} {
  786. wrapper := mysql.NewWrapper(rawClient.(*sql.DB))
  787. wrapper.Query("select uid,nick_name,base_level,create_date,last_login_date,ban_date,map_level,fight_power,active_code,open_id,serverid from role where open_id=?", username).Each(func(wrapper2 *mysql.Wrapper) bool {
  788. bfInfo = parseUserInfo(wrapper2)
  789. return true
  790. })
  791. if wrapper.Err != nil {
  792. util.ErrorF("uid=%v WebGmProcessUserGet err=%v", username, wrapper.Err)
  793. }
  794. return nil
  795. })
  796. if bfInfo == nil {
  797. util.ErrorF("uid=%v not found err=%v", username)
  798. c.JSON(http.StatusOK, gin.H{"status": 1, "msg": "not found user"})
  799. return
  800. }
  801. uidStr := bfInfo.Uid
  802. titleStr := "system award"
  803. contentStr := v.Desc
  804. rewardStr := v.Reward
  805. // list表示获取邮件列表
  806. // attach添加替换邮件
  807. // del删除延迟发送邮件
  808. //mailType := c.DefaultQuery("type", "")
  809. //uid
  810. var uidList []uint64
  811. uidList = append(uidList, uidStr)
  812. //reward
  813. var rewardList []*serverproto.KeyValueType
  814. rewardStrList := strings.Split(rewardStr, ",")
  815. for idx := 0; idx < len(rewardStrList); idx++ {
  816. key, val := model.Str2Res(rewardStrList[idx])
  817. if key > 0 && val > 0 {
  818. rewardList = append(rewardList, &serverproto.KeyValueType{Key: key, Value: val})
  819. }
  820. }
  821. util.ErrorF("东南亚网页支付:orderId:%v,payAmount:%v,sign:%v,extra:%v,username:%v,server:%v,sandbox:%v,timestamp:%v,award:%v", orderId, payAmount, sign, extra, username, server, sandbox, timestamp, rewardStr)
  822. gmweb.GetMailUpdateMag().AttachMail2Update(1, uidList, titleStr, contentStr, util.GetTimeMilliseconds(), rewardList)
  823. c.JSON(http.StatusOK, gin.H{"status": 0})
  824. }
  825. }
  826. }
  827. }
  828. func WebPayHwDnOpenServerNotify(c *gin.Context) {
  829. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  830. sidStr := c.DefaultQuery("sid", "")
  831. nameStr := c.DefaultQuery("name", "")
  832. timeStr := c.DefaultQuery("time", "") //2019-01-01 12:00:00
  833. gameIdStr := c.DefaultQuery("gameid", "") //2019-01-01 12:00:00
  834. signKeyStr := c.DefaultQuery("signkey", "") //2019-01-01 12:00:00
  835. if nameStr == "" || sidStr == "" || timeStr == "" || gameIdStr == "" {
  836. c.JSON(http.StatusOK, "param error:"+nameStr+sidStr+timeStr)
  837. return
  838. }
  839. reqUrl := "https://i.dze-game.com/game/center/sync_server"
  840. now := strconv.FormatInt(time.Now().Unix(), 10)
  841. // 准备表单数据
  842. formData := url.Values{}
  843. formData.Add("GAME_ID", gameIdStr)
  844. formData.Add("SID", sidStr)
  845. formData.Add("_SID", sidStr)
  846. formData.Add("NAME", nameStr)
  847. formData.Add("START_TIME", timeStr)
  848. formData.Add("sign", Md5Dn(gameIdStr, nameStr, sidStr, timeStr, sidStr, now, signKeyStr))
  849. formData.Add("timestamp", now)
  850. resp, err := http.Post(
  851. reqUrl,
  852. "application/x-www-form-urlencoded",
  853. strings.NewReader(formData.Encode()),
  854. )
  855. if err != nil {
  856. util.ErrorF("req error:%v", err)
  857. c.JSON(http.StatusOK, "req error:"+nameStr+sidStr+timeStr)
  858. return
  859. }
  860. defer resp.Body.Close()
  861. body, err := io.ReadAll(resp.Body)
  862. if err != nil {
  863. util.ErrorF("red body error:%v", err)
  864. c.JSON(http.StatusOK, "res error:"+nameStr+sidStr+timeStr)
  865. return
  866. }
  867. util.ErrorF("东南亚开服信息,sid:%v,name:%v,time:%v,response:%v", sidStr, nameStr, timeStr, string(body))
  868. c.JSON(http.StatusOK, gin.H{"status": 0})
  869. }
  870. func Md5Dn(gameId, name, sid, time, _sid, timestamp, signKey string) string {
  871. key := gameId + name + sid + time + _sid + timestamp + signKey
  872. hash := md5.Sum([]byte(key))
  873. return hex.EncodeToString(hash[:])
  874. }
  875. func WebPayHwDnNotify(c *gin.Context) {
  876. //util.DebugF("支付回调信息:%v", c.Request.PostForm)
  877. params := make(map[string]string)
  878. if err := c.Request.ParseForm(); err != nil {
  879. util.InfoF("parseForm falied")
  880. c.String(http.StatusOK, "FAILED")
  881. return
  882. }
  883. util.ErrorF("支付回调信息东南亚:%v", c.Request.PostForm)
  884. for key, value := range c.Request.PostForm {
  885. params[key] = value[0] // 假设每个参数只有一个值
  886. }
  887. cpOrderId := params["order_code"]
  888. payAmount := params["amount"]
  889. //f64, err := strconv.ParseFloat(payAmount, 32)
  890. //if err != nil {
  891. // fmt.Println("Error:", err)
  892. // return
  893. //}
  894. res := webPayNotifyDn(cpOrderId, payAmount, "")
  895. //// 简单粗暴,直接给其他服转发,不需要确认是哪个服
  896. //payPostRouter := service.GetServiceConfig().SDKConfig.PayPostRouter
  897. //util.WarnF("paycallback payPostRouter:%v\n", payPostRouter)
  898. //// 组装转发body
  899. //params["sign"] = sign
  900. //var routerStr strings.Builder
  901. //for key, value := range params {
  902. // routerStr.WriteString(key)
  903. // routerStr.WriteString("=")
  904. // routerStr.WriteString(value)
  905. // routerStr.WriteString("&")
  906. //}
  907. //routerString := routerStr.String()
  908. //util.WarnF("paycallback routerString:%v\n", routerString)
  909. //go sendPosts(payPostRouter, routerString)
  910. if res == "SUCCESS" {
  911. c.JSON(http.StatusOK, gin.H{"processingStatus": "completed"})
  912. } else {
  913. c.JSON(404, gin.H{"code": "ORDER_CODE_NOT_FOUND", "message": "order_code does not exist"})
  914. }
  915. }
  916. func sendPosts(urls []string, routerString string) {
  917. for i := 0; i < len(urls); i++ {
  918. sendPostToOtherServer(urls[i], []byte(routerString))
  919. }
  920. }
  921. // http://110.40.223.119:8002/pay/hwQucikFromS1GmWeb
  922. func WebPayHwQuickNotifyFromS1GmWeb(c *gin.Context) {
  923. params := make(map[string]string)
  924. if err := c.Request.ParseForm(); err != nil {
  925. util.InfoF("parseForm falied")
  926. c.String(http.StatusOK, "FAILED")
  927. return
  928. }
  929. for key, value := range c.Request.PostForm {
  930. params[key] = value[0] // 假设每个参数只有一个值
  931. }
  932. sign := params["sign"]
  933. newSign := getMd5Sign("03422134397322604272901806704074", params)
  934. util.ErrorF("sign:%v", sign)
  935. util.ErrorF("newSign:%v", newSign)
  936. util.ErrorF("params:%v", params)
  937. if newSign != sign {
  938. util.ErrorF("签名错误%v", sign)
  939. c.String(http.StatusOK, "FAILED")
  940. return
  941. }
  942. uid := c.PostForm("uid")
  943. cpOrderId := c.PostForm("cpOrderNo")
  944. orderNo := c.PostForm("orderNo")
  945. payAmount := c.PostForm("payAmount")
  946. payCurrency := c.PostForm("payCurrency")
  947. payType := c.PostForm("payType")
  948. usdAmount := c.PostForm("usdAmount")
  949. ntfData := &WebNotifyData{}
  950. ntfData.CpOrderId = cpOrderId
  951. ntfData.SdkOrderId = orderNo
  952. ntfData.PayMethod = payType
  953. ntfData.PayCurrency = payCurrency
  954. ntfData.PayTime = uint64(util.GetTimeSeconds())
  955. ntfData.PayChannel = "qk_hw"
  956. util.DebugF("uid=%v cpOrderNo=%v orderNo=%v payAmount=%v payCurrency=%v payType=%v usdAmount=%v",
  957. uid, cpOrderId, orderNo, payAmount, payCurrency, payType, usdAmount)
  958. f64, err := strconv.ParseFloat(usdAmount, 32)
  959. if err != nil {
  960. fmt.Println("Error:", err)
  961. return
  962. }
  963. webPayNotify(ntfData, float32(f64), c)
  964. c.JSON(http.StatusOK, "SUCCESS")
  965. }
  966. // sendPostToOtherServer 发送给其他服务器
  967. func sendPostToOtherServer(url string, body []byte) {
  968. // 创建请求
  969. req, err := http.NewRequest("POST", url, bytes.NewReader(body))
  970. if err != nil {
  971. util.ErrorF("r1 NewRequest:%v \n", err.Error())
  972. }
  973. // 设置Header
  974. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  975. req.Header.Set("Custom-Header", "custom-value")
  976. // 发送请求
  977. client := &http.Client{}
  978. resp, err := client.Do(req)
  979. if err != nil {
  980. util.ErrorF("r1 client.Do(req):%v \n", err.Error())
  981. return
  982. }
  983. defer resp.Body.Close()
  984. }
  985. type KVSt struct {
  986. ParamKey string
  987. ParamVal string
  988. }
  989. func WebPayNBSDKNotify(c *gin.Context) {
  990. tmpReq := c.Request
  991. err := tmpReq.ParseMultipartForm(32 << 20)
  992. if err != nil {
  993. return
  994. }
  995. formCache := tmpReq.PostForm
  996. //util.DebugF("formCache2=%v", formCache)
  997. var kvList []*KVSt
  998. for k, v := range formCache {
  999. if k == "sign" {
  1000. continue
  1001. }
  1002. kv := &KVSt{
  1003. ParamKey: k,
  1004. ParamVal: v[0],
  1005. }
  1006. kvList = append(kvList, kv)
  1007. }
  1008. sort.Slice(kvList, func(i, j int) bool {
  1009. return kvList[i].ParamKey < kvList[j].ParamKey
  1010. })
  1011. //util.DebugF("kvlist=%v", kvList)
  1012. verifyStr := ""
  1013. for idx := 0; idx < len(kvList); idx++ {
  1014. key := url.QueryEscape(kvList[idx].ParamKey)
  1015. val := url.QueryEscape(kvList[idx].ParamVal)
  1016. if idx == 0 {
  1017. verifyStr += key + "=" + val
  1018. } else {
  1019. verifyStr += "&" + key + "=" + val
  1020. }
  1021. }
  1022. sign := c.PostForm("sign")
  1023. sdkOrderId := c.PostForm("sdk_order_id") //SDK订单ID
  1024. cpOrderId := c.PostForm("cp_order_id") //游戏方订单ID,由游戏客户端生成(服务器生成给到客户端)
  1025. serverId := c.PostForm("server_id") //游戏区服ID
  1026. pfUid := c.PostForm("pf_uid") //渠道平台的UID
  1027. roleId := c.PostForm("role_id") //游戏方自己的角色ID
  1028. payAmount := c.PostForm("pay_amount") //支付金额(int,单位分,CP方需要验证是否与计费点金额一致,不做此判断,后果自负哦!!!)
  1029. gameKey := service.GetServiceConfig().SDKConfig.NbGameKey
  1030. tmpHmac := hmac.New(md5.New, []byte(gameKey))
  1031. tmpHmac.Write([]byte(verifyStr))
  1032. tmpSign := hex.EncodeToString(tmpHmac.Sum([]byte("")))
  1033. util.DebugF("uid=%v verifyStr=%v cpOrderId=%v pfUid=%v sdkOrderId=%v serverId=%v tmpSign=%v sign=%v gamekey=%v", roleId, verifyStr, cpOrderId, pfUid,
  1034. sdkOrderId, serverId, tmpSign, sign, gameKey)
  1035. if tmpSign != sign {
  1036. util.InfoF("uid=%v WebPayNBSDKNotify sign verify failed cpOrderId=%v", roleId, cpOrderId)
  1037. return
  1038. }
  1039. checkPayAmount, _ := model.Str2Num(payAmount)
  1040. ntfData := &WebNotifyData{}
  1041. ntfData.CpOrderId = cpOrderId
  1042. ntfData.SdkOrderId = sdkOrderId
  1043. ntfData.PayMethod = ""
  1044. ntfData.PayCurrency = ""
  1045. ntfData.PayTime = uint64(util.GetTimeSeconds())
  1046. ntfData.PayChannel = ""
  1047. ret := webPayNotify(ntfData, float32(checkPayAmount)/100, c)
  1048. //c.JSON(http.StatusOK, `success`)
  1049. c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte(ret))
  1050. }
  1051. type UniSDKPayExtraST struct {
  1052. Aid int `json:"aid"` //用户唯一标识
  1053. PrivateParam string `json:"privateparam"`
  1054. PayChannel string `json:"paychannel"` //支付渠道
  1055. AppChannel string `json:"appchannel"` //appchannel
  1056. Platform string `json:"platfrom"`
  1057. UidId string `json:"uidid"` //设备id
  1058. GoodsCount int `json:"goodscount"` //商品数量
  1059. PayMoney string `json:"paymoney"` //玩家实际支付金额
  1060. FreeMoney string `json:"freemoney"` //免费总价,供游戏服写运营日志(如果渠道不提供,该字段为0)
  1061. PayCurrency string `json:"paycurrency"` //玩家实际支付币种
  1062. Deduct int `json:"deduct"`
  1063. DeductPercent string `json:"deductpercent"`
  1064. DeductReason string `json:"deductreason"` //扣除原因,是黑设备还是黑币种
  1065. JsonData string `json:"jsondata"`
  1066. InitTime int `json:"inittime"` //订单创建时间戳,精确到秒;若订单不通过create_order接口创建(例如web 支付),则此值为0
  1067. PayTime int `json:"paytime"` //订单支付时间戳,精确到秒
  1068. IsTest int `json:"istest"` //订单来源:0,正式环境订单;1,测试环境订单(v3.6.2新增)
  1069. FreeYuanBao int `json:"free_yuanbao"`
  1070. PayYuanBao int `json:"pay_yuanbao"`
  1071. PayMethod string `json:"paymethod"`
  1072. }
  1073. type UniSDKPayST struct {
  1074. GameId string `json:"gameid"`
  1075. HostId int `json:"hostid"`
  1076. RoleId string `json:"roleid"`
  1077. GoodsId string `json:"goodsid"`
  1078. UserName string `json:"username"` //玩家渠道帐号(玩家帐号被sdk渠道转换之后的字符串)
  1079. SN string `json:"sn"` //游戏订单号
  1080. ConsumeSN string `json:"consumesn"` //渠道流水订单号(苹果渠道对应为transaction-id)
  1081. ExtraData UniSDKPayExtraST
  1082. }
  1083. type UniSDKPayResponseST struct {
  1084. Code int `json:"code"`
  1085. Msg string `json:"msg"`
  1086. Data interface{} `json:"data"`
  1087. }
  1088. func WebPayUniSDKNotify(c *gin.Context) {
  1089. sign := c.GetHeader("Gas-Ship-Signature")
  1090. payInfo := &UniSDKPayST{}
  1091. bodyData, err := c.GetRawData()
  1092. if err != nil {
  1093. util.ErrorF("WebPayUniSDKNotify body get error=%v", err)
  1094. return
  1095. }
  1096. err = json.Unmarshal(bodyData, payInfo)
  1097. if err != nil {
  1098. util.ErrorF("WebPayUniSDKNotify body Unmarshal error=%v", err)
  1099. return
  1100. }
  1101. secretKey := service.GetServiceConfig().SDKConfig.UniSecretKey
  1102. tmpHmac := hmac.New(md5.New, []byte(secretKey))
  1103. tmpHmac.Write(bodyData)
  1104. tmpSign := hex.EncodeToString(tmpHmac.Sum([]byte("")))
  1105. if tmpSign != sign {
  1106. util.InfoF("uid=%v WebPayUniSDKNotify sign verify failed cpOrderId=%v", payInfo.RoleId, payInfo.SN)
  1107. c.Header("Gas-Ship-Signature", tmpSign)
  1108. responseSt := &UniSDKPayResponseST{
  1109. Code: 403,
  1110. Msg: "ok",
  1111. Data: nil,
  1112. }
  1113. c.JSON(http.StatusOK, responseSt)
  1114. return
  1115. }
  1116. checkPayAmount, _ := model.Str2Num(payInfo.ExtraData.PayMoney)
  1117. ntfData := &WebNotifyData{}
  1118. ntfData.CpOrderId = payInfo.SN
  1119. ntfData.SdkOrderId = payInfo.ConsumeSN
  1120. ntfData.PayMethod = payInfo.ExtraData.PayMethod
  1121. ntfData.PayCurrency = payInfo.ExtraData.PayCurrency
  1122. ntfData.PayTime = uint64(payInfo.ExtraData.PayTime)
  1123. ntfData.PayChannel = payInfo.ExtraData.PayChannel
  1124. ret := webPayNotify(ntfData, float32(checkPayAmount)/100, c)
  1125. if ret == "FAILED" {
  1126. c.JSON(http.StatusOK, "FAILED")
  1127. }
  1128. c.Header("Gas-Ship-Signature", tmpSign)
  1129. responseSt := &UniSDKPayResponseST{
  1130. Code: 200,
  1131. Msg: "ok",
  1132. Data: nil,
  1133. }
  1134. c.JSON(http.StatusOK, responseSt)
  1135. }
  1136. func WebPayNBH5Notify(c *gin.Context) {
  1137. sdkOrderId := c.PostForm("sdk_order_id") //SDK订单ID
  1138. cpOrderId := c.PostForm("cp_order_id") //游戏方订单ID,由游戏客户端生成(服务器生成给到客户端)
  1139. serverId := c.PostForm("server_id") //游戏区服ID
  1140. pfUid := c.PostForm("pf_uid") //渠道平台的UID
  1141. roleId := c.PostForm("role_id") //游戏方自己的角色ID(uid)
  1142. payAmount := c.PostForm("pay_amount") //支付金额(int,单位分,CP方需要验证是否与计费点金额一致,不做此判断,后果自负哦!!!)
  1143. goodsType := c.PostForm("goods_type")
  1144. goodsID := c.PostForm("goods_id")
  1145. util.InfoF("WebPayH5Notify roleId=%v pfUid=%v sdkOrderId=%v serverId=%v", roleId, pfUid, sdkOrderId, serverId)
  1146. if cpOrderId == "" {
  1147. cpOrderId = "WebPayH5Notify"
  1148. }
  1149. gameRoleId, _ := model.Str2NumU64(roleId)
  1150. checkPayAmount, _ := model.Str2Num(payAmount)
  1151. if gameRoleId <= 0 || checkPayAmount <= 0 {
  1152. c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte("FAILED"))
  1153. return
  1154. }
  1155. ntfData := &WebNotifyData{}
  1156. ntfData.GameRoleId = gameRoleId
  1157. ntfData.CpOrderId = cpOrderId
  1158. ntfData.SdkOrderId = sdkOrderId
  1159. ntfData.PayMethod = ""
  1160. ntfData.PayCurrency = ""
  1161. ntfData.PayTime = uint64(util.GetTimeSeconds())
  1162. ntfData.PayChannel = "WebPayH5Notify"
  1163. ntfData.GoodsType, _ = model.Str2NumU64(goodsType)
  1164. ntfData.GoodsID, _ = model.Str2NumU64(goodsID)
  1165. ret := webPayNotifyH5(ntfData, float32(checkPayAmount)/100, c)
  1166. c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte(ret))
  1167. }
  1168. type WebNotifyData struct {
  1169. CpOrderId string
  1170. SdkOrderId string
  1171. PayMethod string
  1172. PayCurrency string
  1173. PayTime uint64
  1174. PayChannel string
  1175. GameRoleId uint64
  1176. GoodsType uint64
  1177. GoodsID uint64
  1178. }
  1179. func webPayNotify(webNtf *WebNotifyData, payAmount float32, c *gin.Context) string {
  1180. //流程处理gmweb保存订单状态到redis中设置为 成功充值状态
  1181. //发送给gameserver,成功收到后设置订单状态为成功获取充值状态,如果gameserver没有收到
  1182. //每次玩家上线时,重新获取一次订单状态如果是成功充值,但是没有获取成功就获取一次
  1183. // 充值成功获取对应的ntdata数据
  1184. // 1,回复成/失败消息给quick
  1185. // 2,订单状态写入redis(判重处理),并发送给social做获取奖励处理
  1186. msgStr, err := service.GetRedis().HGet(model.PayOrderPrefix, webNtf.CpOrderId).Result()
  1187. if err != nil {
  1188. //util.ErrorF("WebPayQuickNotify order not exist err=%v", err)
  1189. util.ErrorF("WebPayQuickNotify order not exist err=%v, cpOrderId=%v, sdkOrderId=%v", err, webNtf.CpOrderId, webNtf.SdkOrderId)
  1190. //c.JSON(http.StatusOK, "FAILED")
  1191. //return "FAILED"
  1192. return fmt.Sprintf("FAILED,cpOrderId=%v err=%v", webNtf.CpOrderId, err)
  1193. }
  1194. payInfo := &serverproto.PayOrderSaveInfo{}
  1195. err = model.GetDecodeMessage(payInfo, msgStr)
  1196. if err != nil {
  1197. util.ErrorF("WebPayQuickNotify GetDecodeMessage err=%, cpOrderId=%v, sdkOrderId=%v", err, webNtf.CpOrderId, webNtf.SdkOrderId)
  1198. //util.ErrorF("WebPayQuickNotify GetDecodeMessage err=%v", err)
  1199. //c.JSON(http.StatusOK, "FAILED")
  1200. //return "FAILED"
  1201. return fmt.Sprintf("FAILED,cpOrderId=%v err=%v", webNtf.CpOrderId, err)
  1202. }
  1203. if payInfo.OrderState == int32(serverproto.PayOrderState_EPayOrderState_Gen) {
  1204. //实际支付 == 订单的钱,否则为支付失败
  1205. //payAmount := int32(payAmount * 100) //该渠道是以分为单位(游戏以卢布为单位)
  1206. //服务器订单实际金额:
  1207. //orderAmount := int32(payInfo.Amount * 1000)
  1208. if payAmount == payInfo.Amount {
  1209. payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayOk)
  1210. } else {
  1211. payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayFailed)
  1212. util.ErrorF("uid=%v WebPayQuickNotify failed payAmount:%v order=%v", payInfo.Uid, payAmount, payInfo)
  1213. return "FAILED"
  1214. }
  1215. payInfo.OrderProcessTime = util.GetTimeMilliseconds()
  1216. payInfo.SdkOrderId = webNtf.SdkOrderId //sdk订单id\
  1217. payInfo.PayMethod = webNtf.PayMethod
  1218. payInfo.PayCurrency = webNtf.PayCurrency
  1219. payInfo.PayTime = webNtf.PayTime
  1220. payInfo.PayChannel = webNtf.PayChannel
  1221. //订单状态修改,写入数据库(后续玩家发货成功后会再次修改订单状态为PayOrderState_EPayOrderState_PayOkReward)
  1222. err, newPayInfoStr := model.GetEncodeMessage(payInfo)
  1223. if err == nil {
  1224. service.GetRedis().HSet(model.PayOrderPrefix, webNtf.CpOrderId, newPayInfoStr)
  1225. }
  1226. //完成订单id列表(避免上次发货不成功,玩家下次登陆时可以重新获取一次奖励)
  1227. uidStr := strconv.FormatUint(payInfo.Uid, 10)
  1228. okListKeyStr := model.PayOrderOKIdListPrefix + uidStr
  1229. service.GetRedis().SAdd(okListKeyStr, payInfo.CpOrderId)
  1230. if payInfo.OrderState == int32(serverproto.PayOrderState_EPayOrderState_PayOk) {
  1231. ssNtfMsg := &serverproto.SSPayInfoOrderNtf{
  1232. PayOrderInfo: payInfo,
  1233. }
  1234. selfmodel.SendSocial(ssNtfMsg)
  1235. }
  1236. util.InfoF("uid=%v WebPayQuickNotify ok order=%v", payInfo.Uid, payInfo)
  1237. } else {
  1238. util.ErrorF("WebPayQuickNotify uid=%v state error state=%v", payInfo.Uid, payInfo.OrderState)
  1239. //return "FAILED"
  1240. return fmt.Sprintf("FAILED,cpOrderId=%v state error=%v", webNtf.CpOrderId, payInfo.OrderState)
  1241. }
  1242. return "SUCCESS"
  1243. }
  1244. func webPayNotifyDn(cpOrderId string, Amount, sdkOrderId string) string {
  1245. //流程处理gmweb保存订单状态到redis中设置为 成功充值状态
  1246. //发送给gameserver,成功收到后设置订单状态为成功获取充值状态,如果gameserver没有收到
  1247. //每次玩家上线时,重新获取一次订单状态如果是成功充值,但是没有获取成功就获取一次
  1248. // 充值成功获取对应的ntdata数据
  1249. // 1,回复成/失败消息给quick
  1250. // 2,订单状态写入redis(判重处理),并发送给social做获取奖励处理
  1251. msgStr, err := service.GetRedis().HGet(model.PayOrderPrefix, cpOrderId).Result()
  1252. if err != nil {
  1253. //util.ErrorF("WebPayQuickNotify order not exist err=%v", err)
  1254. util.ErrorF("WebPayQuickNotify order not exist err=%v, cpOrderId=%v, sdkOrderId=%v", err, cpOrderId, 0)
  1255. //c.JSON(http.StatusOK, "FAILED")
  1256. //return "FAILED"
  1257. return fmt.Sprintf("FAILED,cpOrderId=%v err=%v", cpOrderId, err)
  1258. }
  1259. payInfo := &serverproto.PayOrderSaveInfo{}
  1260. err = model.GetDecodeMessage(payInfo, msgStr)
  1261. if err != nil {
  1262. util.ErrorF("WebPayQuickNotify GetDecodeMessage err=%, cpOrderId=%v, sdkOrderId=%v", err, cpOrderId, 0)
  1263. //util.ErrorF("WebPayQuickNotify GetDecodeMessage err=%v", err)
  1264. //c.JSON(http.StatusOK, "FAILED")
  1265. //return "FAILED"
  1266. return fmt.Sprintf("FAILED,cpOrderId=%v err=%v", cpOrderId, err)
  1267. }
  1268. if payInfo.OrderState == int32(serverproto.PayOrderState_EPayOrderState_Gen) {
  1269. //实际支付 == 订单的钱,否则为支付失败
  1270. //payAmount := int32(Amount * 1000)
  1271. ////服务器订单实际金额:
  1272. orderAmount := fmt.Sprintf("%.2f", payInfo.Amount)
  1273. if Amount == orderAmount {
  1274. payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayOk)
  1275. } else {
  1276. payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayFailed)
  1277. util.ErrorF("uid=%v WebPayQuickNotify failed payAmount:%v order=%v ,price=%v", payInfo.Uid, Amount, payInfo, orderAmount)
  1278. return ""
  1279. }
  1280. //payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayOk)
  1281. payInfo.OrderProcessTime = util.GetTimeMilliseconds()
  1282. payInfo.SdkOrderId = sdkOrderId //sdk订单id\
  1283. //payInfo.PayMethod = webNtf.PayMethod
  1284. //payInfo.PayCurrency = webNtf.PayCurrency
  1285. payInfo.PayTime = util.GetTimeMilliseconds()
  1286. payInfo.PayChannel = "dn"
  1287. //订单状态修改,写入数据库(后续玩家发货成功后会再次修改订单状态为PayOrderState_EPayOrderState_PayOkReward)
  1288. err, newPayInfoStr := model.GetEncodeMessage(payInfo)
  1289. if err == nil {
  1290. service.GetRedis().HSet(model.PayOrderPrefix, cpOrderId, newPayInfoStr)
  1291. }
  1292. //完成订单id列表(避免上次发货不成功,玩家下次登陆时可以重新获取一次奖励)
  1293. uidStr := strconv.FormatUint(payInfo.Uid, 10)
  1294. okListKeyStr := model.PayOrderOKIdListPrefix + uidStr
  1295. service.GetRedis().SAdd(okListKeyStr, payInfo.CpOrderId)
  1296. if payInfo.OrderState == int32(serverproto.PayOrderState_EPayOrderState_PayOk) {
  1297. ssNtfMsg := &serverproto.SSPayInfoOrderNtf{
  1298. PayOrderInfo: payInfo,
  1299. }
  1300. selfmodel.SendSocial(ssNtfMsg)
  1301. }
  1302. util.InfoF("uid=%v WebPayQuickNotify ok order=%v", payInfo.Uid, payInfo)
  1303. } else {
  1304. util.ErrorF("WebPayQuickNotify uid=%v state error state=%v", payInfo.Uid, payInfo.OrderState)
  1305. //return "FAILED"
  1306. return fmt.Sprintf("FAILED,cpOrderId=%v state error=%v", cpOrderId, payInfo.OrderState)
  1307. }
  1308. return "SUCCESS"
  1309. }
  1310. // 外层发起主动充值(不走游戏流程)
  1311. func webPayNotifyH5(webNtf *WebNotifyData, payAmount float32, c *gin.Context) string {
  1312. payInfo := &serverproto.PayOrderSaveInfo{}
  1313. payInfo.Uid = webNtf.GameRoleId
  1314. payInfo.Amount = payAmount
  1315. payInfo.OrderProcessTime = util.GetTimeMilliseconds()
  1316. payInfo.SdkOrderId = webNtf.SdkOrderId //sdk订单id\
  1317. payInfo.PayMethod = webNtf.PayMethod
  1318. payInfo.PayCurrency = webNtf.PayCurrency
  1319. payInfo.PayTime = webNtf.PayTime
  1320. payInfo.PayChannel = webNtf.PayChannel
  1321. payInfo.GoodsType = int32(webNtf.GoodsType)
  1322. payInfo.GoodsId = int32(webNtf.GoodsID)
  1323. rewardStr := c.DefaultQuery("reward", "")
  1324. //reward
  1325. rewardStrList := strings.Split(rewardStr, ",")
  1326. for idx := 0; idx < len(rewardStrList); idx++ {
  1327. key, val := model.Str2Res(rewardStrList[idx])
  1328. if key > 0 && val > 0 {
  1329. payInfo.RewardList = append(payInfo.RewardList, &serverproto.KeyValueType{Key: key, Value: val})
  1330. }
  1331. }
  1332. payInfo.OrderState = int32(serverproto.PayOrderState_EPayOrderState_PayOk)
  1333. //订单状态修改,写入数据库(后续玩家发货成功后会再次修改订单状态为PayOrderState_EPayOrderState_PayOkReward)
  1334. err, newPayInfoStr := model.GetEncodeMessage(payInfo)
  1335. if err == nil {
  1336. service.GetRedis().HSet(model.PayOrderPrefix, webNtf.CpOrderId, newPayInfoStr)
  1337. }
  1338. //完成订单id列表(避免上次发货不成功,玩家下次登陆时可以重新获取一次奖励)
  1339. uidStr := strconv.FormatUint(payInfo.Uid, 10)
  1340. okListKeyStr := model.PayOrderOKIdListPrefix + uidStr
  1341. service.GetRedis().SAdd(okListKeyStr, payInfo.CpOrderId)
  1342. util.InfoF("webPayNotifyH5: %v", payInfo)
  1343. ssNtfMsg := &serverproto.SSPayInfoOrderNtf{
  1344. PayOrderInfo: payInfo,
  1345. }
  1346. selfmodel.SendSocial(ssNtfMsg)
  1347. return "SUCCESS"
  1348. }