using LitJson; using Newtonsoft.Json.Linq; using Org.BouncyCastle.Bcpg; using ProtoCSStruct; using SimpleHttpServer; using Sog; using Sog.Log; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Text.Json.Nodes; using System.Threading.Tasks; namespace HttpProxy { public static class HttpParamsUtils { // 解析k1=v1&k2=v2&k3=v3...格式的字符串 public static Dictionary ParseByKeyValue(string str) { str = str.Trim(); if (string.IsNullOrEmpty(str)) { return null; } int idx = str.IndexOf('?'); if (idx != -1) { str = str.Substring(idx + 1); } var map = new Dictionary(); string[] allParams = str.Split('&'); foreach (var param in allParams) { string[] namevalue = param.Split('='); if (namevalue != null && namevalue.Length == 2) { map[namevalue[0]] = namevalue[1]; } } return map; } } public static class WXMsgHandler { private static string accessToken = null; private static long expireTimeSec = 0; private static ConcurrentDictionary cachedAILink = new ConcurrentDictionary(); public static void CheckFreshAccessToken(bool force = false) { long now = HttpProxyServerUtils.GetTimeSecond(); if (now > expireTimeSec || force) { //https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET string url = "https://api.weixin.qq.com/cgi-bin/stable_token"; LitJson.JsonData j = new JsonData(); j["grant_type"] = "client_credential"; j["appid"] = HttpProxyServerUtils.GetServerConfig().wechatMini_appid; j["secret"] = HttpProxyServerUtils.GetServerConfig().wechatMini_appsecreat; j["force_refresh"] = false; var cont = j.ToJson(); HttpContent content = new StringContent(cont, Encoding.UTF8, "application/json"); string ret = HttpUtils.HttpPost(url, content, out bool exception); TraceLog.Debug("WXMsgHandler.checkFreshAccessToken, get ret:{0}", ret); if (ret == null) { return; } LitJson.JsonData jsonData = JsonMapper.ToObject(ret); //if (jsonData.ContainsKey("errcode")) //{ // LitJson.JsonData errCode = jsonData["errcode"]; // LitJson.JsonData errMsg = jsonData["errmsg"]; // if (errCode.ToString() != "0") // { // TraceLog.Error("checkFreshAccessToken , msdk server ack failed, accountid:{0} errCode {1} errMsg:{2}", 0, errCode.ToString(), errMsg.ToString()); // return ; // } //} accessToken = jsonData["access_token"].ToString(); expireTimeSec = now + ((long)jsonData["expires_in"]); } } public static void HomeMiniMsgBack(HttpContext httpCtx) { if (httpCtx.httpRequest == null) { TraceLog.Trace("HeroPayHttpHandler.HomeMiniCallBack ctx id {0} httpRequest is null", httpCtx.id); return; } TraceLog.Trace("HeroPayHttpHandler.HomeMiniMsgBack ctx id {0} content {1}, url {2}, path={3}, header{4}", httpCtx.id, httpCtx.httpRequest.Content, httpCtx.httpRequest.Url, httpCtx.httpRequest.Path, httpCtx.httpRequest.Headers); var postParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Path); if (!postParams.TryGetValue("signature", out string signature)) { TraceLog.Error("HeroPayHttpHandler.HomeMiniMsgBack 'signature' is null"); //return; } if (!postParams.TryGetValue("msg_signature", out string msg_signature)) { TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'msg_signature' is null"); //return; } if (!postParams.TryGetValue("timestamp", out string timestamp)) { TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'timestamp' is null"); return; } if (!postParams.TryGetValue("nonce", out string nonce)) { TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack 'nonce' is null"); return; } if (httpCtx.httpRequest.Method == "GET") { var getParams = HttpParamsUtils.ParseByKeyValue(httpCtx.httpRequest.Path); getParams.TryGetValue("echostr", out string echostr); var list = new List(); list.Add(timestamp); list.Add(nonce); list.Add(HttpProxyServerUtils.GetServerConfig().wxMsgToken); list.Sort((x, y) => string.Compare(x, y)); var str = string.Join("", list); var sig = HashHelper.SHA1String(str); TraceLog.Trace("HeroPayHttpHandler.HomeMiniMsgBack signature {0} sig {1}", signature, sig); if (signature == sig) { httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes(echostr) }; HttpServer.SendResponse(httpCtx); return; } httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("Verify fail") }; HttpServer.SendResponse(httpCtx); return; } Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt(HttpProxyServerUtils.GetServerConfig().wxMsgToken, HttpProxyServerUtils.GetServerConfig().wxMsgAesKey, HttpProxyServerUtils.GetServerConfig().wechatMini_appid); string sMsg = ""; //解析之后的明文 int ret = 0; JsonData reqJson = JsonMapper.ToObject(httpCtx.httpRequest.Content); ret = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, reqJson["Encrypt"].ToString(), ref sMsg); if (ret != 0) { TraceLog.Error("HeroPayHttpHandler.HomeMiniCallBack: Decrypt fail, ret: " + ret); return; } TraceLog.Trace("smsg-> {0}",sMsg); JsonData jsonData = JsonMapper.ToObject(sMsg); string openId = jsonData["FromUserName"].ToString(); string MsgType = jsonData["MsgType"].ToString(); if(MsgType == "miniprogrampage") { //string Title = jsonData["Title"].ToString(); if (cachedAILink.TryRemove(openId, out string url)) { string ThumbUrl = jsonData["ThumbUrl"].ToString(); sendLink(openId, "客服窗口", "点击联系客服", url, ThumbUrl); } httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}\r\n") }; HttpServer.SendResponse(httpCtx); return; } if(MsgType != "event") { httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}\r\n") }; HttpServer.SendResponse(httpCtx); return; } string Event = jsonData["Event"].ToString(); if(Event == "minigame_deliver_goods") { //{"ToUserName":"gh_0c0d31132839","FromUserName":"oPCeL6wwHCrM9HbtGc24nwte9Wes","CreateTime":1733970633,"MsgType":"event","Event":"minigame_deliver_goods","MiniGame":{"OrderId":"wxag_game_gift20241212pfdYC1zFof","IsPreview":0,"ToUserOpenid":"oPCeL6-m33wLqfw2hTjS62qZd3G8","GoodsList":[{"Id":"2","Num":200}],"Zone":2001,"GiftTypeId":1,"GiftId":"CBgAAoXb6-hxz9zBs6LC3k24DeboTA8XOq_Eg4EI_iqMcQLqkAc6TNL1TUTxf7TVfwDEoZy4crXGEhoQ","SendTime":1733969370}} httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}\r\n") }; HttpServer.SendResponse(httpCtx); var MiniGame = jsonData["MiniGame"]; var GoodsList = MiniGame["GoodsList"]; var IsPreview = MiniGame["IsPreview"].ToString(); //if(IsPreview == "1") //{ // return; //} var ToUserOpenid = MiniGame["ToUserOpenid"].ToString(); SSSendGift send = new SSSendGift(); send.AccountType = (int)AccountType.AccountType_WXMini; send.AccountId.SetString(ToUserOpenid); send.WorldId = 801; for (int i = 0; i < GoodsList.Count; i++) { var id = GoodsList[i]["Id"].ToString(); var num = GoodsList[i]["Num"].ToString(); var t = new TypeIDValueString(); t.Type = (int)GoodsType.Items; t.Id.SetString(id); t.Value = int.Parse(num); send.Goods.Add(ref t); } HttpProxyServerUtils.GetPacketSender().SendToServerByID( (uint)ServerIDUtils.GetLevel0ServerIDByType((int)ServerType.Account, 1), (int)SSMsgID.SendGifts, ref send, 0); return; } // if (jsonData.ContainsKey("SessionFrom")) { string sessionFrom = jsonData["SessionFrom"].ToString(); TraceLog.Trace("openId {0} sessionFrom {1}", openId, sessionFrom); if (sessionFrom != "") { JObject PayJson = JObject.Parse(sessionFrom); TraceLog.Trace("sessionFrom {0}", PayJson.ToString()); JsonData fromJson = JsonMapper.ToObject(PayJson.ToString()); if (!fromJson.ContainsKey("type")) { httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}\r\n") }; HttpServer.SendResponse(httpCtx); return; } string enterType = fromJson["type"].ToString(); if (enterType == "aihelp") { JsonData p = fromJson["params"]; string url = p["url"].ToString(); cachedAILink.TryAdd(openId, url); //sendToAIHelp(sMsg); } else if(enterType == "pay") { JsonData p = fromJson["params"]; string Uid = p["uid"].ToString(); string OrderId = p["orderId"].ToString(); string payUrl = HttpProxyServerUtils.GetServerConfig().wxJSApiURL+ "?uid="+ Uid + "&orderId="+ OrderId; string[] ss = OrderId.Split('-'); var desc = PayDiamondDescMgr.Instance.GetConfig(int.Parse(ss[4])); sendLink(openId, "点我充值", "点我购买"+desc.comm, payUrl, "https://cdn-huoliqiang-xcx.yingxiong.com/wxpay/chongzhi.jpg"); } else { sendText(openId, "欢迎来到方块大冒险"); } } httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes("{\"ErrCode\":0,\"ErrMsg\":\"Success\"}\r\n") }; HttpServer.SendResponse(httpCtx); } } public static void sendText(String openId, String msg) { if (msg == "") { return; } JObject textJson = new JObject(); textJson["content"] = msg; JObject postJson = new JObject(); postJson["touser"] = openId; postJson["msgtype"] = "text"; postJson["link"] = textJson; send(postJson.ToString()); } public static void sendLink(String openId, String title, String desc, String url, String thumb_url) { // JsonData linkJson = new JsonData(); //JsonObject linkJson = new JsonObject(); JObject linkJson = new JObject(); linkJson["title"] = title; linkJson["description"] = desc; linkJson["url"] = url; linkJson["thumb_url"] = thumb_url; JObject postJson = new JObject(); postJson["touser"] = openId; postJson["msgtype"] = "link"; postJson["link"] = linkJson; send(postJson.ToString()); } private static void send(string scontent) { CheckFreshAccessToken(false); string url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+accessToken; StringContent content = new StringContent(scontent, Encoding.UTF8, "application/json"); string ret = HttpUtils.HttpPost(url, content, out bool exception); TraceLog.Trace("send {0} ret: {1}", scontent, ret); } private static void sendToAIHelp(string msg) { long timestamp = HttpProxyServerUtils.GetTimeMs(); string sign = MD5Encrypt(HttpProxyServerUtils.GetServerConfig().aiHelpAppKey+HttpProxyServerUtils.GetServerConfig().aiHelpSec+timestamp); HttpContent content = new StringContent(msg, Encoding.UTF8); List< KeyValuePair < String, String >> headerList = new List>(); headerList.Add(new KeyValuePair("timestamp", timestamp.ToString())); headerList.Add(new KeyValuePair("sign", sign)); headerList.Add(new KeyValuePair("appKey", HttpProxyServerUtils.GetServerConfig().aiHelpAppKey)); string ret = HttpUtils.HttpPost(HttpProxyServerUtils.GetServerConfig().aiHelpUrl,content, headerList, out bool ex); TraceLog.Trace("sendToAIHelp ret: {0}, sign={1}, time={2} ", ret , sign , timestamp); } public static string MD5Encrypt(string strText) { MD5 md5 = MD5.Create(); byte[] result = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(strText)); md5.Dispose(); string byte2String = null; for (int i = 0; i < result.Length; i++) { byte2String += result[i].ToString("x2"); } return byte2String; } } }