You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

341 lines
16 KiB

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<string, string> 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, string>();
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<string, string> cachedAILink = new ConcurrentDictionary<string, string>();
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<string>();
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<SSSendGift>(
(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<KeyValuePair<string, string>>();
headerList.Add(new KeyValuePair<string, string>("timestamp", timestamp.ToString()));
headerList.Add(new KeyValuePair<string, string>("sign", sign));
headerList.Add(new KeyValuePair<string, string>("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;
}
}
}