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.
342 lines
16 KiB
342 lines
16 KiB
1 month ago
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|